aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/components/main/layout/block.rs53
-rw-r--r--src/components/main/layout/construct.rs232
-rw-r--r--src/components/main/layout/flow.rs220
-rw-r--r--src/components/main/layout/flow_list.rs179
-rw-r--r--src/components/main/layout/flow_ref.rs79
-rw-r--r--src/components/main/layout/fragment.rs7
-rw-r--r--src/components/main/layout/inline.rs2
-rw-r--r--src/components/main/layout/layout_task.rs38
-rw-r--r--src/components/main/layout/model.rs2
-rw-r--r--src/components/main/layout/parallel.rs69
-rw-r--r--src/components/main/layout/table.rs2
-rw-r--r--src/components/main/layout/table_caption.rs2
-rw-r--r--src/components/main/layout/table_cell.rs2
-rw-r--r--src/components/main/layout/table_colgroup.rs2
-rw-r--r--src/components/main/layout/table_row.rs2
-rw-r--r--src/components/main/layout/table_rowgroup.rs2
-rw-r--r--src/components/main/layout/table_wrapper.rs2
-rw-r--r--src/components/main/layout/text.rs2
-rw-r--r--src/components/main/layout/wrapper.rs40
-rw-r--r--src/components/main/servo.rs1
20 files changed, 485 insertions, 453 deletions
diff --git a/src/components/main/layout/block.rs b/src/components/main/layout/block.rs
index 24f60acf7d1..d0187afda8e 100644
--- a/src/components/main/layout/block.rs
+++ b/src/components/main/layout/block.rs
@@ -12,6 +12,8 @@
//!
//! CB: Containing Block of the current flow.
+#![deny(unsafe_block)]
+
use layout::construct::FlowConstructor;
use layout::context::LayoutContext;
use layout::floats::{ClearBoth, ClearLeft, ClearRight, FloatKind, Floats, PlacementInfo};
@@ -656,17 +658,12 @@ impl BlockFlow {
let mut descendant_offset_iter = mut_base(flow).abs_descendants.iter_with_offset();
// Pass in the respective static y offset for each descendant.
for (ref mut descendant_link, ref y_offset) in descendant_offset_iter {
- match descendant_link.resolve() {
- Some(flow) => {
- let block = flow.as_block();
- // The stored y_offset is wrt to the flow box.
- // Translate it to the CB (which is the padding box).
- block.static_y_offset = **y_offset - cb_top_edge_offset;
- if !block.traverse_preorder_absolute_flows(traversal) {
- return false
- }
- }
- None => fail!("empty Rawlink to a descendant")
+ let block = descendant_link.as_block();
+ // The stored y_offset is wrt to the flow box.
+ // Translate it to the CB (which is the padding box).
+ block.static_y_offset = **y_offset - cb_top_edge_offset;
+ if !block.traverse_preorder_absolute_flows(traversal) {
+ return false
}
}
@@ -685,14 +682,9 @@ impl BlockFlow {
}
for descendant_link in mut_base(flow).abs_descendants.iter() {
- match descendant_link.resolve() {
- Some(abs_flow) => {
- let block = abs_flow.as_block();
- if !block.traverse_postorder_absolute_flows(traversal) {
- return false
- }
- }
- None => fail!("empty Rawlink to a descendant")
+ let block = descendant_link.as_block();
+ if !block.traverse_postorder_absolute_flows(traversal) {
+ return false
}
}
@@ -1125,15 +1117,10 @@ impl BlockFlow {
// Process absolute descendant links.
for abs_descendant_link in self.base.abs_descendants.iter() {
- match abs_descendant_link.resolve() {
- Some(kid) => {
- // TODO(pradeep): Send in our absolute position directly.
- accumulator.push_child(&mut display_list, kid);
- child_layers.append(mem::replace(&mut flow::mut_base(kid).layers,
- DList::new()));
- }
- None => fail!("empty Rawlink to a descendant")
- }
+ // TODO(pradeep): Send in our absolute position directly.
+ accumulator.push_child(&mut display_list, abs_descendant_link);
+ child_layers.append(mem::replace(&mut flow::mut_base(abs_descendant_link).layers,
+ DList::new()));
}
accumulator.finish(&mut *self, display_list);
@@ -1634,14 +1621,8 @@ impl Flow for BlockFlow {
}
// Process absolute descendant links.
- for absolute_descendant_link in self.base.abs_descendants.iter() {
- match absolute_descendant_link.resolve() {
- Some(absolute_descendant) => {
- flow::mut_base(absolute_descendant).absolute_position_info =
- absolute_position_info
- }
- None => fail!("empty Rawlink to a descendant")
- }
+ for absolute_descendant in self.base.abs_descendants.iter() {
+ flow::mut_base(absolute_descendant).absolute_position_info = absolute_position_info
}
}
diff --git a/src/components/main/layout/construct.rs b/src/components/main/layout/construct.rs
index e84fa3e7350..a6f7e97698e 100644
--- a/src/components/main/layout/construct.rs
+++ b/src/components/main/layout/construct.rs
@@ -16,9 +16,8 @@
//! apart" a flow tree and have the flows migrate "home" to their respective DOM nodes while we
//! perform flow tree construction. The precise mechanism for this will take some experimentation
//! to get right.
-//!
-//! TODO(pcwalton): This scheme should be amenable to parallelization, but, of course, that's not
-//! yet implemented.
+
+#![deny(unsafe_block)]
use css::node_style::StyledNode;
use layout::block::BlockFlow;
@@ -26,11 +25,15 @@ use layout::context::LayoutContext;
use layout::floats::FloatKind;
use layout::flow::{Flow, ImmutableFlowUtils, MutableOwnedFlowUtils};
use layout::flow::{Descendants, AbsDescendants};
-use layout::flow_list::{Rawlink};
-use layout::fragment::{Fragment, GenericFragment, IframeFragment, IframeFragmentInfo, ImageFragment, ImageFragmentInfo};
-use layout::fragment::{SpecificFragmentInfo, TableFragment, TableCellFragment, TableColumnFragment, TableColumnFragmentInfo};
-use layout::fragment::{TableRowFragment, TableWrapperFragment, UnscannedTextFragment, UnscannedTextFragmentInfo};
+use layout::flow;
+use layout::flow_ref::FlowRef;
+use layout::fragment::{Fragment, GenericFragment, IframeFragment, IframeFragmentInfo};
+use layout::fragment::{ImageFragment, ImageFragmentInfo, SpecificFragmentInfo, TableFragment};
+use layout::fragment::{TableCellFragment, TableColumnFragment, TableColumnFragmentInfo};
+use layout::fragment::{TableRowFragment, TableWrapperFragment, UnscannedTextFragment};
+use layout::fragment::{UnscannedTextFragmentInfo};
use layout::inline::{FragmentIndex, InlineFragments, InlineFlow};
+use layout::parallel;
use layout::table_wrapper::TableWrapperFlow;
use layout::table::TableFlow;
use layout::table_caption::TableCaptionFlow;
@@ -45,7 +48,6 @@ use layout::wrapper::{Before, BeforeBlock, After, AfterBlock, Normal};
use gfx::display_list::OpaqueNode;
use gfx::font_context::FontContext;
-use script::dom::bindings::js::JS;
use script::dom::element::{HTMLIFrameElementTypeId, HTMLImageElementTypeId};
use script::dom::element::{HTMLObjectElementTypeId};
use script::dom::element::{HTMLTableColElementTypeId, HTMLTableDataCellElementTypeId};
@@ -54,14 +56,13 @@ use script::dom::element::{HTMLTableRowElementTypeId, HTMLTableSectionElementTyp
use script::dom::node::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId};
use script::dom::node::{TextNodeTypeId};
-use script::dom::text::Text;
use servo_util::namespace;
use servo_util::range::Range;
-use servo_util::str::is_whitespace;
use servo_util::url::{is_image_data, parse_url};
use std::mem;
+use std::sync::atomics::Relaxed;
use style::ComputedValues;
-use style::computed_values::{display, position, float, white_space};
+use style::computed_values::{display, position, float};
use sync::Arc;
use url::Url;
@@ -74,23 +75,13 @@ pub enum ConstructionResult {
/// This node contributed a flow at the proper position in the tree.
/// Nothing more needs to be done for this node. It has bubbled up fixed
/// and absolute descendant flows that have a CB above it.
- FlowConstructionResult(Box<Flow:Share>, AbsDescendants),
+ FlowConstructionResult(FlowRef, AbsDescendants),
/// This node contributed some object or objects that will be needed to construct a proper flow
/// later up the tree, but these objects have not yet found their home.
ConstructionItemConstructionResult(ConstructionItem),
}
-impl ConstructionResult {
- fn destroy(&mut self) {
- match *self {
- NoConstructionResult => {}
- FlowConstructionResult(ref mut flow, _) => flow.destroy(),
- ConstructionItemConstructionResult(ref mut item) => item.destroy(),
- }
- }
-}
-
/// Represents the output of flow construction for a DOM node that has not yet resulted in a
/// complete flow. Construction items bubble up the tree until they find a `Flow` to be
/// attached to.
@@ -103,20 +94,6 @@ pub enum ConstructionItem {
TableColumnFragmentConstructionItem(Fragment),
}
-impl ConstructionItem {
- fn destroy(&mut self) {
- match *self {
- InlineFragmentsConstructionItem(ref mut result) => {
- for split in result.splits.mut_iter() {
- split.destroy()
- }
- }
- WhitespaceConstructionItem(..) => {}
- TableColumnFragmentConstructionItem(_) => {}
- }
- }
-}
-
/// Represents inline fragments and {ib} splits that are bubbling up from an inline.
pub struct InlineFragmentsConstructionResult {
/// Any {ib} splits that we're bubbling up.
@@ -156,13 +133,7 @@ pub struct InlineBlockSplit {
pub predecessors: InlineFragments,
/// The flow that caused this {ib} split.
- pub flow: Box<Flow:Share>,
-}
-
-impl InlineBlockSplit {
- fn destroy(&mut self) {
- self.flow.destroy()
- }
+ pub flow: FlowRef,
}
/// Holds inline fragments that we're gathering for children of an inline node.
@@ -302,8 +273,8 @@ impl<'a> FlowConstructor<'a> {
#[inline(always)]
fn flush_inline_fragments_to_flow_or_list(&mut self,
fragment_accumulator: InlineFragmentsAccumulator,
- flow: &mut Box<Flow:Share>,
- flow_list: &mut Vec<Box<Flow:Share>>,
+ flow: &mut FlowRef,
+ flow_list: &mut Vec<FlowRef>,
whitespace_stripping: WhitespaceStrippingMode,
node: &ThreadSafeLayoutNode) {
let mut fragments = fragment_accumulator.finish();
@@ -323,11 +294,12 @@ impl<'a> FlowConstructor<'a> {
let mut inline_flow = box InlineFlow::from_fragments((*node).clone(), fragments);
inline_flow.compute_minimum_ascent_and_descent(self.font_context(), &**node.style());
- let mut inline_flow = inline_flow as Box<Flow:Share>;
+ let mut inline_flow = inline_flow as Box<Flow>;
TextRunScanner::new().scan_for_runs(self.font_context(), inline_flow);
+ let mut inline_flow = FlowRef::new(inline_flow);
inline_flow.finish(self.layout_context);
- if flow.need_anonymous_flow(inline_flow) {
+ if flow.get().need_anonymous_flow(inline_flow.get()) {
flow_list.push(inline_flow)
} else {
flow.add_new_child(inline_flow)
@@ -335,9 +307,8 @@ impl<'a> FlowConstructor<'a> {
}
fn build_block_flow_using_children_construction_result(&mut self,
- flow: &mut Box<Flow:Share>,
- consecutive_siblings:
- &mut Vec<Box<Flow:Share>>,
+ flow: &mut FlowRef,
+ consecutive_siblings: &mut Vec<FlowRef>,
node: &ThreadSafeLayoutNode,
kid: ThreadSafeLayoutNode,
inline_fragment_accumulator:
@@ -349,16 +320,16 @@ impl<'a> FlowConstructor<'a> {
FlowConstructionResult(kid_flow, kid_abs_descendants) => {
// If kid_flow is TableCaptionFlow, kid_flow should be added under
// TableWrapperFlow.
- if flow.is_table() && kid_flow.is_table_caption() {
+ if flow.get().is_table() && kid_flow.get().is_table_caption() {
kid.set_flow_construction_result(FlowConstructionResult(
kid_flow,
Descendants::new()))
- } else if flow.need_anonymous_flow(kid_flow) {
+ } else if flow.get().need_anonymous_flow(kid_flow.get()) {
consecutive_siblings.push(kid_flow)
} else {
// Strip ignorable whitespace from the start of this flow per CSS 2.1 §
// 9.2.1.1.
- let whitespace_stripping = if flow.is_table_kind() || *first_fragment {
+ let whitespace_stripping = if flow.get().is_table_kind() || *first_fragment {
*first_fragment = false;
StripWhitespaceFromStart
} else {
@@ -423,7 +394,7 @@ impl<'a> FlowConstructor<'a> {
// Push the flow generated by the {ib} split onto our list of
// flows.
- if flow.need_anonymous_flow(kid_flow) {
+ if flow.get().need_anonymous_flow(kid_flow.get()) {
consecutive_siblings.push(kid_flow)
} else {
flow.add_new_child(kid_flow)
@@ -451,9 +422,7 @@ impl<'a> FlowConstructor<'a> {
/// this block flow.
/// Also, deal with the absolute and fixed descendants bubbled up by
/// children nodes.
- fn build_flow_using_children(&mut self,
- mut flow: Box<Flow:Share>,
- node: &ThreadSafeLayoutNode)
+ fn build_flow_using_children(&mut self, mut flow: FlowRef, node: &ThreadSafeLayoutNode)
-> ConstructionResult {
// Gather up fragments for the inline flows we might need to create.
let mut inline_fragment_accumulator = InlineFragmentsAccumulator::new();
@@ -489,18 +458,19 @@ impl<'a> FlowConstructor<'a> {
// The flow is done.
flow.finish(self.layout_context);
- let is_positioned = flow.as_block().is_positioned();
- let is_fixed_positioned = flow.as_block().is_fixed();
- let is_absolutely_positioned = flow.as_block().is_absolutely_positioned();
+ let is_positioned = flow.get_mut().as_block().is_positioned();
+ let is_fixed_positioned = flow.get_mut().as_block().is_fixed();
+ let is_absolutely_positioned = flow.get_mut().as_block().is_absolutely_positioned();
if is_positioned {
// This is the CB for all the absolute descendants.
flow.set_abs_descendants(abs_descendants);
+
abs_descendants = Descendants::new();
if is_fixed_positioned || is_absolutely_positioned {
// This is now the only absolute flow in the subtree which hasn't yet
// reached its CB.
- abs_descendants.push(Rawlink::some(flow));
+ abs_descendants.push(flow.clone());
}
}
FlowConstructionResult(flow, abs_descendants)
@@ -510,16 +480,16 @@ impl<'a> FlowConstructor<'a> {
/// 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) -> ConstructionResult {
- let flow = box BlockFlow::from_node(self, node) as Box<Flow:Share>;
- self.build_flow_using_children(flow, node)
+ let flow = box BlockFlow::from_node(self, node) as Box<Flow>;
+ self.build_flow_using_children(FlowRef::new(flow), node)
}
/// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with
/// a `BlockFlow` underneath it.
fn build_flow_for_floated_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: FloatKind)
-> ConstructionResult {
- let flow = box BlockFlow::float_from_node(self, node, float_kind) as Box<Flow:Share>;
- self.build_flow_using_children(flow, node)
+ let flow = box BlockFlow::float_from_node(self, node, float_kind) as Box<Flow>;
+ self.build_flow_using_children(FlowRef::new(flow), node)
}
/// Concatenates the fragments of kids, adding in our own borders/padding/margins if necessary.
@@ -655,14 +625,14 @@ impl<'a> FlowConstructor<'a> {
/// TableCaptionFlow is populated underneath TableWrapperFlow
fn place_table_caption_under_table_wrapper(&mut self,
- table_wrapper_flow: &mut Box<Flow:Share>,
+ table_wrapper_flow: &mut FlowRef,
node: &ThreadSafeLayoutNode) {
for kid in node.children() {
match kid.swap_out_construction_result() {
NoConstructionResult | ConstructionItemConstructionResult(_) => {}
FlowConstructionResult(kid_flow, _) => {
// Only kid flows with table-caption are matched here.
- assert!(kid_flow.is_table_caption());
+ assert!(kid_flow.get().is_table_caption());
table_wrapper_flow.add_new_child(kid_flow);
}
}
@@ -672,18 +642,20 @@ impl<'a> FlowConstructor<'a> {
/// Generates an anonymous table flow according to CSS 2.1 § 17.2.1, step 2.
/// If necessary, generate recursively another anonymous table flow.
fn generate_anonymous_missing_child(&mut self,
- child_flows: Vec<Box<Flow:Share>>,
- flow: &mut Box<Flow:Share>,
+ child_flows: Vec<FlowRef>,
+ flow: &mut FlowRef,
node: &ThreadSafeLayoutNode) {
- let mut anonymous_flow = flow.generate_missing_child_flow(node);
+ let mut anonymous_flow = flow.get().generate_missing_child_flow(node);
let mut consecutive_siblings = vec!();
for kid_flow in child_flows.move_iter() {
- if anonymous_flow.need_anonymous_flow(kid_flow) {
+ if anonymous_flow.get().need_anonymous_flow(kid_flow.get()) {
consecutive_siblings.push(kid_flow);
continue;
}
if !consecutive_siblings.is_empty() {
- self.generate_anonymous_missing_child(consecutive_siblings, &mut anonymous_flow, node);
+ self.generate_anonymous_missing_child(consecutive_siblings,
+ &mut anonymous_flow,
+ node);
consecutive_siblings = vec!();
}
anonymous_flow.add_new_child(kid_flow);
@@ -700,10 +672,12 @@ impl<'a> FlowConstructor<'a> {
/// other `TableCaptionFlow`s or `TableFlow`s underneath it.
fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
let fragment = Fragment::new_from_specific_info(node, TableWrapperFragment);
- let mut wrapper_flow = box TableWrapperFlow::from_node_and_fragment(node, fragment) as Box<Flow:Share>;
+ let wrapper_flow = box TableWrapperFlow::from_node_and_fragment(node, fragment);
+ let mut wrapper_flow = FlowRef::new(wrapper_flow as Box<Flow>);
let table_fragment = Fragment::new_from_specific_info(node, TableFragment);
- let table_flow = box TableFlow::from_node_and_fragment(node, table_fragment) as Box<Flow:Share>;
+ let table_flow = box TableFlow::from_node_and_fragment(node, table_fragment);
+ let table_flow = FlowRef::new(table_flow as Box<Flow>);
// We first populate the TableFlow with other flows than TableCaptionFlow.
// We then populate the TableWrapperFlow with TableCaptionFlow, and attach
@@ -726,21 +700,24 @@ impl<'a> FlowConstructor<'a> {
// The flow is done.
wrapper_flow.finish(self.layout_context);
- let is_positioned = wrapper_flow.as_block().is_positioned();
- let is_fixed_positioned = wrapper_flow.as_block().is_fixed();
- let is_absolutely_positioned = wrapper_flow.as_block().is_absolutely_positioned();
+ let is_positioned = wrapper_flow.get_mut().as_block().is_positioned();
+ let is_fixed_positioned = wrapper_flow.get_mut().as_block().is_fixed();
+ let is_absolutely_positioned = wrapper_flow.get_mut()
+ .as_block()
+ .is_absolutely_positioned();
if is_positioned {
// This is the CB for all the absolute descendants.
wrapper_flow.set_abs_descendants(abs_descendants);
+
abs_descendants = Descendants::new();
if is_fixed_positioned {
// Send itself along with the other fixed descendants.
- fixed_descendants.push(Rawlink::some(wrapper_flow));
+ fixed_descendants.push(wrapper_flow.clone());
} else if is_absolutely_positioned {
// This is now the only absolute flow in the subtree which hasn't yet
// reached its CB.
- abs_descendants.push(Rawlink::some(wrapper_flow));
+ abs_descendants.push(wrapper_flow.clone());
}
}
FlowConstructionResult(wrapper_flow, abs_descendants)
@@ -749,32 +726,33 @@ 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 {
- let flow = box TableCaptionFlow::from_node(self, node) as Box<Flow:Share>;
- self.build_flow_using_children(flow, node)
+ let flow = box TableCaptionFlow::from_node(self, node) as Box<Flow>;
+ self.build_flow_using_children(FlowRef::new(flow), node)
}
/// 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) -> ConstructionResult {
let fragment = Fragment::new_from_specific_info(node, TableRowFragment);
- let flow = box TableRowGroupFlow::from_node_and_fragment(node, fragment) as Box<Flow:Share>;
- self.build_flow_using_children(flow, node)
+ let flow = box TableRowGroupFlow::from_node_and_fragment(node, fragment);
+ let flow = flow as Box<Flow>;
+ self.build_flow_using_children(FlowRef::new(flow), node)
}
/// 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 {
let fragment = Fragment::new_from_specific_info(node, TableRowFragment);
- let flow = box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow:Share>;
- self.build_flow_using_children(flow, node)
+ let flow = box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow>;
+ self.build_flow_using_children(FlowRef::new(flow), node)
}
/// 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 {
let fragment = Fragment::new_from_specific_info(node, TableCellFragment);
- let flow = box TableCellFlow::from_node_and_fragment(node, fragment) as Box<Flow:Share>;
- self.build_flow_using_children(flow, node)
+ let flow = box TableCellFlow::from_node_and_fragment(node, fragment) as Box<Flow>;
+ self.build_flow_using_children(FlowRef::new(flow), node)
}
/// Creates a fragment for a node with `display: table-column`.
@@ -812,7 +790,8 @@ impl<'a> FlowConstructor<'a> {
let specific = TableColumnFragment(TableColumnFragmentInfo::new(node));
col_fragments.push(Fragment::new_from_specific_info(node, specific));
}
- let mut flow = box TableColGroupFlow::from_node_and_fragments(node, fragment, col_fragments) as Box<Flow:Share>;
+ let flow = box TableColGroupFlow::from_node_and_fragments(node, fragment, col_fragments);
+ let mut flow = FlowRef::new(flow as Box<Flow>);
flow.finish(self.layout_context);
FlowConstructionResult(flow, Descendants::new())
@@ -860,8 +839,7 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
// results of children.
(display::none, _, _) => {
for child in node.children() {
- let mut old_result = child.swap_out_construction_result();
- old_result.destroy()
+ drop(child.swap_out_construction_result())
}
}
@@ -950,9 +928,6 @@ trait NodeUtils {
/// Returns true if this node doesn't render its kids and false otherwise.
fn is_replaced_content(&self) -> bool;
- /// Returns true if this node is ignorable whitespace.
- fn is_ignorable_whitespace(&self) -> bool;
-
/// Sets the construction result of a flow.
fn set_flow_construction_result(&self, result: ConstructionResult);
@@ -977,31 +952,6 @@ impl<'ln> NodeUtils for ThreadSafeLayoutNode<'ln> {
}
}
- fn is_ignorable_whitespace(&self) -> bool {
- match self.type_id() {
- Some(TextNodeTypeId) => {
- unsafe {
- let text: JS<Text> = self.get_jsmanaged().transmute_copy();
- if !is_whitespace((*text.unsafe_get()).characterdata.data) {
- return false
- }
-
- // NB: See the rules for `white-space` here:
- //
- // http://www.w3.org/TR/CSS21/text.html#propdef-white-space
- //
- // If you implement other values for this property, you will almost certainly
- // want to update this check.
- match self.style().get_inheritedtext().white_space {
- white_space::normal => true,
- _ => false,
- }
- }
- }
- _ => false
- }
- }
-
#[inline(always)]
fn set_flow_construction_result(&self, result: ConstructionResult) {
let mut layout_data_ref = self.mutate_layout_data();
@@ -1078,3 +1028,49 @@ impl<'ln> ObjectElement for ThreadSafeLayoutNode<'ln> {
}
}
}
+
+pub trait FlowConstructionUtils {
+ /// Adds a new flow as a child of this flow. Removes the flow from the given leaf set if
+ /// it's present.
+ fn add_new_child(&mut self, new_child: FlowRef);
+
+ /// Finishes a flow. Once a flow is finished, no more child flows or boxes may be added to it.
+ /// This will normally run the bubble-widths (minimum and preferred -- i.e. intrinsic -- width)
+ /// calculation, unless the global `bubble_widths_separately` flag is on.
+ ///
+ /// All flows must be finished at some point, or they will not have their intrinsic widths
+ /// properly computed. (This is not, however, a memory safety problem.)
+ fn finish(&mut self, context: &mut LayoutContext);
+}
+
+impl FlowConstructionUtils for FlowRef {
+ /// Adds a new flow as a child of this flow. Fails if this flow is marked as a leaf.
+ ///
+ /// This must not be public because only the layout constructor can do this.
+ fn add_new_child(&mut self, mut new_child: FlowRef) {
+ {
+ let kid_base = flow::mut_base(new_child.get_mut());
+ kid_base.parallel.parent = parallel::mut_owned_flow_to_unsafe_flow(self);
+ }
+
+ let base = flow::mut_base(self.get_mut());
+ base.children.push_back(new_child);
+ let _ = base.parallel.children_count.fetch_add(1, Relaxed);
+ let _ = base.parallel.children_and_absolute_descendant_count.fetch_add(1, Relaxed);
+ }
+
+ /// Finishes a flow. Once a flow is finished, no more child flows or fragments may be added to
+ /// it. This will normally run the bubble-widths (minimum and preferred -- i.e. intrinsic --
+ /// width) calculation, unless the global `bubble_widths_separately` flag is on.
+ ///
+ /// All flows must be finished at some point, or they will not have their intrinsic widths
+ /// properly computed. (This is not, however, a memory safety problem.)
+ ///
+ /// This must not be public because only the layout constructor can do this.
+ fn finish(&mut self, context: &mut LayoutContext) {
+ if !context.opts.bubble_widths_separately {
+ self.get_mut().bubble_widths(context)
+ }
+ }
+}
+
diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs
index d50f19272d4..4cf331473bb 100644
--- a/src/components/main/layout/flow.rs
+++ b/src/components/main/layout/flow.rs
@@ -29,13 +29,13 @@ use css::node_style::StyledNode;
use layout::block::BlockFlow;
use layout::context::LayoutContext;
use layout::floats::Floats;
-use layout::flow_list::{FlowList, Link, Rawlink, FlowListIterator, MutFlowListIterator};
+use layout::flow_list::{FlowList, Link, FlowListIterator, MutFlowListIterator};
+use layout::flow_ref::FlowRef;
use layout::fragment::{Fragment, TableRowFragment, TableCellFragment};
use layout::incremental::RestyleDamage;
use layout::inline::InlineFlow;
use layout::model::{CollapsibleMargins, IntrinsicWidths, MarginCollapseInfo};
use layout::parallel::FlowParallelInfo;
-use layout::parallel;
use layout::table_wrapper::TableWrapperFlow;
use layout::table::TableFlow;
use layout::table_colgroup::TableColGroupFlow;
@@ -45,7 +45,6 @@ use layout::table_caption::TableCaptionFlow;
use layout::table_cell::TableCellFlow;
use layout::wrapper::ThreadSafeLayoutNode;
-use collections::Deque;
use collections::dlist::DList;
use geom::point::Point2D;
use geom::rect::Rect;
@@ -58,7 +57,7 @@ use std::cast;
use std::fmt;
use std::iter::Zip;
use std::num::Zero;
-use std::sync::atomics::Relaxed;
+use std::sync::atomics::{AtomicUint, Relaxed, SeqCst};
use std::slice::MutItems;
use style::computed_values::{clear, position, text_align};
@@ -66,7 +65,7 @@ use style::computed_values::{clear, position, text_align};
///
/// Note that virtual methods have a cost; we should not overuse them in Servo. Consider adding
/// methods to `ImmutableFlowUtils` or `MutableFlowUtils` before adding more methods here.
-pub trait Flow: fmt::Show + ToStr {
+pub trait Flow: fmt::Show + ToStr + Share {
// RTTI
//
// TODO(pcwalton): Use Rust's RTTI, once that works.
@@ -293,11 +292,6 @@ pub fn mut_base<'a>(this: &'a mut Flow) -> &'a mut BaseFlow {
}
}
-/// Returns the last child of this flow.
-pub fn last_child<'a>(flow: &'a mut Flow) -> Option<&'a mut Flow> {
- mut_base(flow).children.back_mut()
-}
-
/// Iterates over the children of this flow.
pub fn child_iter<'a>(flow: &'a mut Flow) -> MutFlowListIterator<'a> {
mut_base(flow).children.mut_iter()
@@ -337,7 +331,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) -> Box<Flow:Share>;
+ fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> FlowRef;
/// Returns true if this flow has no children.
fn is_leaf(self) -> bool;
@@ -372,42 +366,18 @@ pub trait MutableFlowUtils {
// Mutators
- /// Invokes a closure with the first child of this flow.
- fn with_first_child<R>(self, f: |Option<&mut Flow>| -> R) -> R;
-
- /// Invokes a closure with the last child of this flow.
- fn with_last_child<R>(self, f: |Option<&mut Flow>| -> R) -> R;
-
/// Computes the overflow region for this flow.
fn store_overflow(self, _: &mut LayoutContext);
/// Builds the display lists for this flow.
fn build_display_list(self, layout_context: &LayoutContext);
-
- /// Destroys the flow.
- fn destroy(self);
}
pub trait MutableOwnedFlowUtils {
- /// Adds a new flow as a child of this flow. Removes the flow from the given leaf set if
- /// it's present.
- fn add_new_child(&mut self, new_child: Box<Flow:Share>);
-
- /// Finishes a flow. Once a flow is finished, no more child flows or boxes may be added to it.
- /// This will normally run the bubble-widths (minimum and preferred -- i.e. intrinsic -- width)
- /// calculation, unless the global `bubble_widths_separately` flag is on.
- ///
- /// All flows must be finished at some point, or they will not have their intrinsic widths
- /// properly computed. (This is not, however, a memory safety problem.)
- fn finish(&mut self, context: &mut LayoutContext);
-
/// Set absolute descendants for this flow.
///
/// Set this flow as the Containing Block for all the absolute descendants.
fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants);
-
- /// Destroys the flow.
- fn destroy(&mut self);
}
#[deriving(Eq, Show)]
@@ -550,10 +520,11 @@ impl FlowFlags {
/// The Descendants of a flow.
///
/// Also, details about their position wrt this flow.
-/// FIXME: This should use @pcwalton's reference counting scheme (Coming Soon).
pub struct Descendants {
- /// Links to every Descendant.
- pub descendant_links: Vec<Rawlink>,
+ /// Links to every descendant. This must be private because it is unsafe to leak `FlowRef`s to
+ /// layout.
+ descendant_links: Vec<FlowRef>,
+
/// Static y offsets of all descendants from the start of this flow box.
pub static_y_offsets: Vec<Au>,
}
@@ -570,7 +541,7 @@ impl Descendants {
self.descendant_links.len()
}
- pub fn push(&mut self, given_descendant: Rawlink) {
+ pub fn push(&mut self, given_descendant: FlowRef) {
self.descendant_links.push(given_descendant);
}
@@ -585,21 +556,41 @@ impl Descendants {
/// Return an iterator over the descendant flows.
pub fn iter<'a>(&'a mut self) -> DescendantIter<'a> {
- self.descendant_links.mut_slice_from(0).mut_iter()
+ DescendantIter {
+ iter: self.descendant_links.mut_slice_from(0).mut_iter(),
+ }
}
/// Return an iterator over (descendant, static y offset).
pub fn iter_with_offset<'a>(&'a mut self) -> DescendantOffsetIter<'a> {
- self.descendant_links.mut_slice_from(0).mut_iter().zip(
- self.static_y_offsets.mut_slice_from(0).mut_iter())
+ let descendant_iter = DescendantIter {
+ iter: self.descendant_links.mut_slice_from(0).mut_iter(),
+ };
+ descendant_iter.zip(self.static_y_offsets.mut_slice_from(0).mut_iter())
}
}
pub type AbsDescendants = Descendants;
-pub type DescendantIter<'a> = MutItems<'a, Rawlink>;
+pub struct DescendantIter<'a> {
+ iter: MutItems<'a, FlowRef>,
+}
+
+impl<'a> Iterator<&'a mut Flow> for DescendantIter<'a> {
+ fn next(&mut self) -> Option<&'a mut Flow> {
+ match self.iter.next() {
+ None => None,
+ Some(ref mut flow) => {
+ unsafe {
+ let result: &'a mut Flow = cast::transmute(flow.get_mut());
+ Some(result)
+ }
+ }
+ }
+ }
+}
-pub type DescendantOffsetIter<'a> = Zip<MutItems<'a, Rawlink>, MutItems<'a, Au>>;
+pub type DescendantOffsetIter<'a> = Zip<DescendantIter<'a>, MutItems<'a, Au>>;
/// Information needed to compute absolute (i.e. viewport-relative) flow positions (not to be
/// confused with absolutely-positioned flows).
@@ -628,12 +619,17 @@ impl AbsolutePositionInfo {
/// Data common to all flows.
pub struct BaseFlow {
+ /// NB: Must be the first element.
+ ///
+ /// The necessity of this will disappear once we have dynamically-sized types.
+ ref_count: AtomicUint,
+
pub restyle_damage: RestyleDamage,
/// The children of this flow.
pub children: FlowList,
pub next_sibling: Link,
- pub prev_sibling: Rawlink,
+ pub prev_sibling: Link,
/* layout computations */
// TODO: min/pref and position are used during disjoint phases of
@@ -694,12 +690,6 @@ pub struct BaseFlow {
/// Any layers that we're bubbling up, in a linked list.
pub layers: DList<RenderLayer>,
- /// Whether this flow has been destroyed.
- ///
- /// TODO(pcwalton): Pack this into the flags? Need to be careful because manipulation of this
- /// flag can have memory safety implications.
- destroyed: bool,
-
/// Various flags for flows, tightly packed to save space.
pub flags: FlowFlags,
}
@@ -707,8 +697,8 @@ pub struct BaseFlow {
#[unsafe_destructor]
impl Drop for BaseFlow {
fn drop(&mut self) {
- if !self.destroyed {
- fail!("Flow destroyed by going out of scope—this is unsafe! Use `destroy()` instead!")
+ if self.ref_count.load(SeqCst) != 0 {
+ fail!("Flow destroyed before its ref count hit zero—this is unsafe!")
}
}
}
@@ -717,11 +707,13 @@ impl BaseFlow {
#[inline]
pub fn new(node: ThreadSafeLayoutNode) -> BaseFlow {
BaseFlow {
+ ref_count: AtomicUint::new(1),
+
restyle_damage: node.restyle_damage(),
children: FlowList::new(),
next_sibling: None,
- prev_sibling: Rawlink::none(),
+ prev_sibling: None,
intrinsic_widths: IntrinsicWidths::new(),
position: Rect::zero(),
@@ -740,8 +732,6 @@ impl BaseFlow {
layers: DList::new(),
absolute_position_info: AbsolutePositionInfo::new(),
- destroyed: false,
-
flags: FlowFlags::new(),
}
}
@@ -749,6 +739,10 @@ impl BaseFlow {
pub fn child_iter<'a>(&'a mut self) -> MutFlowListIterator<'a> {
self.children.mut_iter()
}
+
+ pub unsafe fn ref_count<'a>(&'a self) -> &'a AtomicUint {
+ &self.ref_count
+ }
}
impl<'a> ImmutableFlowUtils for &'a Flow {
@@ -841,20 +835,21 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
}
/// Generates missing child flow of this flow.
- fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> Box<Flow:Share> {
- match self.class() {
+ fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> FlowRef {
+ let flow = match self.class() {
TableFlowClass | TableRowGroupFlowClass => {
let fragment = Fragment::new_anonymous_table_fragment(node, TableRowFragment);
- box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow:Share>
+ box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow>
},
TableRowFlowClass => {
let fragment = Fragment::new_anonymous_table_fragment(node, TableCellFragment);
- box TableCellFlow::from_node_and_fragment(node, fragment) as Box<Flow:Share>
+ box TableCellFlow::from_node_and_fragment(node, fragment) as Box<Flow>
},
_ => {
fail!("no need to generate a missing child")
}
- }
+ };
+ FlowRef::new(flow)
}
/// Returns true if this flow has no children.
@@ -957,16 +952,6 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
traversal.process(self)
}
- /// Invokes a closure with the first child of this flow.
- fn with_first_child<R>(self, f: |Option<&mut Flow>| -> R) -> R {
- f(mut_base(self).children.front_mut())
- }
-
- /// Invokes a closure with the last child of this flow.
- fn with_last_child<R>(self, f: |Option<&mut Flow>| -> R) -> R {
- f(mut_base(self).children.back_mut())
- }
-
/// Calculate and set overflow for current flow.
///
/// CSS Section 11.1
@@ -994,14 +979,9 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
// FIXME(#2004, pcwalton): This is wrong for `position: fixed`.
for descendant_link in mut_base(self).abs_descendants.iter() {
- match descendant_link.resolve() {
- Some(flow) => {
- let mut kid_overflow = base(flow).overflow;
- kid_overflow = kid_overflow.translate(&my_position.origin);
- overflow = overflow.union(&kid_overflow)
- }
- None => fail!("empty Rawlink to a descendant")
- }
+ let mut kid_overflow = base(descendant_link).overflow;
+ kid_overflow = kid_overflow.translate(&my_position.origin);
+ overflow = overflow.union(&kid_overflow)
}
}
mut_base(self).overflow = overflow;
@@ -1040,52 +1020,20 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
}
}
}
-
- /// Destroys the flow.
- fn destroy(self) {
- for kid in child_iter(self) {
- kid.destroy()
- }
-
- mut_base(self).destroyed = true
- }
}
-impl MutableOwnedFlowUtils for Box<Flow:Share> {
- /// Adds a new flow as a child of this flow. Fails if this flow is marked as a leaf.
- fn add_new_child(&mut self, mut new_child: Box<Flow:Share>) {
- {
- let kid_base = mut_base(new_child);
- kid_base.parallel.parent = parallel::mut_owned_flow_to_unsafe_flow(self);
- }
-
- let base = mut_base(*self);
- base.children.push_back(new_child);
- let _ = base.parallel.children_count.fetch_add(1, Relaxed);
- let _ = base.parallel.children_and_absolute_descendant_count.fetch_add(1, Relaxed);
- }
-
- /// Finishes a flow. Once a flow is finished, no more child flows or fragments may be added to it.
- /// This will normally run the bubble-widths (minimum and preferred -- i.e. intrinsic -- width)
- /// calculation, unless the global `bubble_widths_separately` flag is on.
- ///
- /// All flows must be finished at some point, or they will not have their intrinsic widths
- /// properly computed. (This is not, however, a memory safety problem.)
- fn finish(&mut self, context: &mut LayoutContext) {
- if !context.opts.bubble_widths_separately {
- self.bubble_widths(context)
- }
- }
-
+impl MutableOwnedFlowUtils for FlowRef {
/// Set absolute descendants for this flow.
///
/// Set yourself as the Containing Block for all the absolute descendants.
///
- /// Assumption: This is called in a bottom-up traversal, so that nothing
- /// else is accessing the descendant flows.
+ /// This is called during flow construction, so nothing else can be accessing the descendant
+ /// flows. This is enforced by the fact that we have a mutable `FlowRef`, which only flow
+ /// construction is allowed to possess.
fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants) {
- let self_link = Rawlink::some(*self);
- let block = self.as_block();
+ let this = self.clone();
+
+ let block = self.get_mut().as_block();
block.base.abs_descendants = abs_descendants;
block.base
.parallel
@@ -1093,21 +1041,10 @@ impl MutableOwnedFlowUtils for Box<Flow:Share> {
.fetch_add(block.base.abs_descendants.len() as int, Relaxed);
for descendant_link in block.base.abs_descendants.iter() {
- match descendant_link.resolve() {
- Some(flow) => {
- let base = mut_base(flow);
- base.absolute_cb.set(self_link.clone());
- }
- None => fail!("empty Rawlink to a descendant")
- }
+ let base = mut_base(descendant_link);
+ base.absolute_cb.set(this.clone());
}
}
-
- /// Destroys the flow.
- fn destroy(&mut self) {
- let self_borrowed: &mut Flow = *self;
- self_borrowed.destroy();
- }
}
/// A link to a flow's containing block.
@@ -1116,29 +1053,34 @@ impl MutableOwnedFlowUtils for Box<Flow:Share> {
/// tree. A pointer up the tree is unsafe during layout because it can be used to access a node
/// with an immutable reference while that same node is being laid out, causing possible iterator
/// invalidation and use-after-free.
+///
+/// FIXME(pcwalton): I think this would be better with a borrow flag instead of `unsafe`.
pub struct ContainingBlockLink {
- /// TODO(pcwalton): Reference count.
- link: Rawlink,
+ /// The pointer up to the containing block.
+ link: Option<FlowRef>,
}
impl ContainingBlockLink {
fn new() -> ContainingBlockLink {
ContainingBlockLink {
- link: Rawlink::none(),
+ link: None,
}
}
- fn set(&mut self, link: Rawlink) {
- self.link = link
+ fn set(&mut self, link: FlowRef) {
+ self.link = Some(link)
}
- pub unsafe fn resolve(&mut self) -> Option<&mut Flow> {
- self.link.resolve()
+ pub unsafe fn get<'a>(&'a mut self) -> &'a mut Option<FlowRef> {
+ &mut self.link
}
#[inline]
pub fn generated_containing_block_rect(&mut self) -> Rect<Au> {
- self.link.resolve().unwrap().generated_containing_block_rect()
+ match self.link {
+ None => fail!("haven't done it"),
+ Some(ref mut link) => link.get_mut().generated_containing_block_rect(),
+ }
}
}
diff --git a/src/components/main/layout/flow_list.rs b/src/components/main/layout/flow_list.rs
index d812db5b740..e0646433e71 100644
--- a/src/components/main/layout/flow_list.rs
+++ b/src/components/main/layout/flow_list.rs
@@ -5,13 +5,14 @@
//! A variant of `DList` specialized to store `Flow`s without an extra
//! indirection.
+use layout::flow::{Flow, base, mut_base};
+use layout::flow_ref::FlowRef;
+
use std::cast;
use std::mem;
use std::ptr;
-use layout::flow::{Flow, base, mut_base};
-
-pub type Link = Option<Box<Flow:Share>>;
+pub type Link = Option<FlowRef>;
#[deriving(Clone)]
pub struct Rawlink {
@@ -26,7 +27,7 @@ pub struct Rawlink {
pub struct FlowList {
length: uint,
list_head: Link,
- list_tail: Rawlink,
+ list_tail: Link,
}
/// Double-ended FlowList iterator
@@ -54,42 +55,30 @@ impl Rawlink {
}
/// Like Option::Some for Rawlink
- pub fn some(n: &mut Flow) -> Rawlink {
+ pub fn some(n: &Flow) -> Rawlink {
unsafe { cast::transmute(n) }
}
- /// Convert the `Rawlink` into an Option value
- fn resolve_immut(&self) -> Option<&Flow> {
- if self.obj.is_null() {
- None
- } else {
- let me: &Flow = unsafe { cast::transmute_copy(self) };
- Some(me)
+ fn from_optional_flow_ref(flow_ref: &Option<FlowRef>) -> Rawlink {
+ match *flow_ref {
+ None => Rawlink::none(),
+ Some(ref flow_ref) => Rawlink::some(flow_ref.get()),
}
}
- pub fn resolve(&mut self) -> Option<&mut Flow> {
+ pub unsafe fn resolve_mut(&self) -> Option<&mut Flow> {
if self.obj.is_null() {
None
} else {
- let me: &mut Flow = unsafe { cast::transmute_copy(self) };
+ let me: &mut Flow = cast::transmute_copy(self);
Some(me)
}
}
-
- fn is_none(&self) -> bool {
- self.obj.is_null()
- }
-
- unsafe fn get<'a>(&'a mut self) -> &'a mut Flow {
- assert!(self.obj.is_not_null());
- cast::transmute_copy(self)
- }
}
/// Set the .prev field on `next`, then return `Some(next)`
-fn link_with_prev(mut next: Box<Flow:Share>, prev: Rawlink) -> Link {
- mut_base(next).prev_sibling = prev;
+unsafe fn link_with_prev(mut next: FlowRef, prev: Option<FlowRef>) -> Link {
+ mut_base(next.get_mut()).prev_sibling = prev;
Some(next)
}
@@ -112,33 +101,34 @@ impl FlowList {
/// Provide a reference to the front element, or None if the list is empty
#[inline]
pub fn front<'a>(&'a self) -> Option<&'a Flow> {
- self.list_head.as_ref().map(|head| { let x: &Flow = *head; x })
+ self.list_head.as_ref().map(|head| head.get())
}
/// Provide a mutable reference to the front element, or None if the list is empty
#[inline]
- pub fn front_mut<'a>(&'a mut self) -> Option<&'a mut Flow> {
- self.list_head.as_mut().map(|head| { let x: &mut Flow = *head; x })
+ pub unsafe fn front_mut<'a>(&'a mut self) -> Option<&'a mut Flow> {
+ self.list_head.as_mut().map(|head| head.get_mut())
}
/// Provide a reference to the back element, or None if the list is empty
#[inline]
pub fn back<'a>(&'a self) -> Option<&'a Flow> {
- let tmp = self.list_tail.resolve_immut();
- tmp.as_ref().map(|tail| { let x: &Flow = *tail; x })
+ match self.list_tail {
+ None => None,
+ Some(ref list_tail) => Some(list_tail.get())
+ }
}
/// Provide a mutable reference to the back element, or None if the list is empty
#[inline]
- pub fn back_mut<'a>(&'a mut self) -> Option<&'a mut Flow> {
+ pub unsafe fn back_mut<'a>(&'a mut self) -> Option<&'a mut Flow> {
// Can't use map() due to error:
// lifetime of `tail` is too short to guarantee its contents can be safely reborrowed
- let tmp = self.list_tail.resolve();
- match tmp {
+ match self.list_tail {
None => None,
- Some(tail) => {
- let x: &mut Flow = tail;
- Some(x)
+ Some(ref mut tail) => {
+ let x: &mut Flow = tail.get_mut();
+ Some(cast::transmute_copy(&x))
}
}
}
@@ -146,31 +136,35 @@ impl FlowList {
/// Add an element first in the list
///
/// O(1)
- pub fn push_front(&mut self, mut new_head: Box<Flow:Share>) {
- match self.list_head {
- None => {
- self.list_tail = Rawlink::some(new_head);
- self.list_head = link_with_prev(new_head, Rawlink::none());
- }
- Some(ref mut head) => {
- mut_base(new_head).prev_sibling = Rawlink::none();
- mut_base(*head).prev_sibling = Rawlink::some(new_head);
- mem::swap(head, &mut new_head);
- mut_base(*head).next_sibling = Some(new_head);
+ pub fn push_front(&mut self, mut new_head: FlowRef) {
+ unsafe {
+ match self.list_head {
+ None => {
+ self.list_tail = Some(new_head.clone());
+ self.list_head = link_with_prev(new_head, None);
+ }
+ Some(ref mut head) => {
+ mut_base(new_head.get_mut()).prev_sibling = None;
+ mut_base(head.get_mut()).prev_sibling = Some(new_head.clone());
+ mem::swap(head, &mut new_head);
+ mut_base(head.get_mut()).next_sibling = Some(new_head);
+ }
}
+ self.length += 1;
}
- self.length += 1;
}
/// Remove the first element and return it, or None if the list is empty
///
/// O(1)
- pub fn pop_front(&mut self) -> Option<Box<Flow:Share>> {
+ pub fn pop_front(&mut self) -> Option<FlowRef> {
self.list_head.take().map(|mut front_node| {
self.length -= 1;
- match mut_base(front_node).next_sibling.take() {
- Some(node) => self.list_head = link_with_prev(node, Rawlink::none()),
- None => self.list_tail = Rawlink::none()
+ unsafe {
+ match mut_base(front_node.get_mut()).next_sibling.take() {
+ Some(node) => self.list_head = link_with_prev(node, None),
+ None => self.list_tail = None,
+ }
}
front_node
})
@@ -179,34 +173,19 @@ impl FlowList {
/// Add an element last in the list
///
/// O(1)
- pub fn push_back(&mut self, mut new_tail: Box<Flow:Share>) {
+ pub fn push_back(&mut self, new_tail: FlowRef) {
if self.list_tail.is_none() {
return self.push_front(new_tail);
- } else {
- let mut old_tail = self.list_tail;
- self.list_tail = Rawlink::some(new_tail);
- let tail = unsafe { old_tail.get() };
- mut_base(tail).next_sibling = link_with_prev(new_tail, Rawlink::some(tail));
}
- self.length += 1;
- }
-
- /// Remove the last element and return it, or None if the list is empty
- ///
- /// O(1)
- pub fn pop_back(&mut self) -> Option<Box<Flow:Share>> {
- if self.list_tail.is_none() {
- None
- } else {
- self.length -= 1;
- self.list_tail = base(unsafe { self.list_tail.get() }).prev_sibling;
- if self.list_tail.is_none() {
- self.list_head.take()
- } else {
- mut_base(unsafe { self.list_tail.get() }).next_sibling.take()
- }
+ let old_tail = self.list_tail.clone();
+ self.list_tail = Some(new_tail.clone());
+ let mut tail = (*old_tail.as_ref().unwrap()).clone();
+ let tail_clone = Some(tail.clone());
+ unsafe {
+ mut_base(tail.get_mut()).next_sibling = link_with_prev(new_tail, tail_clone);
}
+ self.length += 1;
}
/// Create an empty list
@@ -214,7 +193,7 @@ impl FlowList {
pub fn new() -> FlowList {
FlowList {
list_head: None,
- list_tail: Rawlink::none(),
+ list_tail: None,
length: 0,
}
}
@@ -225,7 +204,7 @@ impl FlowList {
FlowListIterator {
nelem: self.len(),
head: &self.list_head,
- tail: self.list_tail
+ tail: Rawlink::from_optional_flow_ref(&self.list_tail)
}
}
@@ -233,13 +212,13 @@ impl FlowList {
#[inline]
pub fn mut_iter<'a>(&'a mut self) -> MutFlowListIterator<'a> {
let head_raw = match self.list_head {
- Some(ref mut h) => Rawlink::some(*h),
+ Some(ref mut h) => Rawlink::some(h.get()),
None => Rawlink::none(),
};
MutFlowListIterator {
nelem: self.len(),
head: head_raw,
- tail: self.list_tail,
+ tail: Rawlink::from_optional_flow_ref(&self.list_tail),
list: self
}
}
@@ -251,20 +230,20 @@ impl Drop for FlowList {
// Dissolve the list in backwards direction
// Just dropping the list_head can lead to stack exhaustion
// when length is >> 1_000_000
- let mut tail = self.list_tail;
+ let mut tail = mem::replace(&mut self.list_tail, None);
loop {
- match tail.resolve() {
+ let new_tail = match tail {
None => break,
- Some(prev) => {
- let prev_base = mut_base(prev);
+ Some(ref mut prev) => {
+ let prev_base = mut_base(prev.get_mut());
prev_base.next_sibling.take();
- tail = prev_base.prev_sibling;
+ prev_base.prev_sibling.clone()
}
- }
+ };
+ tail = new_tail
}
self.length = 0;
self.list_head = None;
- self.list_tail = Rawlink::none();
}
}
@@ -275,10 +254,10 @@ impl<'a> Iterator<&'a Flow> for FlowListIterator<'a> {
return None;
}
self.head.as_ref().map(|head| {
- let head_base = base(*head);
+ let head_base = base(head.get());
self.nelem -= 1;
self.head = &head_base.next_sibling;
- let ret: &Flow = *head;
+ let ret: &Flow = head.get();
ret
})
}
@@ -295,17 +274,19 @@ impl<'a> Iterator<&'a mut Flow> for MutFlowListIterator<'a> {
if self.nelem == 0 {
return None;
}
- self.head.resolve().map(|next| {
- self.nelem -= 1;
- self.head = match mut_base(next).next_sibling {
- Some(ref mut node) => {
- let x: &mut Flow = *node;
- Rawlink::some(x)
- }
- None => Rawlink::none(),
- };
- next
- })
+ unsafe {
+ self.head.resolve_mut().map(|next| {
+ self.nelem -= 1;
+ self.head = match mut_base(next).next_sibling {
+ Some(ref mut node) => {
+ let x: &mut Flow = node.get_mut();
+ Rawlink::some(x)
+ }
+ None => Rawlink::none(),
+ };
+ next
+ })
+ }
}
#[inline]
diff --git a/src/components/main/layout/flow_ref.rs b/src/components/main/layout/flow_ref.rs
new file mode 100644
index 00000000000..8b10d5a41f6
--- /dev/null
+++ b/src/components/main/layout/flow_ref.rs
@@ -0,0 +1,79 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/// Reference-counted pointers to flows.
+///
+/// Eventually, with dynamically sized types in Rust, much of this code will be superfluous.
+
+use layout::flow::Flow;
+use layout::flow;
+
+use std::cast;
+use std::mem;
+use std::ptr;
+use std::sync::atomics::SeqCst;
+
+#[unsafe_no_drop_flag]
+pub struct FlowRef {
+ vtable: *u8,
+ ptr: *u8,
+}
+
+impl FlowRef {
+ pub fn new(mut flow: Box<Flow>) -> FlowRef {
+ unsafe {
+ let result = {
+ let flow_ref: &mut Flow = flow;
+ cast::transmute(flow_ref)
+ };
+ cast::forget(flow);
+ result
+ }
+ }
+
+ pub fn get<'a>(&'a self) -> &'a Flow {
+ unsafe {
+ cast::transmute_copy(self)
+ }
+ }
+
+ pub fn get_mut<'a>(&'a mut self) -> &'a mut Flow {
+ unsafe {
+ cast::transmute_copy(self)
+ }
+ }
+}
+
+impl Drop for FlowRef {
+ fn drop(&mut self) {
+ unsafe {
+ if self.vtable == ptr::null() {
+ return
+ }
+ if flow::base(self.get()).ref_count().fetch_sub(1, SeqCst) > 1 {
+ return
+ }
+ let flow_ref: FlowRef = mem::replace(self, FlowRef {
+ vtable: ptr::null(),
+ ptr: ptr::null(),
+ });
+ drop(cast::transmute::<FlowRef,Box<Flow>>(flow_ref));
+ self.vtable = ptr::null();
+ self.ptr = ptr::null();
+ }
+ }
+}
+
+impl Clone for FlowRef {
+ fn clone(&self) -> FlowRef {
+ unsafe {
+ drop(flow::base(self.get()).ref_count().fetch_add(1, SeqCst));
+ FlowRef {
+ vtable: self.vtable,
+ ptr: self.ptr,
+ }
+ }
+ }
+}
+
diff --git a/src/components/main/layout/fragment.rs b/src/components/main/layout/fragment.rs
index a64d7d50290..713daf72368 100644
--- a/src/components/main/layout/fragment.rs
+++ b/src/components/main/layout/fragment.rs
@@ -4,6 +4,8 @@
//! The `Box` type, which represents the leaves of the layout tree.
+#![deny(unsafe_block)]
+
use css::node_style::StyledNode;
use layout::construct::FlowConstructor;
use layout::context::LayoutContext;
@@ -38,7 +40,6 @@ use servo_util::range::*;
use servo_util::namespace;
use servo_util::smallvec::SmallVec;
use servo_util::str::is_whitespace;
-use std::cast;
use std::fmt;
use std::from_str::FromStr;
use std::iter::AdditiveIterator;
@@ -381,9 +382,7 @@ impl Fragment {
/// Returns a debug ID of this fragment. This ID should not be considered stable across multiple
/// layouts or fragment manipulations.
pub fn debug_id(&self) -> uint {
- unsafe {
- cast::transmute(self)
- }
+ self as *Fragment as uint
}
/// Transforms this fragment into another fragment of the given type, with the given size, preserving all
diff --git a/src/components/main/layout/inline.rs b/src/components/main/layout/inline.rs
index 01d544c3ec0..3318aa62ab2 100644
--- a/src/components/main/layout/inline.rs
+++ b/src/components/main/layout/inline.rs
@@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#![deny(unsafe_block)]
+
use css::node_style::StyledNode;
use layout::context::LayoutContext;
use layout::floats::{FloatLeft, Floats, PlacementInfo};
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs
index 08252df5417..6cede7b1d9c 100644
--- a/src/components/main/layout/layout_task.rs
+++ b/src/components/main/layout/layout_task.rs
@@ -14,6 +14,7 @@ use layout::context::LayoutContext;
use layout::flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
use layout::flow::{PreorderFlowTraversal, PostorderFlowTraversal};
use layout::flow;
+use layout::flow_ref::FlowRef;
use layout::incremental::RestyleDamage;
use layout::parallel::PaddedUnsafeFlow;
use layout::parallel;
@@ -246,7 +247,7 @@ impl<'a> BuildDisplayListTraversal<'a> {
}
for absolute_descendant_link in flow::mut_base(flow).abs_descendants.iter() {
- self.process(absolute_descendant_link.resolve().unwrap())
+ self.process(absolute_descendant_link)
}
flow.build_display_list(self.layout_context)
@@ -455,7 +456,7 @@ impl LayoutTask {
}
/// Retrieves the flow tree root from the root node.
- fn get_layout_root(&self, node: LayoutNode) -> Box<Flow:Share> {
+ fn get_layout_root(&self, node: LayoutNode) -> FlowRef {
let mut layout_data_ref = node.mutate_layout_data();
let result = match &mut *layout_data_ref {
&Some(ref mut layout_data) => {
@@ -475,7 +476,7 @@ impl LayoutTask {
}
_ => fail!("Flow construction didn't result in a flow at the root of the tree!"),
};
- flow.mark_as_root();
+ flow.get_mut().mark_as_root();
flow
}
@@ -521,13 +522,13 @@ impl LayoutTask {
/// benchmarked against those two. It is marked `#[inline(never)]` to aid profiling.
#[inline(never)]
fn solve_constraints_parallel(&mut self,
- layout_root: &mut Box<Flow:Share>,
+ layout_root: &mut FlowRef,
layout_context: &mut LayoutContext) {
if layout_context.opts.bubble_widths_separately {
let mut traversal = BubbleWidthsTraversal {
layout_context: layout_context,
};
- layout_root.traverse_postorder(&mut traversal);
+ layout_root.get_mut().traverse_postorder(&mut traversal);
}
match self.parallel_traversal {
@@ -547,13 +548,13 @@ impl LayoutTask {
/// This is only on in debug builds.
#[inline(never)]
#[cfg(debug)]
- fn verify_flow_tree(&mut self, layout_root: &mut Box<Flow:Share>) {
+ fn verify_flow_tree(&mut self, layout_root: &mut FlowRef) {
let mut traversal = FlowTreeVerificationTraversal;
layout_root.traverse_preorder(&mut traversal);
}
#[cfg(not(debug))]
- fn verify_flow_tree(&mut self, _: &mut Box<Flow:Share>) {
+ fn verify_flow_tree(&mut self, _: &mut FlowRef) {
}
/// The high-level routine that performs layout tasks.
@@ -634,10 +635,10 @@ impl LayoutTask {
// Propagate damage.
profile(time::LayoutDamagePropagateCategory, self.profiler_chan.clone(), || {
- layout_root.traverse_preorder(&mut PropagateDamageTraversal {
+ layout_root.get_mut().traverse_preorder(&mut PropagateDamageTraversal {
all_style_damage: all_style_damage
});
- layout_root.traverse_postorder(&mut ComputeDamageTraversal.clone());
+ layout_root.get_mut().traverse_postorder(&mut ComputeDamageTraversal.clone());
});
// Perform the primary layout passes over the flow tree to compute the locations of all
@@ -646,7 +647,7 @@ impl LayoutTask {
match self.parallel_traversal {
None => {
// Sequential mode.
- self.solve_constraints(layout_root, &mut layout_ctx)
+ self.solve_constraints(layout_root.get_mut(), &mut layout_ctx)
}
Some(_) => {
// Parallel mode.
@@ -658,14 +659,14 @@ impl LayoutTask {
// Build the display list if necessary, and send it to the renderer.
if data.goal == ReflowForDisplay {
profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone(), || {
- layout_ctx.dirty = flow::base(layout_root).position.clone();
+ layout_ctx.dirty = flow::base(layout_root.get()).position.clone();
match self.parallel_traversal {
None => {
let mut traversal = BuildDisplayListTraversal {
layout_context: &layout_ctx,
};
- traversal.process(layout_root);
+ traversal.process(layout_root.get_mut());
}
Some(ref mut traversal) => {
parallel::build_display_list_for_subtree(&mut layout_root,
@@ -675,8 +676,9 @@ impl LayoutTask {
}
}
- let root_display_list = mem::replace(&mut flow::mut_base(layout_root).display_list,
- DisplayList::new());
+ let root_display_list =
+ mem::replace(&mut flow::mut_base(layout_root.get_mut()).display_list,
+ DisplayList::new());
let display_list = Arc::new(root_display_list.flatten(ContentStackingLevel));
// FIXME(pcwalton): This is really ugly and can't handle overflow: scroll. Refactor
@@ -703,11 +705,11 @@ impl LayoutTask {
}
}
- let root_size = flow::base(layout_root).position.size;
+ let root_size = flow::base(layout_root.get()).position.size;
let root_size = Size2D(root_size.width.to_nearest_px() as uint,
root_size.height.to_nearest_px() as uint);
let render_layer = RenderLayer {
- id: layout_root.layer_id(0),
+ id: layout_root.get().layer_id(0),
display_list: display_list.clone(),
position: Rect(Point2D(0u, 0u), root_size),
background_color: color,
@@ -721,7 +723,7 @@ impl LayoutTask {
// reflow.
let mut layers = SmallVec1::new();
layers.push(render_layer);
- for layer in mem::replace(&mut flow::mut_base(layout_root).layers,
+ for layer in mem::replace(&mut flow::mut_base(layout_root.get_mut()).layers,
DList::new()).move_iter() {
layers.push(layer)
}
@@ -732,8 +734,6 @@ impl LayoutTask {
});
}
- layout_root.destroy();
-
// Tell script that we're done.
//
// FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without
diff --git a/src/components/main/layout/model.rs b/src/components/main/layout/model.rs
index 4b35f3aee18..b0adfbabc82 100644
--- a/src/components/main/layout/model.rs
+++ b/src/components/main/layout/model.rs
@@ -4,6 +4,8 @@
//! Borders, padding, and margins.
+#![deny(unsafe_block)]
+
use layout::fragment::Fragment;
use computed = style::computed_values;
diff --git a/src/components/main/layout/parallel.rs b/src/components/main/layout/parallel.rs
index 13ea72cf22e..6c4c2292c39 100644
--- a/src/components/main/layout/parallel.rs
+++ b/src/components/main/layout/parallel.rs
@@ -12,6 +12,7 @@ use layout::context::LayoutContext;
use layout::extra::LayoutAuxMethods;
use layout::flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal};
use layout::flow;
+use layout::flow_ref::FlowRef;
use layout::layout_task::{AssignHeightsAndStoreOverflowTraversal, AssignWidthsTraversal};
use layout::layout_task::{BubbleWidthsTraversal};
use layout::util::{LayoutDataAccess, OpaqueNodeMethods};
@@ -63,13 +64,13 @@ fn null_unsafe_flow() -> UnsafeFlow {
(0, 0)
}
-pub fn owned_flow_to_unsafe_flow(flow: *Box<Flow:Share>) -> UnsafeFlow {
+pub fn owned_flow_to_unsafe_flow(flow: *FlowRef) -> UnsafeFlow {
unsafe {
cast::transmute_copy(&*flow)
}
}
-pub fn mut_owned_flow_to_unsafe_flow(flow: *mut Box<Flow:Share>) -> UnsafeFlow {
+pub fn mut_owned_flow_to_unsafe_flow(flow: *mut FlowRef) -> UnsafeFlow {
unsafe {
cast::transmute_copy(&*flow)
}
@@ -141,14 +142,14 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
loop {
unsafe {
// Get a real flow.
- let flow: &mut Box<Flow:Share> = cast::transmute(&unsafe_flow);
+ let flow: &mut FlowRef = cast::transmute(&unsafe_flow);
// Perform the appropriate traversal.
- if self.should_process(*flow) {
- self.process(*flow);
+ if self.should_process(flow.get_mut()) {
+ self.process(flow.get_mut());
}
- let base = flow::mut_base(*flow);
+ let base = flow::mut_base(flow.get_mut());
// Reset the count of children for the next layout traversal.
base.parallel.children_count.store(base.children.len() as int, Relaxed);
@@ -163,8 +164,8 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
// No, we're not at the root yet. Then are we the last child
// of our parent to finish processing? If so, we can continue
// on with our parent; otherwise, we've gotta wait.
- let parent: &mut Box<Flow:Share> = cast::transmute(&unsafe_parent);
- let parent_base = flow::mut_base(*parent);
+ let parent: &mut FlowRef = cast::transmute(&unsafe_parent);
+ let parent_base = flow::mut_base(parent.get_mut());
if parent_base.parallel.children_count.fetch_sub(1, SeqCst) == 1 {
// We were the last child of our parent. Reflow our parent.
unsafe_flow = unsafe_parent
@@ -196,13 +197,13 @@ trait ParallelPreorderFlowTraversal : PreorderFlowTraversal {
let mut had_children = false;
unsafe {
// Get a real flow.
- let flow: &mut Box<Flow:Share> = cast::transmute(&unsafe_flow);
+ let flow: &mut FlowRef = cast::transmute(&unsafe_flow);
// Perform the appropriate traversal.
- self.process(*flow);
+ self.process(flow.get_mut());
// Possibly enqueue the children.
- for kid in flow::child_iter(*flow) {
+ for kid in flow::child_iter(flow.get_mut()) {
had_children = true;
proxy.push(WorkUnit {
fun: top_down_func,
@@ -421,27 +422,28 @@ fn compute_absolute_position(unsafe_flow: PaddedUnsafeFlow,
let mut had_descendants = false;
unsafe {
// Get a real flow.
- let flow: &mut Box<Flow:Share> = cast::transmute(&unsafe_flow);
+ let flow: &mut FlowRef = cast::transmute(&unsafe_flow);
// Compute the absolute position for the flow.
- flow.compute_absolute_position();
+ flow.get_mut().compute_absolute_position();
// Count the number of absolutely-positioned children, so that we can subtract it from
// from `children_and_absolute_descendant_count` to get the number of real children.
let mut absolutely_positioned_child_count = 0;
- for kid in flow::child_iter(*flow) {
+ for kid in flow::child_iter(flow.get_mut()) {
if kid.is_absolutely_positioned() {
absolutely_positioned_child_count += 1;
}
}
// Don't enqueue absolutely positioned children.
- drop(flow::mut_base(*flow).parallel
- .children_and_absolute_descendant_count
- .fetch_sub(absolutely_positioned_child_count as int, SeqCst));
+ drop(flow::mut_base(flow.get_mut()).parallel
+ .children_and_absolute_descendant_count
+ .fetch_sub(absolutely_positioned_child_count as int,
+ SeqCst));
// Possibly enqueue the children.
- for kid in flow::child_iter(*flow) {
+ for kid in flow::child_iter(flow.get_mut()) {
if !kid.is_absolutely_positioned() {
had_descendants = true;
proxy.push(WorkUnit {
@@ -452,9 +454,9 @@ fn compute_absolute_position(unsafe_flow: PaddedUnsafeFlow,
}
// Possibly enqueue absolute descendants.
- for absolute_descendant_link in flow::mut_base(*flow).abs_descendants.iter() {
+ for absolute_descendant_link in flow::mut_base(flow.get_mut()).abs_descendants.iter() {
had_descendants = true;
- let descendant = absolute_descendant_link.resolve().unwrap();
+ let descendant = absolute_descendant_link;
proxy.push(WorkUnit {
fun: compute_absolute_position,
data: UnsafeFlowConversions::from_flow(&borrowed_flow_to_unsafe_flow(descendant)),
@@ -479,13 +481,13 @@ fn build_display_list(mut unsafe_flow: PaddedUnsafeFlow,
loop {
unsafe {
// Get a real flow.
- let flow: &mut Box<Flow:Share> = cast::transmute(&unsafe_flow);
+ let flow: &mut FlowRef = cast::transmute(&unsafe_flow);
// Build display lists.
- flow.build_display_list(layout_context);
+ flow.get_mut().build_display_list(layout_context);
{
- let base = flow::mut_base(*flow);
+ let base = flow::mut_base(flow.get_mut());
// Reset the count of children and absolute descendants for the next layout
// traversal.
@@ -497,12 +499,15 @@ fn build_display_list(mut unsafe_flow: PaddedUnsafeFlow,
}
// Possibly enqueue the parent.
- let unsafe_parent = if flow.is_absolutely_positioned() {
- mut_borrowed_flow_to_unsafe_flow(flow::mut_base(*flow).absolute_cb
- .resolve()
- .unwrap())
+ let unsafe_parent = if flow.get().is_absolutely_positioned() {
+ match *flow::mut_base(flow.get_mut()).absolute_cb.get() {
+ None => fail!("no absolute containing block for absolutely positioned?!"),
+ Some(ref mut absolute_cb) => {
+ mut_borrowed_flow_to_unsafe_flow(absolute_cb.get_mut())
+ }
+ }
} else {
- flow::mut_base(*flow).parallel.parent
+ flow::mut_base(flow.get_mut()).parallel.parent
};
if unsafe_parent == null_unsafe_flow() {
// We're done!
@@ -512,8 +517,8 @@ fn build_display_list(mut unsafe_flow: PaddedUnsafeFlow,
// No, we're not at the root yet. Then are we the last child
// of our parent to finish processing? If so, we can continue
// on with our parent; otherwise, we've gotta wait.
- let parent: &mut Box<Flow:Share> = cast::transmute(&unsafe_parent);
- let parent_base = flow::mut_base(*parent);
+ let parent: &mut FlowRef = cast::transmute(&unsafe_parent);
+ let parent_base = flow::mut_base(parent.get_mut());
if parent_base.parallel
.children_and_absolute_descendant_count
.fetch_sub(1, SeqCst) == 1 {
@@ -545,7 +550,7 @@ pub fn recalc_style_for_subtree(root_node: &LayoutNode,
queue.data = ptr::mut_null()
}
-pub fn traverse_flow_tree_preorder(root: &mut Box<Flow:Share>,
+pub fn traverse_flow_tree_preorder(root: &mut FlowRef,
profiler_chan: ProfilerChan,
layout_context: &mut LayoutContext,
queue: &mut WorkQueue<*mut LayoutContext,PaddedUnsafeFlow>) {
@@ -565,7 +570,7 @@ pub fn traverse_flow_tree_preorder(root: &mut Box<Flow:Share>,
queue.data = ptr::mut_null()
}
-pub fn build_display_list_for_subtree(root: &mut Box<Flow:Share>,
+pub fn build_display_list_for_subtree(root: &mut FlowRef,
profiler_chan: ProfilerChan,
layout_context: &mut LayoutContext,
queue: &mut WorkQueue<*mut LayoutContext,PaddedUnsafeFlow>) {
diff --git a/src/components/main/layout/table.rs b/src/components/main/layout/table.rs
index 6d203023e54..daef27fbc76 100644
--- a/src/components/main/layout/table.rs
+++ b/src/components/main/layout/table.rs
@@ -4,6 +4,8 @@
//! CSS table formatting contexts.
+#![deny(unsafe_block)]
+
use layout::block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer};
use layout::block::{WidthConstraintInput, WidthConstraintSolution};
use layout::construct::FlowConstructor;
diff --git a/src/components/main/layout/table_caption.rs b/src/components/main/layout/table_caption.rs
index d53bf0e52b1..dc6f62e8b59 100644
--- a/src/components/main/layout/table_caption.rs
+++ b/src/components/main/layout/table_caption.rs
@@ -4,6 +4,8 @@
//! CSS table formatting contexts.
+#![deny(unsafe_block)]
+
use layout::block::BlockFlow;
use layout::construct::FlowConstructor;
use layout::context::LayoutContext;
diff --git a/src/components/main/layout/table_cell.rs b/src/components/main/layout/table_cell.rs
index b5c29db9f5c..8c26118ae92 100644
--- a/src/components/main/layout/table_cell.rs
+++ b/src/components/main/layout/table_cell.rs
@@ -4,6 +4,8 @@
//! CSS table formatting contexts.
+#![deny(unsafe_block)]
+
use layout::block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer};
use layout::context::LayoutContext;
use layout::flow::{TableCellFlowClass, FlowClass, Flow};
diff --git a/src/components/main/layout/table_colgroup.rs b/src/components/main/layout/table_colgroup.rs
index 5adde1fe8fa..ed281703357 100644
--- a/src/components/main/layout/table_colgroup.rs
+++ b/src/components/main/layout/table_colgroup.rs
@@ -4,6 +4,8 @@
//! CSS table formatting contexts.
+#![deny(unsafe_block)]
+
use layout::context::LayoutContext;
use layout::flow::{BaseFlow, TableColGroupFlowClass, FlowClass, Flow};
use layout::fragment::{Fragment, TableColumnFragment};
diff --git a/src/components/main/layout/table_row.rs b/src/components/main/layout/table_row.rs
index 80b6dac0013..06594e60bba 100644
--- a/src/components/main/layout/table_row.rs
+++ b/src/components/main/layout/table_row.rs
@@ -4,6 +4,8 @@
//! CSS table formatting contexts.
+#![deny(unsafe_block)]
+
use layout::block::BlockFlow;
use layout::block::WidthAndMarginsComputer;
use layout::construct::FlowConstructor;
diff --git a/src/components/main/layout/table_rowgroup.rs b/src/components/main/layout/table_rowgroup.rs
index 980ebd6d084..644f2ee5125 100644
--- a/src/components/main/layout/table_rowgroup.rs
+++ b/src/components/main/layout/table_rowgroup.rs
@@ -4,6 +4,8 @@
//! CSS table formatting contexts.
+#![deny(unsafe_block)]
+
use layout::block::BlockFlow;
use layout::block::WidthAndMarginsComputer;
use layout::construct::FlowConstructor;
diff --git a/src/components/main/layout/table_wrapper.rs b/src/components/main/layout/table_wrapper.rs
index df64b8a1534..c83dabaa30c 100644
--- a/src/components/main/layout/table_wrapper.rs
+++ b/src/components/main/layout/table_wrapper.rs
@@ -4,6 +4,8 @@
//! CSS table formatting contexts.
+#![deny(unsafe_block)]
+
use layout::block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer};
use layout::block::{WidthConstraintInput, WidthConstraintSolution};
use layout::construct::FlowConstructor;
diff --git a/src/components/main/layout/text.rs b/src/components/main/layout/text.rs
index 61f9dd655c9..ca27a542a82 100644
--- a/src/components/main/layout/text.rs
+++ b/src/components/main/layout/text.rs
@@ -4,6 +4,8 @@
//! Text layout.
+#![deny(unsafe_block)]
+
use layout::flow::Flow;
use layout::fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, UnscannedTextFragment};
diff --git a/src/components/main/layout/wrapper.rs b/src/components/main/layout/wrapper.rs
index 3fa7b918785..779416f8de8 100644
--- a/src/components/main/layout/wrapper.rs
+++ b/src/components/main/layout/wrapper.rs
@@ -33,6 +33,9 @@
//! o Instead of `html_element_in_html_document()`, use
//! `html_element_in_html_document_for_layout()`.
+use css::node_style::StyledNode;
+use layout::util::LayoutDataWrapper;
+
use script::dom::bindings::codegen::InheritTypes::{HTMLIFrameElementDerived};
use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementDerived, TextDerived};
use script::dom::bindings::js::JS;
@@ -41,18 +44,18 @@ use script::dom::element::{HTMLLinkElementTypeId, LayoutElementHelpers, RawLayou
use script::dom::htmliframeelement::HTMLIFrameElement;
use script::dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId};
-use script::dom::node::{LayoutNodeHelpers, RawLayoutNodeHelpers};
+use script::dom::node::{LayoutNodeHelpers, RawLayoutNodeHelpers, TextNodeTypeId};
use script::dom::text::Text;
use servo_msg::constellation_msg::{PipelineId, SubpageId};
-use servo_util::namespace;
use servo_util::namespace::Namespace;
+use servo_util::namespace;
+use servo_util::str::is_whitespace;
use std::cast;
use std::cell::{Ref, RefMut};
use std::kinds::marker::ContravariantLifetime;
-use style::{PropertyDeclarationBlock, TElement, TNode, AttrSelector, SpecificNamespace};
-use style::{AnyNamespace};
-use style::computed_values::{content, display};
-use layout::util::LayoutDataWrapper;
+use style::computed_values::{content, display, white_space};
+use style::{AnyNamespace, AttrSelector, PropertyDeclarationBlock, SpecificNamespace, TElement};
+use style::{TNode};
use url::Url;
/// Allows some convenience methods on generic layout nodes.
@@ -630,6 +633,31 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
traversal.process(self)
}
+
+ pub fn is_ignorable_whitespace(&self) -> bool {
+ match self.type_id() {
+ Some(TextNodeTypeId) => {
+ unsafe {
+ let text: JS<Text> = self.get_jsmanaged().transmute_copy();
+ if !is_whitespace((*text.unsafe_get()).characterdata.data) {
+ return false
+ }
+
+ // NB: See the rules for `white-space` here:
+ //
+ // http://www.w3.org/TR/CSS21/text.html#propdef-white-space
+ //
+ // If you implement other values for this property, you will almost certainly
+ // want to update this check.
+ match self.style().get_inheritedtext().white_space {
+ white_space::normal => true,
+ _ => false,
+ }
+ }
+ }
+ _ => false
+ }
+ }
}
pub struct ThreadSafeLayoutNodeChildrenIterator<'a> {
diff --git a/src/components/main/servo.rs b/src/components/main/servo.rs
index 835c1b727dc..14912a7e179 100644
--- a/src/components/main/servo.rs
+++ b/src/components/main/servo.rs
@@ -100,6 +100,7 @@ pub mod layout {
pub mod floats;
pub mod flow;
pub mod flow_list;
+ pub mod flow_ref;
pub mod fragment;
pub mod layout_task;
pub mod inline;