aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2015-11-24 04:01:32 +0530
committerbors-servo <lbergstrom+bors@mozilla.com>2015-11-24 04:01:32 +0530
commit711f516d80c9c0026744cd373d398dc294f14d2a (patch)
treeeaca2f68cede9642add82670bdc884e39fead10c /components/layout
parent6449cd09ebd7f7e3545039c26bcbe9a6ca7a5621 (diff)
parentafa3834f3be849cd4e6745b9fe763df512e4f9fc (diff)
downloadservo-711f516d80c9c0026744cd373d398dc294f14d2a.tar.gz
servo-711f516d80c9c0026744cd373d398dc294f14d2a.zip
Auto merge of #8639 - bholley:generalize_wrappers2, r=pcwalton
Use associated types for layout wrapper trait, and generalized ThreadSafeLayoutFoo <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8639) <!-- Reviewable:end -->
Diffstat (limited to 'components/layout')
-rw-r--r--components/layout/construct.rs66
-rw-r--r--components/layout/flow.rs6
-rw-r--r--components/layout/fragment.rs16
-rw-r--r--components/layout/layout_task.rs3
-rw-r--r--components/layout/query.rs6
-rw-r--r--components/layout/table_cell.rs4
-rw-r--r--components/layout/traversal.rs12
-rw-r--r--components/layout/wrapper.rs553
8 files changed, 370 insertions, 296 deletions
diff --git a/components/layout/construct.rs b/components/layout/construct.rs
index c2427b63b69..c09ecc7b173 100644
--- a/components/layout/construct.rs
+++ b/components/layout/construct.rs
@@ -57,7 +57,7 @@ use traversal::PostorderNodeMutTraversal;
use url::Url;
use util::linked_list;
use util::opts;
-use wrapper::{PseudoElementType, TextContent, ThreadSafeLayoutNode};
+use wrapper::{PseudoElementType, ServoThreadSafeLayoutNode, TextContent, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
/// The results of flow construction for a DOM node.
#[derive(Clone)]
@@ -208,7 +208,7 @@ impl InlineFragmentsAccumulator {
}
}
- fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator {
+ fn from_inline_node(node: &ServoThreadSafeLayoutNode) -> InlineFragmentsAccumulator {
InlineFragmentsAccumulator {
fragments: IntermediateInlineFragments::new(),
enclosing_node: Some(InlineFragmentNodeInfo {
@@ -281,13 +281,13 @@ impl<'a> FlowConstructor<'a> {
#[inline]
fn set_flow_construction_result(&self,
- node: &ThreadSafeLayoutNode,
+ node: &ServoThreadSafeLayoutNode,
result: ConstructionResult) {
node.set_flow_construction_result(result);
}
/// Builds the fragment for the given block or subclass thereof.
- fn build_fragment_for_block(&mut self, node: &ThreadSafeLayoutNode) -> Fragment {
+ fn build_fragment_for_block(&mut self, node: &ServoThreadSafeLayoutNode) -> Fragment {
let specific_fragment_info = match node.type_id() {
Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLIFrameElement))) => {
@@ -343,7 +343,7 @@ impl<'a> FlowConstructor<'a> {
fn generate_anonymous_table_flows_if_necessary(&mut self,
flow: &mut FlowRef,
child: &mut FlowRef,
- child_node: &ThreadSafeLayoutNode) {
+ child_node: &ServoThreadSafeLayoutNode) {
if !flow.is_block_flow() {
return
}
@@ -401,7 +401,7 @@ impl<'a> FlowConstructor<'a> {
flow: &mut FlowRef,
flow_list: &mut Vec<FlowRef>,
absolute_descendants: &mut AbsoluteDescendants,
- node: &ThreadSafeLayoutNode) {
+ node: &ServoThreadSafeLayoutNode) {
let mut fragments = fragment_accumulator.to_intermediate_inline_fragments();
if fragments.is_empty() {
return
@@ -486,8 +486,8 @@ impl<'a> FlowConstructor<'a> {
&mut self,
flow: &mut FlowRef,
consecutive_siblings: &mut Vec<FlowRef>,
- node: &ThreadSafeLayoutNode,
- kid: ThreadSafeLayoutNode,
+ node: &ServoThreadSafeLayoutNode,
+ kid: ServoThreadSafeLayoutNode,
inline_fragment_accumulator: &mut InlineFragmentsAccumulator,
abs_descendants: &mut AbsoluteDescendants) {
match kid.swap_out_construction_result() {
@@ -595,7 +595,7 @@ impl<'a> FlowConstructor<'a> {
fn build_flow_for_block_starting_with_fragments(
&mut self,
mut flow: FlowRef,
- node: &ThreadSafeLayoutNode,
+ node: &ServoThreadSafeLayoutNode,
initial_fragments: IntermediateInlineFragments)
-> ConstructionResult {
// Gather up fragments for the inline flows we might need to create.
@@ -662,7 +662,7 @@ impl<'a> FlowConstructor<'a> {
///
/// FIXME(pcwalton): It is not clear to me that there isn't a cleaner way to handle
/// `<textarea>`.
- fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ThreadSafeLayoutNode)
+ fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ServoThreadSafeLayoutNode)
-> ConstructionResult {
let mut initial_fragments = IntermediateInlineFragments::new();
let node_is_input_or_text_area =
@@ -695,7 +695,7 @@ impl<'a> FlowConstructor<'a> {
/// Pushes fragments appropriate for the content of the given node onto the given list.
fn create_fragments_for_node_text_content(&self,
fragments: &mut IntermediateInlineFragments,
- node: &ThreadSafeLayoutNode,
+ node: &ServoThreadSafeLayoutNode,
style: &Arc<ComputedValues>) {
// Fast path: If there is no text content, return immediately.
let text_content = node.text_content();
@@ -744,7 +744,7 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: block`. This yields a `BlockFlow` with possibly
/// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
/// to happen.
- fn build_flow_for_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: Option<FloatKind>)
+ fn build_flow_for_block(&mut self, node: &ServoThreadSafeLayoutNode, float_kind: Option<FloatKind>)
-> ConstructionResult {
let fragment = self.build_fragment_for_block(node);
let flow: FlowRef = if node.style().is_multicol() {
@@ -758,7 +758,7 @@ impl<'a> FlowConstructor<'a> {
/// Bubbles up {ib} splits.
fn accumulate_inline_block_splits(&mut self,
splits: LinkedList<InlineBlockSplit>,
- node: &ThreadSafeLayoutNode,
+ node: &ServoThreadSafeLayoutNode,
fragment_accumulator: &mut InlineFragmentsAccumulator,
opt_inline_block_splits: &mut LinkedList<InlineBlockSplit>) {
for split in splits {
@@ -783,7 +783,7 @@ impl<'a> FlowConstructor<'a> {
/// Returns the `InlineFragmentsConstructionResult`, if any. There will be no
/// `InlineFragmentsConstructionResult` if this node consisted entirely of ignorable
/// whitespace.
- fn build_fragments_for_nonreplaced_inline_content(&mut self, node: &ThreadSafeLayoutNode)
+ fn build_fragments_for_nonreplaced_inline_content(&mut self, node: &ServoThreadSafeLayoutNode)
-> ConstructionResult {
let mut opt_inline_block_splits: LinkedList<InlineBlockSplit> = LinkedList::new();
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
@@ -897,7 +897,7 @@ impl<'a> FlowConstructor<'a> {
/// Creates an `InlineFragmentsConstructionResult` for replaced content. Replaced content
/// doesn't render its children, so this just nukes a child's fragments and creates a
/// `Fragment`.
- fn build_fragments_for_replaced_inline_content(&mut self, node: &ThreadSafeLayoutNode)
+ fn build_fragments_for_replaced_inline_content(&mut self, node: &ServoThreadSafeLayoutNode)
-> ConstructionResult {
for kid in node.children() {
self.set_flow_construction_result(&kid, ConstructionResult::None)
@@ -941,7 +941,7 @@ impl<'a> FlowConstructor<'a> {
ConstructionResult::ConstructionItem(construction_item)
}
- fn build_fragment_for_inline_block(&mut self, node: &ThreadSafeLayoutNode)
+ fn build_fragment_for_inline_block(&mut self, node: &ServoThreadSafeLayoutNode)
-> ConstructionResult {
let block_flow_result = self.build_flow_for_block(node, None);
let (block_flow, abs_descendants) = match block_flow_result {
@@ -973,7 +973,7 @@ impl<'a> FlowConstructor<'a> {
/// This is an annoying case, because the computed `display` value is `block`, but the
/// hypothetical box is inline.
- fn build_fragment_for_absolutely_positioned_inline(&mut self, node: &ThreadSafeLayoutNode)
+ fn build_fragment_for_absolutely_positioned_inline(&mut self, node: &ServoThreadSafeLayoutNode)
-> ConstructionResult {
let block_flow_result = self.build_flow_for_block(node, None);
let (block_flow, abs_descendants) = match block_flow_result {
@@ -1005,7 +1005,7 @@ impl<'a> FlowConstructor<'a> {
/// Builds one or more fragments for a node with `display: inline`. This yields an
/// `InlineFragmentsConstructionResult`.
- fn build_fragments_for_inline(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
+ fn build_fragments_for_inline(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult {
// Is this node replaced content?
if !node.is_replaced_content() {
// Go to a path that concatenates our kids' fragments.
@@ -1021,7 +1021,7 @@ impl<'a> FlowConstructor<'a> {
/// `caption-side` property is equal to the given `side`.
fn place_table_caption_under_table_wrapper_on_side(&mut self,
table_wrapper_flow: &mut FlowRef,
- node: &ThreadSafeLayoutNode,
+ node: &ServoThreadSafeLayoutNode,
side: caption_side::T) {
// Only flows that are table captions are matched here.
for kid in node.children() {
@@ -1046,7 +1046,7 @@ impl<'a> FlowConstructor<'a> {
fn generate_anonymous_missing_child(&mut self,
child_flows: Vec<FlowRef>,
flow: &mut FlowRef,
- node: &ThreadSafeLayoutNode) {
+ node: &ServoThreadSafeLayoutNode) {
let mut anonymous_flow = flow.generate_missing_child_flow(node);
let mut consecutive_siblings = vec!();
for kid_flow in child_flows {
@@ -1072,7 +1072,7 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: table`. This yields a `TableWrapperFlow` with
/// possibly other `TableCaptionFlow`s or `TableFlow`s underneath it.
- fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode, float_value: float::T)
+ fn build_flow_for_table_wrapper(&mut self, node: &ServoThreadSafeLayoutNode, float_value: float::T)
-> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableWrapper);
let mut wrapper_flow: FlowRef = Arc::new(
@@ -1134,7 +1134,7 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: table-caption`. This yields a `TableCaptionFlow`
/// with possibly other `BlockFlow`s or `InlineFlow`s underneath it.
- fn build_flow_for_table_caption(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
+ fn build_flow_for_table_caption(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult {
let fragment = self.build_fragment_for_block(node);
let flow = Arc::new(TableCaptionFlow::from_fragment(fragment));
self.build_flow_for_block_like(flow, node)
@@ -1142,7 +1142,7 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: table-row-group`. This yields a `TableRowGroupFlow`
/// with possibly other `TableRowFlow`s underneath it.
- fn build_flow_for_table_rowgroup(&mut self, node: &ThreadSafeLayoutNode)
+ fn build_flow_for_table_rowgroup(&mut self, node: &ServoThreadSafeLayoutNode)
-> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
let flow = Arc::new(TableRowGroupFlow::from_fragment(fragment));
@@ -1151,7 +1151,7 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: table-row`. This yields a `TableRowFlow` with
/// possibly other `TableCellFlow`s underneath it.
- fn build_flow_for_table_row(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
+ fn build_flow_for_table_row(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableRow);
let flow = Arc::new(TableRowFlow::from_fragment(fragment));
self.build_flow_for_block_like(flow, node)
@@ -1159,7 +1159,7 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it.
- fn build_flow_for_table_cell(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
+ fn build_flow_for_table_cell(&mut self, node: &ServoThreadSafeLayoutNode) -> ConstructionResult {
let fragment = Fragment::new(node, SpecificFragmentInfo::TableCell);
// Determine if the table cell should be hidden. Per CSS 2.1 § 17.6.1.1, this will be true
@@ -1180,7 +1180,7 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: list-item`. This yields a `ListItemFlow` with
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it.
- fn build_flow_for_list_item(&mut self, node: &ThreadSafeLayoutNode, flotation: float::T)
+ fn build_flow_for_list_item(&mut self, node: &ServoThreadSafeLayoutNode, flotation: float::T)
-> ConstructionResult {
let flotation = FloatKind::from_property(flotation);
let marker_fragments = match node.style().get_list().list_style_image.0 {
@@ -1239,7 +1239,7 @@ impl<'a> FlowConstructor<'a> {
}
/// Creates a fragment for a node with `display: table-column`.
- fn build_fragments_for_table_column(&mut self, node: &ThreadSafeLayoutNode)
+ fn build_fragments_for_table_column(&mut self, node: &ServoThreadSafeLayoutNode)
-> ConstructionResult {
// CSS 2.1 § 17.2.1. Treat all child fragments of a `table-column` as `display: none`.
for kid in node.children() {
@@ -1254,7 +1254,7 @@ impl<'a> FlowConstructor<'a> {
/// Builds a flow for a node with `display: table-column-group`.
/// This yields a `TableColGroupFlow`.
- fn build_flow_for_table_colgroup(&mut self, node: &ThreadSafeLayoutNode)
+ fn build_flow_for_table_colgroup(&mut self, node: &ServoThreadSafeLayoutNode)
-> ConstructionResult {
let fragment =
Fragment::new(node,
@@ -1283,7 +1283,7 @@ impl<'a> FlowConstructor<'a> {
}
/// Builds a flow for a node with 'display: flex'.
- fn build_flow_for_flex(&mut self, node: &ThreadSafeLayoutNode, float_kind: Option<FloatKind>)
+ fn build_flow_for_flex(&mut self, node: &ServoThreadSafeLayoutNode, float_kind: Option<FloatKind>)
-> ConstructionResult {
let fragment = self.build_fragment_for_block(node);
let flow = Arc::new(FlexFlow::from_fragment(fragment, float_kind));
@@ -1295,7 +1295,7 @@ impl<'a> FlowConstructor<'a> {
///
/// TODO(pcwalton): Add some more fast paths, like toggling `display: none`, adding block kids
/// to block parents with no {ib} splits, adding out-of-flow kids, etc.
- pub fn repair_if_possible(&mut self, node: &ThreadSafeLayoutNode) -> bool {
+ pub fn repair_if_possible(&mut self, node: &ServoThreadSafeLayoutNode) -> bool {
// We can skip reconstructing the flow if we don't have to reconstruct and none of our kids
// did either.
//
@@ -1410,7 +1410,7 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
//
// TODO: This should actually consult the table in that section to get the
// final computed value for 'display'.
- fn process(&mut self, node: &ThreadSafeLayoutNode) -> bool {
+ fn process(&mut self, node: &ServoThreadSafeLayoutNode) -> bool {
// Get the `display` property for this node, and determine whether this node is floated.
let (display, float, positioning) = match node.type_id() {
None => {
@@ -1580,7 +1580,7 @@ trait NodeUtils {
fn swap_out_construction_result(self) -> ConstructionResult;
}
-impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
+impl<'ln> NodeUtils for ServoThreadSafeLayoutNode<'ln> {
fn is_replaced_content(&self) -> bool {
match self.type_id() {
None |
@@ -1639,7 +1639,7 @@ trait ObjectElement<'a> {
fn object_data(&self) -> Option<Url>;
}
-impl<'ln> ObjectElement<'ln> for ThreadSafeLayoutNode<'ln> {
+impl<'ln> ObjectElement<'ln> for ServoThreadSafeLayoutNode<'ln> {
fn get_type_and_data(&self) -> (Option<&'ln str>, Option<&'ln str>) {
let elem = self.as_element();
(elem.get_attr(&ns!(""), &atom!("type")), elem.get_attr(&ns!(""), &atom!("data")))
diff --git a/components/layout/flow.rs b/components/layout/flow.rs
index 8251bd88b6c..fba998d759e 100644
--- a/components/layout/flow.rs
+++ b/components/layout/flow.rs
@@ -58,7 +58,7 @@ use table_rowgroup::TableRowGroupFlow;
use table_wrapper::TableWrapperFlow;
use util::geometry::ZERO_RECT;
use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
-use wrapper::{PseudoElementType, ThreadSafeLayoutNode};
+use wrapper::{PseudoElementType, ServoThreadSafeLayoutNode, ThreadSafeLayoutNode};
/// Virtual methods that make up a float context.
///
@@ -428,7 +428,7 @@ pub trait ImmutableFlowUtils {
fn need_anonymous_flow(self, child: &Flow) -> bool;
/// Generates missing child flow of this flow.
- fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> FlowRef;
+ fn generate_missing_child_flow(self, node: &ServoThreadSafeLayoutNode) -> FlowRef;
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
fn contains_roots_of_absolute_flow_tree(&self) -> bool;
@@ -1186,7 +1186,7 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
/// FIXME(pcwalton): This duplicates some logic in
/// `generate_anonymous_table_flows_if_necessary()`. We should remove this function eventually,
/// as it's harder to understand.
- fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> FlowRef {
+ fn generate_missing_child_flow(self, node: &ServoThreadSafeLayoutNode) -> FlowRef {
let mut style = node.style().clone();
match self.class() {
FlowClass::Table | FlowClass::TableRowGroup => {
diff --git a/components/layout/fragment.rs b/components/layout/fragment.rs
index 70fcffffe3f..df49117d626 100644
--- a/components/layout/fragment.rs
+++ b/components/layout/fragment.rs
@@ -50,7 +50,7 @@ use util::geometry::ZERO_POINT;
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
use util::range::*;
use util::str::slice_chars;
-use wrapper::{PseudoElementType, ThreadSafeLayoutNode};
+use wrapper::{PseudoElementType, ServoThreadSafeLayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode};
/// 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
@@ -309,7 +309,7 @@ pub struct CanvasFragmentInfo {
}
impl CanvasFragmentInfo {
- pub fn new(node: &ThreadSafeLayoutNode, data: HTMLCanvasData) -> CanvasFragmentInfo {
+ pub fn new(node: &ServoThreadSafeLayoutNode, data: HTMLCanvasData) -> CanvasFragmentInfo {
CanvasFragmentInfo {
replaced_image_fragment_info: ReplacedImageFragmentInfo::new(node,
Some(Au::from_px(data.width as i32)),
@@ -345,11 +345,11 @@ impl ImageFragmentInfo {
///
/// FIXME(pcwalton): The fact that image fragments store the cache in the fragment makes little
/// sense to me.
- pub fn new(node: &ThreadSafeLayoutNode,
+ pub fn new(node: &ServoThreadSafeLayoutNode,
url: Option<Url>,
layout_context: &LayoutContext)
-> ImageFragmentInfo {
- fn convert_length(node: &ThreadSafeLayoutNode, name: &Atom) -> Option<Au> {
+ fn convert_length(node: &ServoThreadSafeLayoutNode, name: &Atom) -> Option<Au> {
let element = node.as_element();
element.get_attr(&ns!(""), name)
.and_then(|string| string.parse().ok())
@@ -423,7 +423,7 @@ pub struct ReplacedImageFragmentInfo {
}
impl ReplacedImageFragmentInfo {
- pub fn new(node: &ThreadSafeLayoutNode,
+ pub fn new(node: &ServoThreadSafeLayoutNode,
dom_width: Option<Au>,
dom_height: Option<Au>) -> ReplacedImageFragmentInfo {
let is_vertical = node.style().writing_mode.is_vertical();
@@ -583,7 +583,7 @@ pub struct IframeFragmentInfo {
impl IframeFragmentInfo {
/// Creates the information specific to an iframe fragment.
- pub fn new(node: &ThreadSafeLayoutNode) -> IframeFragmentInfo {
+ pub fn new(node: &ServoThreadSafeLayoutNode) -> IframeFragmentInfo {
let pipeline_id = node.iframe_pipeline_id();
IframeFragmentInfo {
pipeline_id: pipeline_id,
@@ -758,7 +758,7 @@ pub struct TableColumnFragmentInfo {
impl TableColumnFragmentInfo {
/// Create the information specific to an table column fragment.
- pub fn new(node: &ThreadSafeLayoutNode) -> TableColumnFragmentInfo {
+ pub fn new(node: &ServoThreadSafeLayoutNode) -> TableColumnFragmentInfo {
let element = node.as_element();
let span = element.get_attr(&ns!(""), &atom!("span"))
.and_then(|string| string.parse().ok())
@@ -771,7 +771,7 @@ impl TableColumnFragmentInfo {
impl Fragment {
/// Constructs a new `Fragment` instance.
- pub fn new(node: &ThreadSafeLayoutNode, specific: SpecificFragmentInfo) -> Fragment {
+ pub fn new(node: &ServoThreadSafeLayoutNode, specific: SpecificFragmentInfo) -> Fragment {
let style = node.style().clone();
let writing_mode = style.writing_mode;
Fragment {
diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs
index 60a0ec80120..d9bbc2b78cc 100644
--- a/components/layout/layout_task.rs
+++ b/components/layout/layout_task.rs
@@ -73,7 +73,8 @@ use util::opts;
use util::task;
use util::task_state;
use util::workqueue::WorkQueue;
-use wrapper::{LayoutDocument, LayoutElement, LayoutNode, ServoLayoutNode};
+use wrapper::{LayoutDocument, LayoutElement, LayoutNode};
+use wrapper::{ServoLayoutNode, ThreadSafeLayoutNode};
/// 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;
diff --git a/components/layout/query.rs b/components/layout/query.rs
index 7c789c76cac..cdb0c7da0eb 100644
--- a/components/layout/query.rs
+++ b/components/layout/query.rs
@@ -31,7 +31,7 @@ use style::values::AuExtensionMethods;
use util::cursor::Cursor;
use util::geometry::ZERO_POINT;
use util::logical_geometry::WritingMode;
-use wrapper::{LayoutNode, ServoLayoutNode, ThreadSafeLayoutNode};
+use wrapper::{LayoutNode, ServoLayoutNode, ServoThreadSafeLayoutNode, ThreadSafeLayoutNode};
pub struct LayoutRPCImpl(pub Arc<Mutex<LayoutTaskData>>);
@@ -446,7 +446,7 @@ pub fn process_resolved_style_request(requested_node: ServoLayoutNode,
property: &Atom,
layout_root: &mut FlowRef)
-> Option<String> {
- let layout_node = ThreadSafeLayoutNode::new(&requested_node);
+ let layout_node = ServoThreadSafeLayoutNode::new(&requested_node);
let layout_node = match pseudo {
&Some(PseudoElement::Before) => layout_node.get_before_pseudo(),
&Some(PseudoElement::After) => layout_node.get_after_pseudo(),
@@ -480,7 +480,7 @@ pub fn process_resolved_style_request(requested_node: ServoLayoutNode,
// There are probably other quirks.
let applies = true;
- fn used_value_for_position_property(layout_node: ThreadSafeLayoutNode,
+ fn used_value_for_position_property(layout_node: ServoThreadSafeLayoutNode,
layout_root: &mut FlowRef,
requested_node: ServoLayoutNode,
property: &Atom) -> Option<String> {
diff --git a/components/layout/table_cell.rs b/components/layout/table_cell.rs
index eda755f177c..ed5c878c9f5 100644
--- a/components/layout/table_cell.rs
+++ b/components/layout/table_cell.rs
@@ -24,7 +24,7 @@ use style::properties::ComputedValues;
use table::InternalTable;
use table_row::{CollapsedBorder, CollapsedBorderProvenance};
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
-use wrapper::ThreadSafeLayoutNode;
+use wrapper::{ServoThreadSafeLayoutNode, ThreadSafeLayoutNode};
/// A table formatting context.
#[derive(RustcEncodable)]
@@ -44,7 +44,7 @@ pub struct TableCellFlow {
}
impl TableCellFlow {
- pub fn from_node_fragment_and_visibility_flag(node: &ThreadSafeLayoutNode,
+ pub fn from_node_fragment_and_visibility_flag(node: &ServoThreadSafeLayoutNode,
fragment: Fragment,
visible: bool)
-> TableCellFlow {
diff --git a/components/layout/traversal.rs b/components/layout/traversal.rs
index 2a25b01df95..a224f57feb1 100644
--- a/components/layout/traversal.rs
+++ b/components/layout/traversal.rs
@@ -18,7 +18,7 @@ use std::mem;
use util::opts;
use util::tid::tid;
use wrapper::{LayoutNode, ServoLayoutNode, layout_node_to_unsafe_layout_node};
-use wrapper::{ThreadSafeLayoutNode, UnsafeLayoutNode};
+use wrapper::{ServoThreadSafeLayoutNode, ThreadSafeLayoutNode, UnsafeLayoutNode};
/// Every time we do another layout, the old bloom filters are invalid. This is
/// detected by ticking a generation number every layout.
@@ -130,7 +130,7 @@ pub trait PostorderDomTraversal {
/// A bottom-up, parallelizable traversal.
pub trait PostorderNodeMutTraversal {
/// The operation to perform. Return true to continue or false to stop.
- fn process<'a>(&'a mut self, node: &ThreadSafeLayoutNode<'a>) -> bool;
+ fn process<'a>(&'a mut self, node: &ServoThreadSafeLayoutNode<'a>) -> bool;
}
/// The recalc-style-for-node traversal, which styles each node and must run before
@@ -162,7 +162,7 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> {
// Remove existing CSS styles from nodes whose content has changed (e.g. text changed),
// to force non-incremental reflow.
if node.has_changed() {
- let node = ThreadSafeLayoutNode::new(&node);
+ let node = ServoThreadSafeLayoutNode::new(&node);
node.unstyle();
}
@@ -199,7 +199,7 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> {
},
None => {
if node.has_changed() {
- ThreadSafeLayoutNode::new(&node).set_restyle_damage(
+ ServoThreadSafeLayoutNode::new(&node).set_restyle_damage(
incremental::rebuild_and_reflow())
}
None
@@ -222,7 +222,7 @@ impl<'a> PreorderDomTraversal for RecalcStyleForNode<'a> {
}
StyleSharingResult::StyleWasShared(index, damage) => {
style_sharing_candidate_cache.touch(index);
- ThreadSafeLayoutNode::new(&node).set_restyle_damage(damage);
+ ServoThreadSafeLayoutNode::new(&node).set_restyle_damage(damage);
}
}
}
@@ -252,7 +252,7 @@ impl<'a> PostorderDomTraversal for ConstructFlows<'a> {
fn process(&self, node: ServoLayoutNode) {
// Construct flows for this node.
{
- let tnode = ThreadSafeLayoutNode::new(&node);
+ let tnode = ServoThreadSafeLayoutNode::new(&node);
// Always reconstruct if incremental layout is turned off.
let nonincremental_layout = opts::get().nonincremental_layout;
diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs
index f158dfb386d..5c1622c3295 100644
--- a/components/layout/wrapper.rs
+++ b/components/layout/wrapper.rs
@@ -74,14 +74,10 @@ use util::str::{is_whitespace, search_index};
/// A wrapper so that layout can access only the methods that it should have access to. Layout must
/// only ever see these and must never see instances of `LayoutJS`.
-pub trait WrapperTypes<'a> : Sized {
- type Node: LayoutNode<'a, Self>;
- type Document: LayoutDocument<'a, Self>;
- type Element: LayoutElement<'a, Self>;
-}
+pub trait LayoutNode<'ln> : Sized + Copy + Clone {
+ type ConcreteLayoutElement: LayoutElement<'ln>;
+ type ConcreteLayoutDocument: LayoutDocument<'ln>;
-pub trait LayoutNode<'ln, Wrappers> : Sized + Copy + Clone
- where Wrappers: WrapperTypes<'ln> {
/// Returns the type ID of this node.
fn type_id(&self) -> NodeTypeId;
@@ -89,12 +85,12 @@ pub trait LayoutNode<'ln, Wrappers> : Sized + Copy + Clone
fn dump(self);
- fn traverse_preorder(self) -> LayoutTreeIterator<'ln, Wrappers>;
+ fn traverse_preorder(self) -> LayoutTreeIterator<'ln, Self>;
/// Returns an iterator over this node's children.
- fn children(self) -> LayoutNodeChildrenIterator<'ln, Wrappers>;
+ fn children(self) -> LayoutNodeChildrenIterator<'ln, Self>;
- fn rev_children(self) -> LayoutNodeReverseChildrenIterator<'ln, Wrappers>;
+ fn rev_children(self) -> LayoutNodeReverseChildrenIterator<'ln, Self>;
/// Converts self into an `OpaqueNode`.
fn opaque(&self) -> OpaqueNode;
@@ -110,9 +106,9 @@ pub trait LayoutNode<'ln, Wrappers> : Sized + Copy + Clone
fn debug_id(self) -> usize;
- fn as_element(&self) -> Option<Wrappers::Element>;
+ fn as_element(&self) -> Option<Self::ConcreteLayoutElement>;
- fn as_document(&self) -> Option<Wrappers::Document>;
+ fn as_document(&self) -> Option<Self::ConcreteLayoutDocument>;
fn children_count(&self) -> u32;
@@ -154,29 +150,33 @@ pub trait LayoutNode<'ln, Wrappers> : Sized + Copy + Clone
#[inline(always)]
fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>>;
- fn parent_node(&self) -> Option<Wrappers::Node>;
+ fn parent_node(&self) -> Option<Self>;
- fn first_child(&self) -> Option<Wrappers::Node>;
+ fn first_child(&self) -> Option<Self>;
- fn last_child(&self) -> Option<Wrappers::Node>;
+ fn last_child(&self) -> Option<Self>;
- fn prev_sibling(&self) -> Option<Wrappers::Node>;
+ fn prev_sibling(&self) -> Option<Self>;
- fn next_sibling(&self) -> Option<Wrappers::Node>;
+ fn next_sibling(&self) -> Option<Self>;
}
-pub trait LayoutDocument<'ld, Wrappers> : Sized + Copy + Clone
- where Wrappers: WrapperTypes<'ld> {
- fn as_node(&self) -> Wrappers::Node;
+pub trait LayoutDocument<'ld> : Sized + Copy + Clone {
+ type ConcreteLayoutNode: LayoutNode<'ld>;
+ type ConcreteLayoutElement: LayoutElement<'ld>;
+
+ fn as_node(&self) -> Self::ConcreteLayoutNode;
- fn root_node(&self) -> Option<Wrappers::Node>;
+ fn root_node(&self) -> Option<Self::ConcreteLayoutNode>;
- fn drain_modified_elements(&self) -> Vec<(Wrappers::Element, ElementSnapshot)>;
+ fn drain_modified_elements(&self) -> Vec<(Self::ConcreteLayoutElement, ElementSnapshot)>;
}
-pub trait LayoutElement<'le, Wrappers> : Sized + Copy + Clone + ::selectors::Element
- where Wrappers: WrapperTypes<'le> {
- fn as_node(&self) -> Wrappers::Node;
+pub trait LayoutElement<'le> : Sized + Copy + Clone + ::selectors::Element + TElementAttributes {
+ type ConcreteLayoutNode: LayoutNode<'le>;
+ type ConcreteLayoutDocument: LayoutDocument<'le>;
+
+ fn as_node(&self) -> Self::ConcreteLayoutNode;
fn style_attribute(&self) -> &'le Option<PropertyDeclarationBlock>;
@@ -224,17 +224,6 @@ pub trait LayoutElement<'le, Wrappers> : Sized + Copy + Clone + ::selectors::Ele
}
}
-pub struct ServoWrapperTypes<'a> {
- // Satisfy the compiler about the unused lifetime.
- phantom: PhantomData<&'a ()>,
-}
-
-impl<'a> WrapperTypes<'a> for ServoWrapperTypes<'a> {
- type Node = ServoLayoutNode<'a>;
- type Element = ServoLayoutElement<'a>;
- type Document = ServoLayoutDocument<'a>;
-}
-
#[derive(Copy, Clone)]
pub struct ServoLayoutNode<'a> {
/// The wrapped node.
@@ -272,7 +261,10 @@ impl<'ln> ServoLayoutNode<'ln> {
}
}
-impl<'ln> LayoutNode<'ln, ServoWrapperTypes<'ln>> for ServoLayoutNode<'ln> {
+impl<'ln> LayoutNode<'ln> for ServoLayoutNode<'ln> {
+ type ConcreteLayoutElement = ServoLayoutElement<'ln>;
+ type ConcreteLayoutDocument = ServoLayoutDocument<'ln>;
+
fn type_id(&self) -> NodeTypeId {
unsafe {
self.node.type_id_for_layout()
@@ -289,19 +281,21 @@ impl<'ln> LayoutNode<'ln, ServoWrapperTypes<'ln>> for ServoLayoutNode<'ln> {
self.dump_indent(0);
}
- fn traverse_preorder(self) -> LayoutTreeIterator<'ln, ServoWrapperTypes<'ln>> {
+ fn traverse_preorder(self) -> LayoutTreeIterator<'ln, Self> {
LayoutTreeIterator::new(self)
}
- fn children(self) -> LayoutNodeChildrenIterator<'ln, ServoWrapperTypes<'ln>> {
+ fn children(self) -> LayoutNodeChildrenIterator<'ln, Self> {
LayoutNodeChildrenIterator {
current: self.first_child(),
+ phantom: PhantomData,
}
}
- fn rev_children(self) -> LayoutNodeReverseChildrenIterator<'ln, ServoWrapperTypes<'ln>> {
+ fn rev_children(self) -> LayoutNodeReverseChildrenIterator<'ln, Self> {
LayoutNodeReverseChildrenIterator {
- current: self.last_child()
+ current: self.last_child(),
+ phantom: PhantomData,
}
}
@@ -452,49 +446,59 @@ impl<'ln> ServoLayoutNode<'ln> {
}
}
-pub struct LayoutNodeChildrenIterator<'a, Wrappers: WrapperTypes<'a>> {
- current: Option<Wrappers::Node>,
+pub struct LayoutNodeChildrenIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
+ current: Option<ConcreteLayoutNode>,
+ // Satisfy the compiler about the unused lifetime.
+ phantom: PhantomData<&'a ()>,
}
-impl<'a, Wrappers: WrapperTypes<'a>> Iterator for LayoutNodeChildrenIterator<'a, Wrappers> {
- type Item = Wrappers::Node;
- fn next(&mut self) -> Option<Wrappers::Node> {
+impl<'a, ConcreteLayoutNode> Iterator for LayoutNodeChildrenIterator<'a, ConcreteLayoutNode>
+ where ConcreteLayoutNode: LayoutNode<'a> {
+ type Item = ConcreteLayoutNode;
+ fn next(&mut self) -> Option<ConcreteLayoutNode> {
let node = self.current;
self.current = node.and_then(|node| node.next_sibling());
node
}
}
-pub struct LayoutNodeReverseChildrenIterator<'a, Wrappers: WrapperTypes<'a>> {
- current: Option<Wrappers::Node>,
+pub struct LayoutNodeReverseChildrenIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
+ current: Option<ConcreteLayoutNode>,
+ // Satisfy the compiler about the unused lifetime.
+ phantom: PhantomData<&'a ()>,
}
-impl<'a, Wrappers: WrapperTypes<'a>> Iterator for LayoutNodeReverseChildrenIterator<'a, Wrappers> {
- type Item = Wrappers::Node;
- fn next(&mut self) -> Option<Wrappers::Node> {
+impl<'a, ConcreteLayoutNode> Iterator for LayoutNodeReverseChildrenIterator<'a, ConcreteLayoutNode>
+ where ConcreteLayoutNode: LayoutNode<'a> {
+ type Item = ConcreteLayoutNode;
+ fn next(&mut self) -> Option<ConcreteLayoutNode> {
let node = self.current;
self.current = node.and_then(|node| node.prev_sibling());
node
}
}
-pub struct LayoutTreeIterator<'a, Wrappers: WrapperTypes<'a>> {
- stack: Vec<Wrappers::Node>,
+pub struct LayoutTreeIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
+ stack: Vec<ConcreteLayoutNode>,
+ // Satisfy the compiler about the unused lifetime.
+ phantom: PhantomData<&'a ()>,
}
-impl<'a, Wrappers> LayoutTreeIterator<'a, Wrappers> where Wrappers: WrapperTypes<'a> {
- fn new(root: Wrappers::Node) -> LayoutTreeIterator<'a, Wrappers> {
+impl<'a, ConcreteLayoutNode> LayoutTreeIterator<'a, ConcreteLayoutNode> where ConcreteLayoutNode: LayoutNode<'a> {
+ fn new(root: ConcreteLayoutNode) -> LayoutTreeIterator<'a, ConcreteLayoutNode> {
let mut stack = vec!();
stack.push(root);
LayoutTreeIterator {
- stack: stack
+ stack: stack,
+ phantom: PhantomData,
}
}
}
-impl<'a, Wrappers> Iterator for LayoutTreeIterator<'a, Wrappers> where Wrappers: WrapperTypes<'a> {
- type Item = Wrappers::Node;
- fn next(&mut self) -> Option<Wrappers::Node> {
+impl<'a, ConcreteLayoutNode> Iterator for LayoutTreeIterator<'a, ConcreteLayoutNode>
+ where ConcreteLayoutNode: LayoutNode<'a> {
+ type Item = ConcreteLayoutNode;
+ fn next(&mut self) -> Option<ConcreteLayoutNode> {
let ret = self.stack.pop();
ret.map(|node| self.stack.extend(node.rev_children()));
ret
@@ -508,7 +512,10 @@ pub struct ServoLayoutDocument<'ld> {
chain: PhantomData<&'ld ()>,
}
-impl<'ld> LayoutDocument<'ld, ServoWrapperTypes<'ld>> for ServoLayoutDocument<'ld> {
+impl<'ld> LayoutDocument<'ld> for ServoLayoutDocument<'ld> {
+ type ConcreteLayoutNode = ServoLayoutNode<'ld>;
+ type ConcreteLayoutElement = ServoLayoutElement<'ld>;
+
fn as_node(&self) -> ServoLayoutNode<'ld> {
ServoLayoutNode::from_layout_js(self.document.upcast())
}
@@ -539,7 +546,10 @@ pub struct ServoLayoutElement<'le> {
chain: PhantomData<&'le ()>,
}
-impl<'le> LayoutElement<'le, ServoWrapperTypes<'le>> for ServoLayoutElement<'le> {
+impl<'le> LayoutElement<'le> for ServoLayoutElement<'le> {
+ type ConcreteLayoutNode = ServoLayoutNode<'le>;
+ type ConcreteLayoutDocument = ServoLayoutDocument<'le>;
+
fn as_node(&self) -> ServoLayoutNode<'le> {
ServoLayoutNode::from_layout_js(self.element.upcast())
}
@@ -782,35 +792,203 @@ impl<T> PseudoElementType<T> {
/// 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.
+
+pub trait ThreadSafeLayoutNode<'ln> : Clone + Copy + Sized {
+ type ConcreteThreadSafeLayoutElement: ThreadSafeLayoutElement<'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> : ThreadSafeLayoutNode<'ln> {
+ unsafe fn dangerous_first_child(&self) -> Option<Self>;
+ unsafe fn dangerous_next_sibling(&self) -> Option<Self>;
+}
+
+pub trait ThreadSafeLayoutElement<'le> {
+ type ConcreteThreadSafeLayoutNode: ThreadSafeLayoutNode<'le>;
+
+ #[inline]
+ fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str>;
+}
+
#[derive(Copy, Clone)]
-pub struct ThreadSafeLayoutNode<'ln> {
+pub struct ServoThreadSafeLayoutNode<'ln> {
/// The wrapped node.
node: ServoLayoutNode<'ln>,
pseudo: PseudoElementType<display::T>,
}
-impl<'ln> ThreadSafeLayoutNode<'ln> {
+impl<'ln> DangerousThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'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> ServoThreadSafeLayoutNode<'ln> {
/// 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> {
- ThreadSafeLayoutNode {
+ pub unsafe fn new_with_this_lifetime(&self, node: &LayoutJS<Node>) -> ServoThreadSafeLayoutNode<'ln> {
+ ServoThreadSafeLayoutNode {
node: self.node.new_with_this_lifetime(node),
pseudo: PseudoElementType::Normal,
}
}
- /// Creates a new `ThreadSafeLayoutNode` from the given `LayoutNode`.
- pub fn new<'a>(node: &ServoLayoutNode<'a>) -> ThreadSafeLayoutNode<'a> {
- ThreadSafeLayoutNode {
+ /// Creates a new `ServoThreadSafeLayoutNode` from the given `ServoLayoutNode`.
+ pub fn new<'a>(node: &ServoLayoutNode<'a>) -> ServoThreadSafeLayoutNode<'a> {
+ ServoThreadSafeLayoutNode {
node: node.clone(),
pseudo: PseudoElementType::Normal,
}
}
- /// Creates a new `ThreadSafeLayoutNode` for the same `LayoutNode`
+ /// Creates a new `ServoThreadSafeLayoutNode` for the same `LayoutNode`
/// with a different pseudo-element type.
- fn with_pseudo(&self, pseudo: PseudoElementType<display::T>) -> ThreadSafeLayoutNode<'ln> {
- ThreadSafeLayoutNode {
+ fn with_pseudo(&self, pseudo: PseudoElementType<display::T>) -> ServoThreadSafeLayoutNode<'ln> {
+ ServoThreadSafeLayoutNode {
node: self.node.clone(),
pseudo: pseudo,
}
@@ -822,14 +1000,23 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
self.node.get_jsmanaged()
}
- /// Converts self into an `OpaqueNode`.
- pub fn opaque(&self) -> OpaqueNode {
+ /// Borrows the layout data without checking.
+ #[inline(always)]
+ fn borrow_layout_data_unchecked(&self) -> *const Option<LayoutDataWrapper> {
+ unsafe {
+ self.node.borrow_layout_data_unchecked()
+ }
+ }
+}
+
+impl<'ln> ThreadSafeLayoutNode<'ln> for ServoThreadSafeLayoutNode<'ln> {
+ type ConcreteThreadSafeLayoutElement = ServoThreadSafeLayoutElement<'ln>;
+
+ fn opaque(&self) -> OpaqueNode {
OpaqueNodeMethods::from_jsmanaged(unsafe { self.get_jsmanaged() })
}
- /// Returns the type ID of this node.
- /// Returns `None` if this is a pseudo-element; otherwise, returns `Some`.
- pub fn type_id(&self) -> Option<NodeTypeId> {
+ fn type_id(&self) -> Option<NodeTypeId> {
if self.pseudo != PseudoElementType::Normal {
return None
}
@@ -837,22 +1024,19 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
Some(self.node.type_id())
}
- pub fn debug_id(self) -> usize {
+ fn debug_id(self) -> usize {
self.node.debug_id()
}
- pub fn flow_debug_id(self) -> usize {
+ fn flow_debug_id(self) -> usize {
self.node.flow_debug_id()
}
- /// Returns an iterator over this node's children.
- pub fn children(&self) -> ThreadSafeLayoutNodeChildrenIterator<'ln> {
+ fn children(&self) -> ThreadSafeLayoutNodeChildrenIterator<'ln, Self> {
ThreadSafeLayoutNodeChildrenIterator::new(*self)
}
- /// If this is an element, accesses the element data. Fails if this is not an element node.
- #[inline]
- pub fn as_element(&self) -> ThreadSafeLayoutElement<'ln> {
+ fn as_element(&self) -> ServoThreadSafeLayoutElement<'ln> {
unsafe {
let element = match self.get_jsmanaged().downcast() {
Some(e) => e.unsafe_get(),
@@ -860,19 +1044,17 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
};
// FIXME(pcwalton): Workaround until Rust gets multiple lifetime parameters on
// implementations.
- ThreadSafeLayoutElement {
+ ServoThreadSafeLayoutElement {
element: &*element,
}
}
}
- #[inline]
- pub fn get_pseudo_element_type(&self) -> PseudoElementType<display::T> {
+ fn get_pseudo_element_type(&self) -> PseudoElementType<display::T> {
self.pseudo
}
- #[inline]
- pub fn get_before_pseudo(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
+ fn get_before_pseudo(&self) -> Option<ServoThreadSafeLayoutNode<'ln>> {
let layout_data_ref = self.borrow_layout_data();
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
node_layout_data_wrapper.data.before_style.as_ref().map(|style| {
@@ -880,8 +1062,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
})
}
- #[inline]
- pub fn get_after_pseudo(&self) -> Option<ThreadSafeLayoutNode<'ln>> {
+ fn get_after_pseudo(&self) -> Option<ServoThreadSafeLayoutNode<'ln>> {
let layout_data_ref = self.borrow_layout_data();
let node_layout_data_wrapper = layout_data_ref.as_ref().unwrap();
node_layout_data_wrapper.data.after_style.as_ref().map(|style| {
@@ -889,61 +1070,15 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
})
}
- /// Borrows the layout data without checking.
- #[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>> {
+ fn borrow_layout_data(&self) -> Ref<Option<LayoutDataWrapper>> {
self.node.borrow_layout_data()
}
- /// 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)]
- pub fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>> {
+ fn mutate_layout_data(&self) -> RefMut<Option<LayoutDataWrapper>> {
self.node.mutate_layout_data()
}
- /// Returns the style results for the given node. If CSS selector matching
- /// 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 {
+ fn is_ignorable_whitespace(&self) -> bool {
unsafe {
let text: LayoutJS<Text> = match self.get_jsmanaged().downcast() {
Some(text) => text,
@@ -964,24 +1099,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
}
}
- /// Get the description of how to account for recent style changes.
- /// 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 {
+ fn flags(self) -> LayoutDataFlags {
unsafe {
match *self.borrow_layout_data_unchecked() {
None => panic!(),
@@ -990,38 +1108,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
}
}
- /// Adds the given flags to this node.
- 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 {
+ fn text_content(&self) -> TextContent {
if self.pseudo != PseudoElementType::Normal {
let layout_data_ref = self.borrow_layout_data();
let data = &layout_data_ref.as_ref().unwrap().data;
@@ -1058,8 +1145,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
panic!("not text!")
}
- /// If the insertion point is within this node, returns it. Otherwise, returns `None`.
- pub fn insertion_point(&self) -> Option<CharIndex> {
+ fn insertion_point(&self) -> Option<CharIndex> {
let this = unsafe {
self.get_jsmanaged()
};
@@ -1078,10 +1164,7 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
None
}
- /// If this is an image element, returns its URL. If this is not an image element, fails.
- ///
- /// FIXME(pcwalton): Don't copy URLs.
- pub fn image_url(&self) -> Option<Url> {
+ fn image_url(&self) -> Option<Url> {
unsafe {
self.get_jsmanaged().downcast()
.expect("not an image!")
@@ -1089,16 +1172,14 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
}
}
- pub fn canvas_data(&self) -> Option<HTMLCanvasData> {
+ fn canvas_data(&self) -> Option<HTMLCanvasData> {
unsafe {
let canvas_element = self.get_jsmanaged().downcast();
canvas_element.map(|canvas| canvas.data())
}
}
- /// If this node is an iframe element, returns its pipeline ID. If this node is
- /// not an iframe element, fails.
- pub fn iframe_pipeline_id(&self) -> PipelineId {
+ fn iframe_pipeline_id(&self) -> PipelineId {
use script::dom::htmliframeelement::HTMLIFrameElementLayoutMethods;
unsafe {
let iframe_element = self.get_jsmanaged().downcast::<HTMLIFrameElement>()
@@ -1107,65 +1188,56 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
}
}
- pub fn get_colspan(&self) -> u32 {
+ fn get_colspan(&self) -> u32 {
unsafe {
self.get_jsmanaged().downcast::<Element>().unwrap().get_colspan()
}
}
}
-pub struct ThreadSafeLayoutNodeChildrenIterator<'a> {
- current_node: Option<ThreadSafeLayoutNode<'a>>,
- parent_node: ThreadSafeLayoutNode<'a>,
+pub struct ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode: ThreadSafeLayoutNode<'ln>> {
+ current_node: Option<ConcreteNode>,
+ parent_node: ConcreteNode,
+ // Satisfy the compiler about the unused lifetime.
+ phantom: PhantomData<&'ln ()>,
}
-impl<'a> ThreadSafeLayoutNodeChildrenIterator<'a> {
- fn new(parent: ThreadSafeLayoutNode<'a>) -> ThreadSafeLayoutNodeChildrenIterator<'a> {
- fn first_child(parent: ThreadSafeLayoutNode)
- -> Option<ThreadSafeLayoutNode> {
- if parent.pseudo != PseudoElementType::Normal {
- return None
- }
-
- parent.get_before_pseudo().or_else(|| {
- unsafe {
- parent.get_jsmanaged().first_child_ref()
- .map(|node| parent.new_with_this_lifetime(&node))
- }
- })
- }
-
+impl<'ln, ConcreteNode> ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode>
+ where ConcreteNode: DangerousThreadSafeLayoutNode<'ln> {
+ fn new(parent: ConcreteNode) -> Self {
+ let first_child: Option<ConcreteNode> = match parent.get_pseudo_element_type() {
+ PseudoElementType::Normal => {
+ parent.get_before_pseudo().or_else(|| {
+ unsafe { parent.dangerous_first_child() }
+ })
+ },
+ _ => None,
+ };
ThreadSafeLayoutNodeChildrenIterator {
- current_node: first_child(parent),
+ current_node: first_child,
parent_node: parent,
+ phantom: PhantomData,
}
}
}
-impl<'a> Iterator for ThreadSafeLayoutNodeChildrenIterator<'a> {
- type Item = ThreadSafeLayoutNode<'a>;
- fn next(&mut self) -> Option<ThreadSafeLayoutNode<'a>> {
+impl<'ln, ConcreteNode> Iterator for ThreadSafeLayoutNodeChildrenIterator<'ln, ConcreteNode>
+ where ConcreteNode: DangerousThreadSafeLayoutNode<'ln> {
+ type Item = ConcreteNode;
+ fn next(&mut self) -> Option<ConcreteNode> {
let node = self.current_node.clone();
if let Some(ref node) = node {
- self.current_node = match node.pseudo {
+ self.current_node = match node.get_pseudo_element_type() {
PseudoElementType::Before(_) => {
- match unsafe { self.parent_node.get_jsmanaged().first_child_ref() } {
- Some(first) => {
- Some(unsafe {
- self.parent_node.new_with_this_lifetime(&first)
- })
- },
+ match unsafe { self.parent_node.dangerous_first_child() } {
+ Some(first) => Some(first),
None => self.parent_node.get_after_pseudo(),
}
},
PseudoElementType::Normal => {
- match unsafe { node.get_jsmanaged().next_sibling_ref() } {
- Some(next) => {
- Some(unsafe {
- self.parent_node.new_with_this_lifetime(&next)
- })
- },
+ match unsafe { node.dangerous_next_sibling() } {
+ Some(next) => Some(next),
None => self.parent_node.get_after_pseudo(),
}
},
@@ -1181,13 +1253,14 @@ impl<'a> Iterator for ThreadSafeLayoutNodeChildrenIterator<'a> {
/// A wrapper around elements that ensures layout can only ever access safe properties and cannot
/// race on elements.
-pub struct ThreadSafeLayoutElement<'le> {
+pub struct ServoThreadSafeLayoutElement<'le> {
element: &'le Element,
}
-impl<'le> ThreadSafeLayoutElement<'le> {
- #[inline]
- pub fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str> {
+impl<'le> ThreadSafeLayoutElement<'le> for ServoThreadSafeLayoutElement<'le> {
+ type ConcreteThreadSafeLayoutNode = ServoThreadSafeLayoutNode<'le>;
+
+ fn get_attr(&self, namespace: &Namespace, name: &Atom) -> Option<&'le str> {
unsafe {
self.element.get_attr_val_for_layout(namespace, name)
}