auto merge of #2570 : pcwalton/servo/ref-count-flows, r=pcwalton

r? @glennw
This commit is contained in:
bors-servo 2014-06-04 01:25:28 -04:00
commit 57ab420616
20 changed files with 486 additions and 454 deletions

View file

@ -12,6 +12,8 @@
//! //!
//! CB: Containing Block of the current flow. //! CB: Containing Block of the current flow.
#![deny(unsafe_block)]
use layout::construct::FlowConstructor; use layout::construct::FlowConstructor;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::floats::{ClearBoth, ClearLeft, ClearRight, FloatKind, Floats, PlacementInfo}; use layout::floats::{ClearBoth, ClearLeft, ClearRight, FloatKind, Floats, PlacementInfo};
@ -656,9 +658,7 @@ impl BlockFlow {
let mut descendant_offset_iter = mut_base(flow).abs_descendants.iter_with_offset(); let mut descendant_offset_iter = mut_base(flow).abs_descendants.iter_with_offset();
// Pass in the respective static y offset for each descendant. // Pass in the respective static y offset for each descendant.
for (ref mut descendant_link, ref y_offset) in descendant_offset_iter { for (ref mut descendant_link, ref y_offset) in descendant_offset_iter {
match descendant_link.resolve() { let block = descendant_link.as_block();
Some(flow) => {
let block = flow.as_block();
// The stored y_offset is wrt to the flow box. // The stored y_offset is wrt to the flow box.
// Translate it to the CB (which is the padding box). // Translate it to the CB (which is the padding box).
block.static_y_offset = **y_offset - cb_top_edge_offset; block.static_y_offset = **y_offset - cb_top_edge_offset;
@ -666,9 +666,6 @@ impl BlockFlow {
return false return false
} }
} }
None => fail!("empty Rawlink to a descendant")
}
}
true true
} }
@ -685,16 +682,11 @@ impl BlockFlow {
} }
for descendant_link in mut_base(flow).abs_descendants.iter() { for descendant_link in mut_base(flow).abs_descendants.iter() {
match descendant_link.resolve() { let block = descendant_link.as_block();
Some(abs_flow) => {
let block = abs_flow.as_block();
if !block.traverse_postorder_absolute_flows(traversal) { if !block.traverse_postorder_absolute_flows(traversal) {
return false return false
} }
} }
None => fail!("empty Rawlink to a descendant")
}
}
traversal.process(flow) traversal.process(flow)
} }
@ -1125,16 +1117,11 @@ impl BlockFlow {
// Process absolute descendant links. // Process absolute descendant links.
for abs_descendant_link in self.base.abs_descendants.iter() { 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. // TODO(pradeep): Send in our absolute position directly.
accumulator.push_child(&mut display_list, kid); accumulator.push_child(&mut display_list, abs_descendant_link);
child_layers.append(mem::replace(&mut flow::mut_base(kid).layers, child_layers.append(mem::replace(&mut flow::mut_base(abs_descendant_link).layers,
DList::new())); DList::new()));
} }
None => fail!("empty Rawlink to a descendant")
}
}
accumulator.finish(&mut *self, display_list); accumulator.finish(&mut *self, display_list);
self.base.layers = child_layers self.base.layers = child_layers
@ -1634,14 +1621,8 @@ impl Flow for BlockFlow {
} }
// Process absolute descendant links. // Process absolute descendant links.
for absolute_descendant_link in self.base.abs_descendants.iter() { for absolute_descendant in self.base.abs_descendants.iter() {
match absolute_descendant_link.resolve() { flow::mut_base(absolute_descendant).absolute_position_info = absolute_position_info
Some(absolute_descendant) => {
flow::mut_base(absolute_descendant).absolute_position_info =
absolute_position_info
}
None => fail!("empty Rawlink to a descendant")
}
} }
} }

View file

@ -16,9 +16,8 @@
//! apart" a flow tree and have the flows migrate "home" to their respective DOM nodes while we //! 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 //! perform flow tree construction. The precise mechanism for this will take some experimentation
//! to get right. //! to get right.
//!
//! TODO(pcwalton): This scheme should be amenable to parallelization, but, of course, that's not #![deny(unsafe_block)]
//! yet implemented.
use css::node_style::StyledNode; use css::node_style::StyledNode;
use layout::block::BlockFlow; use layout::block::BlockFlow;
@ -26,11 +25,15 @@ use layout::context::LayoutContext;
use layout::floats::FloatKind; use layout::floats::FloatKind;
use layout::flow::{Flow, ImmutableFlowUtils, MutableOwnedFlowUtils}; use layout::flow::{Flow, ImmutableFlowUtils, MutableOwnedFlowUtils};
use layout::flow::{Descendants, AbsDescendants}; use layout::flow::{Descendants, AbsDescendants};
use layout::flow_list::{Rawlink}; use layout::flow;
use layout::fragment::{Fragment, GenericFragment, IframeFragment, IframeFragmentInfo, ImageFragment, ImageFragmentInfo}; use layout::flow_ref::FlowRef;
use layout::fragment::{SpecificFragmentInfo, TableFragment, TableCellFragment, TableColumnFragment, TableColumnFragmentInfo}; use layout::fragment::{Fragment, GenericFragment, IframeFragment, IframeFragmentInfo};
use layout::fragment::{TableRowFragment, TableWrapperFragment, UnscannedTextFragment, UnscannedTextFragmentInfo}; 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::inline::{FragmentIndex, InlineFragments, InlineFlow};
use layout::parallel;
use layout::table_wrapper::TableWrapperFlow; use layout::table_wrapper::TableWrapperFlow;
use layout::table::TableFlow; use layout::table::TableFlow;
use layout::table_caption::TableCaptionFlow; use layout::table_caption::TableCaptionFlow;
@ -45,7 +48,6 @@ use layout::wrapper::{Before, BeforeBlock, After, AfterBlock, Normal};
use gfx::display_list::OpaqueNode; use gfx::display_list::OpaqueNode;
use gfx::font_context::FontContext; use gfx::font_context::FontContext;
use script::dom::bindings::js::JS;
use script::dom::element::{HTMLIFrameElementTypeId, HTMLImageElementTypeId}; use script::dom::element::{HTMLIFrameElementTypeId, HTMLImageElementTypeId};
use script::dom::element::{HTMLObjectElementTypeId}; use script::dom::element::{HTMLObjectElementTypeId};
use script::dom::element::{HTMLTableColElementTypeId, HTMLTableDataCellElementTypeId}; 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::{CommentNodeTypeId, DoctypeNodeTypeId, DocumentFragmentNodeTypeId};
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId}; use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, ProcessingInstructionNodeTypeId};
use script::dom::node::{TextNodeTypeId}; use script::dom::node::{TextNodeTypeId};
use script::dom::text::Text;
use servo_util::namespace; use servo_util::namespace;
use servo_util::range::Range; use servo_util::range::Range;
use servo_util::str::is_whitespace;
use servo_util::url::{is_image_data, parse_url}; use servo_util::url::{is_image_data, parse_url};
use std::mem; use std::mem;
use std::sync::atomics::Relaxed;
use style::ComputedValues; use style::ComputedValues;
use style::computed_values::{display, position, float, white_space}; use style::computed_values::{display, position, float};
use sync::Arc; use sync::Arc;
use url::Url; use url::Url;
@ -74,23 +75,13 @@ pub enum ConstructionResult {
/// This node contributed a flow at the proper position in the tree. /// 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 /// Nothing more needs to be done for this node. It has bubbled up fixed
/// and absolute descendant flows that have a CB above it. /// 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 /// 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. /// later up the tree, but these objects have not yet found their home.
ConstructionItemConstructionResult(ConstructionItem), 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 /// 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 /// complete flow. Construction items bubble up the tree until they find a `Flow` to be
/// attached to. /// attached to.
@ -103,20 +94,6 @@ pub enum ConstructionItem {
TableColumnFragmentConstructionItem(Fragment), 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. /// Represents inline fragments and {ib} splits that are bubbling up from an inline.
pub struct InlineFragmentsConstructionResult { pub struct InlineFragmentsConstructionResult {
/// Any {ib} splits that we're bubbling up. /// Any {ib} splits that we're bubbling up.
@ -156,13 +133,7 @@ pub struct InlineBlockSplit {
pub predecessors: InlineFragments, pub predecessors: InlineFragments,
/// The flow that caused this {ib} split. /// The flow that caused this {ib} split.
pub flow: Box<Flow:Share>, pub flow: FlowRef,
}
impl InlineBlockSplit {
fn destroy(&mut self) {
self.flow.destroy()
}
} }
/// Holds inline fragments that we're gathering for children of an inline node. /// Holds inline fragments that we're gathering for children of an inline node.
@ -302,8 +273,8 @@ impl<'a> FlowConstructor<'a> {
#[inline(always)] #[inline(always)]
fn flush_inline_fragments_to_flow_or_list(&mut self, fn flush_inline_fragments_to_flow_or_list(&mut self,
fragment_accumulator: InlineFragmentsAccumulator, fragment_accumulator: InlineFragmentsAccumulator,
flow: &mut Box<Flow:Share>, flow: &mut FlowRef,
flow_list: &mut Vec<Box<Flow:Share>>, flow_list: &mut Vec<FlowRef>,
whitespace_stripping: WhitespaceStrippingMode, whitespace_stripping: WhitespaceStrippingMode,
node: &ThreadSafeLayoutNode) { node: &ThreadSafeLayoutNode) {
let mut fragments = fragment_accumulator.finish(); 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); let mut inline_flow = box InlineFlow::from_fragments((*node).clone(), fragments);
inline_flow.compute_minimum_ascent_and_descent(self.font_context(), &**node.style()); 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); TextRunScanner::new().scan_for_runs(self.font_context(), inline_flow);
let mut inline_flow = FlowRef::new(inline_flow);
inline_flow.finish(self.layout_context); 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) flow_list.push(inline_flow)
} else { } else {
flow.add_new_child(inline_flow) flow.add_new_child(inline_flow)
@ -335,9 +307,8 @@ impl<'a> FlowConstructor<'a> {
} }
fn build_block_flow_using_children_construction_result(&mut self, fn build_block_flow_using_children_construction_result(&mut self,
flow: &mut Box<Flow:Share>, flow: &mut FlowRef,
consecutive_siblings: consecutive_siblings: &mut Vec<FlowRef>,
&mut Vec<Box<Flow:Share>>,
node: &ThreadSafeLayoutNode, node: &ThreadSafeLayoutNode,
kid: ThreadSafeLayoutNode, kid: ThreadSafeLayoutNode,
inline_fragment_accumulator: inline_fragment_accumulator:
@ -349,16 +320,16 @@ impl<'a> FlowConstructor<'a> {
FlowConstructionResult(kid_flow, kid_abs_descendants) => { FlowConstructionResult(kid_flow, kid_abs_descendants) => {
// If kid_flow is TableCaptionFlow, kid_flow should be added under // If kid_flow is TableCaptionFlow, kid_flow should be added under
// TableWrapperFlow. // 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.set_flow_construction_result(FlowConstructionResult(
kid_flow, kid_flow,
Descendants::new())) 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) consecutive_siblings.push(kid_flow)
} else { } else {
// Strip ignorable whitespace from the start of this flow per CSS 2.1 § // Strip ignorable whitespace from the start of this flow per CSS 2.1 §
// 9.2.1.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; *first_fragment = false;
StripWhitespaceFromStart StripWhitespaceFromStart
} else { } else {
@ -423,7 +394,7 @@ impl<'a> FlowConstructor<'a> {
// Push the flow generated by the {ib} split onto our list of // Push the flow generated by the {ib} split onto our list of
// flows. // flows.
if flow.need_anonymous_flow(kid_flow) { if flow.get().need_anonymous_flow(kid_flow.get()) {
consecutive_siblings.push(kid_flow) consecutive_siblings.push(kid_flow)
} else { } else {
flow.add_new_child(kid_flow) flow.add_new_child(kid_flow)
@ -451,9 +422,7 @@ impl<'a> FlowConstructor<'a> {
/// this block flow. /// this block flow.
/// Also, deal with the absolute and fixed descendants bubbled up by /// Also, deal with the absolute and fixed descendants bubbled up by
/// children nodes. /// children nodes.
fn build_flow_using_children(&mut self, fn build_flow_using_children(&mut self, mut flow: FlowRef, node: &ThreadSafeLayoutNode)
mut flow: Box<Flow:Share>,
node: &ThreadSafeLayoutNode)
-> ConstructionResult { -> ConstructionResult {
// Gather up fragments for the inline flows we might need to create. // Gather up fragments for the inline flows we might need to create.
let mut inline_fragment_accumulator = InlineFragmentsAccumulator::new(); let mut inline_fragment_accumulator = InlineFragmentsAccumulator::new();
@ -489,18 +458,19 @@ impl<'a> FlowConstructor<'a> {
// The flow is done. // The flow is done.
flow.finish(self.layout_context); flow.finish(self.layout_context);
let is_positioned = flow.as_block().is_positioned(); let is_positioned = flow.get_mut().as_block().is_positioned();
let is_fixed_positioned = flow.as_block().is_fixed(); let is_fixed_positioned = flow.get_mut().as_block().is_fixed();
let is_absolutely_positioned = flow.as_block().is_absolutely_positioned(); let is_absolutely_positioned = flow.get_mut().as_block().is_absolutely_positioned();
if is_positioned { if is_positioned {
// This is the CB for all the absolute descendants. // This is the CB for all the absolute descendants.
flow.set_abs_descendants(abs_descendants); flow.set_abs_descendants(abs_descendants);
abs_descendants = Descendants::new(); abs_descendants = Descendants::new();
if is_fixed_positioned || is_absolutely_positioned { if is_fixed_positioned || is_absolutely_positioned {
// This is now the only absolute flow in the subtree which hasn't yet // This is now the only absolute flow in the subtree which hasn't yet
// reached its CB. // reached its CB.
abs_descendants.push(Rawlink::some(flow)); abs_descendants.push(flow.clone());
} }
} }
FlowConstructionResult(flow, abs_descendants) 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 /// other `BlockFlow`s or `InlineFlow`s underneath it, depending on whether {ib} splits needed
/// to happen. /// to happen.
fn build_flow_for_block(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { fn build_flow_for_block(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
let flow = box BlockFlow::from_node(self, node) as Box<Flow:Share>; let flow = box BlockFlow::from_node(self, node) as Box<Flow>;
self.build_flow_using_children(flow, node) 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 /// Builds the flow for a node with `float: {left|right}`. This yields a float `BlockFlow` with
/// a `BlockFlow` underneath it. /// a `BlockFlow` underneath it.
fn build_flow_for_floated_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: FloatKind) fn build_flow_for_floated_block(&mut self, node: &ThreadSafeLayoutNode, float_kind: FloatKind)
-> ConstructionResult { -> ConstructionResult {
let flow = box BlockFlow::float_from_node(self, node, float_kind) as Box<Flow:Share>; let flow = box BlockFlow::float_from_node(self, node, float_kind) as Box<Flow>;
self.build_flow_using_children(flow, node) self.build_flow_using_children(FlowRef::new(flow), node)
} }
/// Concatenates the fragments of kids, adding in our own borders/padding/margins if necessary. /// 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 /// TableCaptionFlow is populated underneath TableWrapperFlow
fn place_table_caption_under_table_wrapper(&mut self, fn place_table_caption_under_table_wrapper(&mut self,
table_wrapper_flow: &mut Box<Flow:Share>, table_wrapper_flow: &mut FlowRef,
node: &ThreadSafeLayoutNode) { node: &ThreadSafeLayoutNode) {
for kid in node.children() { for kid in node.children() {
match kid.swap_out_construction_result() { match kid.swap_out_construction_result() {
NoConstructionResult | ConstructionItemConstructionResult(_) => {} NoConstructionResult | ConstructionItemConstructionResult(_) => {}
FlowConstructionResult(kid_flow, _) => { FlowConstructionResult(kid_flow, _) => {
// Only kid flows with table-caption are matched here. // 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); 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. /// Generates an anonymous table flow according to CSS 2.1 § 17.2.1, step 2.
/// If necessary, generate recursively another anonymous table flow. /// If necessary, generate recursively another anonymous table flow.
fn generate_anonymous_missing_child(&mut self, fn generate_anonymous_missing_child(&mut self,
child_flows: Vec<Box<Flow:Share>>, child_flows: Vec<FlowRef>,
flow: &mut Box<Flow:Share>, flow: &mut FlowRef,
node: &ThreadSafeLayoutNode) { 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!(); let mut consecutive_siblings = vec!();
for kid_flow in child_flows.move_iter() { 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); consecutive_siblings.push(kid_flow);
continue; continue;
} }
if !consecutive_siblings.is_empty() { 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!(); consecutive_siblings = vec!();
} }
anonymous_flow.add_new_child(kid_flow); anonymous_flow.add_new_child(kid_flow);
@ -700,10 +672,12 @@ impl<'a> FlowConstructor<'a> {
/// other `TableCaptionFlow`s or `TableFlow`s underneath it. /// other `TableCaptionFlow`s or `TableFlow`s underneath it.
fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { fn build_flow_for_table_wrapper(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
let fragment = Fragment::new_from_specific_info(node, TableWrapperFragment); 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_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 first populate the TableFlow with other flows than TableCaptionFlow.
// We then populate the TableWrapperFlow with TableCaptionFlow, and attach // We then populate the TableWrapperFlow with TableCaptionFlow, and attach
@ -726,21 +700,24 @@ impl<'a> FlowConstructor<'a> {
// The flow is done. // The flow is done.
wrapper_flow.finish(self.layout_context); wrapper_flow.finish(self.layout_context);
let is_positioned = wrapper_flow.as_block().is_positioned(); let is_positioned = wrapper_flow.get_mut().as_block().is_positioned();
let is_fixed_positioned = wrapper_flow.as_block().is_fixed(); let is_fixed_positioned = wrapper_flow.get_mut().as_block().is_fixed();
let is_absolutely_positioned = wrapper_flow.as_block().is_absolutely_positioned(); let is_absolutely_positioned = wrapper_flow.get_mut()
.as_block()
.is_absolutely_positioned();
if is_positioned { if is_positioned {
// This is the CB for all the absolute descendants. // This is the CB for all the absolute descendants.
wrapper_flow.set_abs_descendants(abs_descendants); wrapper_flow.set_abs_descendants(abs_descendants);
abs_descendants = Descendants::new(); abs_descendants = Descendants::new();
if is_fixed_positioned { if is_fixed_positioned {
// Send itself along with the other fixed descendants. // 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 { } else if is_absolutely_positioned {
// This is now the only absolute flow in the subtree which hasn't yet // This is now the only absolute flow in the subtree which hasn't yet
// reached its CB. // reached its CB.
abs_descendants.push(Rawlink::some(wrapper_flow)); abs_descendants.push(wrapper_flow.clone());
} }
} }
FlowConstructionResult(wrapper_flow, abs_descendants) 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` /// Builds a flow for a node with `display: table-caption`. This yields a `TableCaptionFlow`
/// with possibly other `BlockFlow`s or `InlineFlow`s underneath it. /// 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: &ThreadSafeLayoutNode) -> ConstructionResult {
let flow = box TableCaptionFlow::from_node(self, node) as Box<Flow:Share>; let flow = box TableCaptionFlow::from_node(self, node) as Box<Flow>;
self.build_flow_using_children(flow, node) self.build_flow_using_children(FlowRef::new(flow), node)
} }
/// Builds a flow for a node with `display: table-row-group`. This yields a `TableRowGroupFlow` /// Builds a flow for a node with `display: table-row-group`. This yields a `TableRowGroupFlow`
/// with possibly other `TableRowFlow`s underneath it. /// with possibly other `TableRowFlow`s underneath it.
fn build_flow_for_table_rowgroup(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult { fn build_flow_for_table_rowgroup(&mut self, node: &ThreadSafeLayoutNode) -> ConstructionResult {
let fragment = Fragment::new_from_specific_info(node, TableRowFragment); let fragment = Fragment::new_from_specific_info(node, TableRowFragment);
let flow = box TableRowGroupFlow::from_node_and_fragment(node, fragment) as Box<Flow:Share>; let flow = box TableRowGroupFlow::from_node_and_fragment(node, fragment);
self.build_flow_using_children(flow, node) 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 /// Builds a flow for a node with `display: table-row`. This yields a `TableRowFlow` with
/// possibly other `TableCellFlow`s underneath it. /// 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: &ThreadSafeLayoutNode) -> ConstructionResult {
let fragment = Fragment::new_from_specific_info(node, TableRowFragment); let fragment = Fragment::new_from_specific_info(node, TableRowFragment);
let flow = box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow:Share>; let flow = box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow>;
self.build_flow_using_children(flow, node) self.build_flow_using_children(FlowRef::new(flow), node)
} }
/// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with /// Builds a flow for a node with `display: table-cell`. This yields a `TableCellFlow` with
/// possibly other `BlockFlow`s or `InlineFlow`s underneath it. /// 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: &ThreadSafeLayoutNode) -> ConstructionResult {
let fragment = Fragment::new_from_specific_info(node, TableCellFragment); let fragment = Fragment::new_from_specific_info(node, TableCellFragment);
let flow = box TableCellFlow::from_node_and_fragment(node, fragment) as Box<Flow:Share>; let flow = box TableCellFlow::from_node_and_fragment(node, fragment) as Box<Flow>;
self.build_flow_using_children(flow, node) self.build_flow_using_children(FlowRef::new(flow), node)
} }
/// Creates a fragment for a node with `display: table-column`. /// Creates a fragment for a node with `display: table-column`.
@ -812,7 +790,8 @@ impl<'a> FlowConstructor<'a> {
let specific = TableColumnFragment(TableColumnFragmentInfo::new(node)); let specific = TableColumnFragment(TableColumnFragmentInfo::new(node));
col_fragments.push(Fragment::new_from_specific_info(node, specific)); 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); flow.finish(self.layout_context);
FlowConstructionResult(flow, Descendants::new()) FlowConstructionResult(flow, Descendants::new())
@ -860,8 +839,7 @@ impl<'a> PostorderNodeMutTraversal for FlowConstructor<'a> {
// results of children. // results of children.
(display::none, _, _) => { (display::none, _, _) => {
for child in node.children() { for child in node.children() {
let mut old_result = child.swap_out_construction_result(); drop(child.swap_out_construction_result())
old_result.destroy()
} }
} }
@ -950,9 +928,6 @@ trait NodeUtils {
/// Returns true if this node doesn't render its kids and false otherwise. /// Returns true if this node doesn't render its kids and false otherwise.
fn is_replaced_content(&self) -> bool; 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. /// Sets the construction result of a flow.
fn set_flow_construction_result(&self, result: ConstructionResult); 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)] #[inline(always)]
fn set_flow_construction_result(&self, result: ConstructionResult) { fn set_flow_construction_result(&self, result: ConstructionResult) {
let mut layout_data_ref = self.mutate_layout_data(); 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)
}
}
}

View file

@ -29,13 +29,13 @@ use css::node_style::StyledNode;
use layout::block::BlockFlow; use layout::block::BlockFlow;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::floats::Floats; 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::fragment::{Fragment, TableRowFragment, TableCellFragment};
use layout::incremental::RestyleDamage; use layout::incremental::RestyleDamage;
use layout::inline::InlineFlow; use layout::inline::InlineFlow;
use layout::model::{CollapsibleMargins, IntrinsicWidths, MarginCollapseInfo}; use layout::model::{CollapsibleMargins, IntrinsicWidths, MarginCollapseInfo};
use layout::parallel::FlowParallelInfo; use layout::parallel::FlowParallelInfo;
use layout::parallel;
use layout::table_wrapper::TableWrapperFlow; use layout::table_wrapper::TableWrapperFlow;
use layout::table::TableFlow; use layout::table::TableFlow;
use layout::table_colgroup::TableColGroupFlow; use layout::table_colgroup::TableColGroupFlow;
@ -45,7 +45,6 @@ use layout::table_caption::TableCaptionFlow;
use layout::table_cell::TableCellFlow; use layout::table_cell::TableCellFlow;
use layout::wrapper::ThreadSafeLayoutNode; use layout::wrapper::ThreadSafeLayoutNode;
use collections::Deque;
use collections::dlist::DList; use collections::dlist::DList;
use geom::point::Point2D; use geom::point::Point2D;
use geom::rect::Rect; use geom::rect::Rect;
@ -58,7 +57,7 @@ use std::cast;
use std::fmt; use std::fmt;
use std::iter::Zip; use std::iter::Zip;
use std::num::Zero; use std::num::Zero;
use std::sync::atomics::Relaxed; use std::sync::atomics::{AtomicUint, Relaxed, SeqCst};
use std::slice::MutItems; use std::slice::MutItems;
use style::computed_values::{clear, position, text_align}; 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 /// 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. /// methods to `ImmutableFlowUtils` or `MutableFlowUtils` before adding more methods here.
pub trait Flow: fmt::Show + ToStr { pub trait Flow: fmt::Show + ToStr + Share {
// RTTI // RTTI
// //
// TODO(pcwalton): Use Rust's RTTI, once that works. // 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. /// Iterates over the children of this flow.
pub fn child_iter<'a>(flow: &'a mut Flow) -> MutFlowListIterator<'a> { pub fn child_iter<'a>(flow: &'a mut Flow) -> MutFlowListIterator<'a> {
mut_base(flow).children.mut_iter() mut_base(flow).children.mut_iter()
@ -337,7 +331,7 @@ pub trait ImmutableFlowUtils {
fn need_anonymous_flow(self, child: &Flow) -> bool; fn need_anonymous_flow(self, child: &Flow) -> bool;
/// Generates missing child flow of this flow. /// 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. /// Returns true if this flow has no children.
fn is_leaf(self) -> bool; fn is_leaf(self) -> bool;
@ -372,42 +366,18 @@ pub trait MutableFlowUtils {
// Mutators // 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. /// Computes the overflow region for this flow.
fn store_overflow(self, _: &mut LayoutContext); fn store_overflow(self, _: &mut LayoutContext);
/// Builds the display lists for this flow. /// Builds the display lists for this flow.
fn build_display_list(self, layout_context: &LayoutContext); fn build_display_list(self, layout_context: &LayoutContext);
/// Destroys the flow.
fn destroy(self);
} }
pub trait MutableOwnedFlowUtils { 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 absolute descendants for this flow.
/// ///
/// Set this flow as the Containing Block for all the absolute descendants. /// Set this flow as the Containing Block for all the absolute descendants.
fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants); fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants);
/// Destroys the flow.
fn destroy(&mut self);
} }
#[deriving(Eq, Show)] #[deriving(Eq, Show)]
@ -550,10 +520,11 @@ impl FlowFlags {
/// The Descendants of a flow. /// The Descendants of a flow.
/// ///
/// Also, details about their position wrt this flow. /// Also, details about their position wrt this flow.
/// FIXME: This should use @pcwalton's reference counting scheme (Coming Soon).
pub struct Descendants { pub struct Descendants {
/// Links to every Descendant. /// Links to every descendant. This must be private because it is unsafe to leak `FlowRef`s to
pub descendant_links: Vec<Rawlink>, /// layout.
descendant_links: Vec<FlowRef>,
/// Static y offsets of all descendants from the start of this flow box. /// Static y offsets of all descendants from the start of this flow box.
pub static_y_offsets: Vec<Au>, pub static_y_offsets: Vec<Au>,
} }
@ -570,7 +541,7 @@ impl Descendants {
self.descendant_links.len() 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); self.descendant_links.push(given_descendant);
} }
@ -585,21 +556,41 @@ impl Descendants {
/// Return an iterator over the descendant flows. /// Return an iterator over the descendant flows.
pub fn iter<'a>(&'a mut self) -> DescendantIter<'a> { 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). /// Return an iterator over (descendant, static y offset).
pub fn iter_with_offset<'a>(&'a mut self) -> DescendantOffsetIter<'a> { pub fn iter_with_offset<'a>(&'a mut self) -> DescendantOffsetIter<'a> {
self.descendant_links.mut_slice_from(0).mut_iter().zip( let descendant_iter = DescendantIter {
self.static_y_offsets.mut_slice_from(0).mut_iter()) 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 AbsDescendants = Descendants;
pub type DescendantIter<'a> = MutItems<'a, Rawlink>; pub struct DescendantIter<'a> {
iter: MutItems<'a, FlowRef>,
}
pub type DescendantOffsetIter<'a> = Zip<MutItems<'a, Rawlink>, MutItems<'a, Au>>; 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<DescendantIter<'a>, MutItems<'a, Au>>;
/// Information needed to compute absolute (i.e. viewport-relative) flow positions (not to be /// Information needed to compute absolute (i.e. viewport-relative) flow positions (not to be
/// confused with absolutely-positioned flows). /// confused with absolutely-positioned flows).
@ -628,12 +619,17 @@ impl AbsolutePositionInfo {
/// Data common to all flows. /// Data common to all flows.
pub struct BaseFlow { 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, pub restyle_damage: RestyleDamage,
/// The children of this flow. /// The children of this flow.
pub children: FlowList, pub children: FlowList,
pub next_sibling: Link, pub next_sibling: Link,
pub prev_sibling: Rawlink, pub prev_sibling: Link,
/* layout computations */ /* layout computations */
// TODO: min/pref and position are used during disjoint phases of // 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. /// Any layers that we're bubbling up, in a linked list.
pub layers: DList<RenderLayer>, 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. /// Various flags for flows, tightly packed to save space.
pub flags: FlowFlags, pub flags: FlowFlags,
} }
@ -707,8 +697,8 @@ pub struct BaseFlow {
#[unsafe_destructor] #[unsafe_destructor]
impl Drop for BaseFlow { impl Drop for BaseFlow {
fn drop(&mut self) { fn drop(&mut self) {
if !self.destroyed { if self.ref_count.load(SeqCst) != 0 {
fail!("Flow destroyed by going out of scope—this is unsafe! Use `destroy()` instead!") fail!("Flow destroyed before its ref count hit zero—this is unsafe!")
} }
} }
} }
@ -717,11 +707,13 @@ impl BaseFlow {
#[inline] #[inline]
pub fn new(node: ThreadSafeLayoutNode) -> BaseFlow { pub fn new(node: ThreadSafeLayoutNode) -> BaseFlow {
BaseFlow { BaseFlow {
ref_count: AtomicUint::new(1),
restyle_damage: node.restyle_damage(), restyle_damage: node.restyle_damage(),
children: FlowList::new(), children: FlowList::new(),
next_sibling: None, next_sibling: None,
prev_sibling: Rawlink::none(), prev_sibling: None,
intrinsic_widths: IntrinsicWidths::new(), intrinsic_widths: IntrinsicWidths::new(),
position: Rect::zero(), position: Rect::zero(),
@ -740,8 +732,6 @@ impl BaseFlow {
layers: DList::new(), layers: DList::new(),
absolute_position_info: AbsolutePositionInfo::new(), absolute_position_info: AbsolutePositionInfo::new(),
destroyed: false,
flags: FlowFlags::new(), flags: FlowFlags::new(),
} }
} }
@ -749,6 +739,10 @@ impl BaseFlow {
pub fn child_iter<'a>(&'a mut self) -> MutFlowListIterator<'a> { pub fn child_iter<'a>(&'a mut self) -> MutFlowListIterator<'a> {
self.children.mut_iter() self.children.mut_iter()
} }
pub unsafe fn ref_count<'a>(&'a self) -> &'a AtomicUint {
&self.ref_count
}
} }
impl<'a> ImmutableFlowUtils for &'a Flow { impl<'a> ImmutableFlowUtils for &'a Flow {
@ -841,20 +835,21 @@ impl<'a> ImmutableFlowUtils for &'a Flow {
} }
/// Generates missing child flow of this flow. /// 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 {
match self.class() { let flow = match self.class() {
TableFlowClass | TableRowGroupFlowClass => { TableFlowClass | TableRowGroupFlowClass => {
let fragment = Fragment::new_anonymous_table_fragment(node, TableRowFragment); 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 => { TableRowFlowClass => {
let fragment = Fragment::new_anonymous_table_fragment(node, TableCellFragment); 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") fail!("no need to generate a missing child")
} }
} };
FlowRef::new(flow)
} }
/// Returns true if this flow has no children. /// Returns true if this flow has no children.
@ -957,16 +952,6 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
traversal.process(self) 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. /// Calculate and set overflow for current flow.
/// ///
/// CSS Section 11.1 /// CSS Section 11.1
@ -994,15 +979,10 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
// FIXME(#2004, pcwalton): This is wrong for `position: fixed`. // FIXME(#2004, pcwalton): This is wrong for `position: fixed`.
for descendant_link in mut_base(self).abs_descendants.iter() { for descendant_link in mut_base(self).abs_descendants.iter() {
match descendant_link.resolve() { let mut kid_overflow = base(descendant_link).overflow;
Some(flow) => {
let mut kid_overflow = base(flow).overflow;
kid_overflow = kid_overflow.translate(&my_position.origin); kid_overflow = kid_overflow.translate(&my_position.origin);
overflow = overflow.union(&kid_overflow) overflow = overflow.union(&kid_overflow)
} }
None => fail!("empty Rawlink to a descendant")
}
}
} }
mut_base(self).overflow = 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 absolute descendants for this flow.
/// ///
/// Set yourself as the Containing Block for all the absolute descendants. /// Set yourself as the Containing Block for all the absolute descendants.
/// ///
/// Assumption: This is called in a bottom-up traversal, so that nothing /// This is called during flow construction, so nothing else can be accessing the descendant
/// else is accessing the descendant flows. /// 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) { fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants) {
let self_link = Rawlink::some(*self); let this = self.clone();
let block = self.as_block();
let block = self.get_mut().as_block();
block.base.abs_descendants = abs_descendants; block.base.abs_descendants = abs_descendants;
block.base block.base
.parallel .parallel
@ -1093,20 +1041,9 @@ impl MutableOwnedFlowUtils for Box<Flow:Share> {
.fetch_add(block.base.abs_descendants.len() as int, Relaxed); .fetch_add(block.base.abs_descendants.len() as int, Relaxed);
for descendant_link in block.base.abs_descendants.iter() { for descendant_link in block.base.abs_descendants.iter() {
match descendant_link.resolve() { let base = mut_base(descendant_link);
Some(flow) => { base.absolute_cb.set(this.clone());
let base = mut_base(flow);
base.absolute_cb.set(self_link.clone());
} }
None => fail!("empty Rawlink to a descendant")
}
}
}
/// Destroys the flow.
fn destroy(&mut self) {
let self_borrowed: &mut Flow = *self;
self_borrowed.destroy();
} }
} }
@ -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 /// 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 /// with an immutable reference while that same node is being laid out, causing possible iterator
/// invalidation and use-after-free. /// invalidation and use-after-free.
///
/// FIXME(pcwalton): I think this would be better with a borrow flag instead of `unsafe`.
pub struct ContainingBlockLink { pub struct ContainingBlockLink {
/// TODO(pcwalton): Reference count. /// The pointer up to the containing block.
link: Rawlink, link: Option<FlowRef>,
} }
impl ContainingBlockLink { impl ContainingBlockLink {
fn new() -> ContainingBlockLink { fn new() -> ContainingBlockLink {
ContainingBlockLink { ContainingBlockLink {
link: Rawlink::none(), link: None,
} }
} }
fn set(&mut self, link: Rawlink) { fn set(&mut self, link: FlowRef) {
self.link = link self.link = Some(link)
} }
pub unsafe fn resolve(&mut self) -> Option<&mut Flow> { pub unsafe fn get<'a>(&'a mut self) -> &'a mut Option<FlowRef> {
self.link.resolve() &mut self.link
} }
#[inline] #[inline]
pub fn generated_containing_block_rect(&mut self) -> Rect<Au> { 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(),
}
} }
} }

View file

@ -5,13 +5,14 @@
//! A variant of `DList` specialized to store `Flow`s without an extra //! A variant of `DList` specialized to store `Flow`s without an extra
//! indirection. //! indirection.
use layout::flow::{Flow, base, mut_base};
use layout::flow_ref::FlowRef;
use std::cast; use std::cast;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use layout::flow::{Flow, base, mut_base}; pub type Link = Option<FlowRef>;
pub type Link = Option<Box<Flow:Share>>;
#[deriving(Clone)] #[deriving(Clone)]
pub struct Rawlink { pub struct Rawlink {
@ -26,7 +27,7 @@ pub struct Rawlink {
pub struct FlowList { pub struct FlowList {
length: uint, length: uint,
list_head: Link, list_head: Link,
list_tail: Rawlink, list_tail: Link,
} }
/// Double-ended FlowList iterator /// Double-ended FlowList iterator
@ -54,42 +55,30 @@ impl Rawlink {
} }
/// Like Option::Some for Rawlink /// Like Option::Some for Rawlink
pub fn some(n: &mut Flow) -> Rawlink { pub fn some(n: &Flow) -> Rawlink {
unsafe { cast::transmute(n) } unsafe { cast::transmute(n) }
} }
/// Convert the `Rawlink` into an Option value fn from_optional_flow_ref(flow_ref: &Option<FlowRef>) -> Rawlink {
fn resolve_immut(&self) -> Option<&Flow> { match *flow_ref {
None => Rawlink::none(),
Some(ref flow_ref) => Rawlink::some(flow_ref.get()),
}
}
pub unsafe fn resolve_mut(&self) -> Option<&mut Flow> {
if self.obj.is_null() { if self.obj.is_null() {
None None
} else { } else {
let me: &Flow = unsafe { cast::transmute_copy(self) }; let me: &mut Flow = cast::transmute_copy(self);
Some(me) Some(me)
} }
} }
pub fn resolve(&mut self) -> Option<&mut Flow> {
if self.obj.is_null() {
None
} else {
let me: &mut Flow = unsafe { 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)` /// Set the .prev field on `next`, then return `Some(next)`
fn link_with_prev(mut next: Box<Flow:Share>, prev: Rawlink) -> Link { unsafe fn link_with_prev(mut next: FlowRef, prev: Option<FlowRef>) -> Link {
mut_base(next).prev_sibling = prev; mut_base(next.get_mut()).prev_sibling = prev;
Some(next) Some(next)
} }
@ -112,33 +101,34 @@ impl FlowList {
/// Provide a reference to the front element, or None if the list is empty /// Provide a reference to the front element, or None if the list is empty
#[inline] #[inline]
pub fn front<'a>(&'a self) -> Option<&'a Flow> { 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 /// Provide a mutable reference to the front element, or None if the list is empty
#[inline] #[inline]
pub fn front_mut<'a>(&'a mut self) -> Option<&'a mut Flow> { pub unsafe fn front_mut<'a>(&'a mut self) -> Option<&'a mut Flow> {
self.list_head.as_mut().map(|head| { let x: &mut Flow = *head; x }) self.list_head.as_mut().map(|head| head.get_mut())
} }
/// Provide a reference to the back element, or None if the list is empty /// Provide a reference to the back element, or None if the list is empty
#[inline] #[inline]
pub fn back<'a>(&'a self) -> Option<&'a Flow> { pub fn back<'a>(&'a self) -> Option<&'a Flow> {
let tmp = self.list_tail.resolve_immut(); match self.list_tail {
tmp.as_ref().map(|tail| { let x: &Flow = *tail; x }) 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 /// Provide a mutable reference to the back element, or None if the list is empty
#[inline] #[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: // Can't use map() due to error:
// lifetime of `tail` is too short to guarantee its contents can be safely reborrowed // lifetime of `tail` is too short to guarantee its contents can be safely reborrowed
let tmp = self.list_tail.resolve(); match self.list_tail {
match tmp {
None => None, None => None,
Some(tail) => { Some(ref mut tail) => {
let x: &mut Flow = tail; let x: &mut Flow = tail.get_mut();
Some(x) Some(cast::transmute_copy(&x))
} }
} }
} }
@ -146,31 +136,35 @@ impl FlowList {
/// Add an element first in the list /// Add an element first in the list
/// ///
/// O(1) /// O(1)
pub fn push_front(&mut self, mut new_head: Box<Flow:Share>) { pub fn push_front(&mut self, mut new_head: FlowRef) {
unsafe {
match self.list_head { match self.list_head {
None => { None => {
self.list_tail = Rawlink::some(new_head); self.list_tail = Some(new_head.clone());
self.list_head = link_with_prev(new_head, Rawlink::none()); self.list_head = link_with_prev(new_head, None);
} }
Some(ref mut head) => { Some(ref mut head) => {
mut_base(new_head).prev_sibling = Rawlink::none(); mut_base(new_head.get_mut()).prev_sibling = None;
mut_base(*head).prev_sibling = Rawlink::some(new_head); mut_base(head.get_mut()).prev_sibling = Some(new_head.clone());
mem::swap(head, &mut new_head); mem::swap(head, &mut new_head);
mut_base(*head).next_sibling = Some(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 /// Remove the first element and return it, or None if the list is empty
/// ///
/// O(1) /// 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.list_head.take().map(|mut front_node| {
self.length -= 1; self.length -= 1;
match mut_base(front_node).next_sibling.take() { unsafe {
Some(node) => self.list_head = link_with_prev(node, Rawlink::none()), match mut_base(front_node.get_mut()).next_sibling.take() {
None => self.list_tail = Rawlink::none() Some(node) => self.list_head = link_with_prev(node, None),
None => self.list_tail = None,
}
} }
front_node front_node
}) })
@ -179,42 +173,27 @@ impl FlowList {
/// Add an element last in the list /// Add an element last in the list
/// ///
/// O(1) /// 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() { if self.list_tail.is_none() {
return self.push_front(new_tail); return self.push_front(new_tail);
} else { }
let mut old_tail = self.list_tail;
self.list_tail = Rawlink::some(new_tail); let old_tail = self.list_tail.clone();
let tail = unsafe { old_tail.get() }; self.list_tail = Some(new_tail.clone());
mut_base(tail).next_sibling = link_with_prev(new_tail, Rawlink::some(tail)); 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; 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()
}
}
}
/// Create an empty list /// Create an empty list
#[inline] #[inline]
pub fn new() -> FlowList { pub fn new() -> FlowList {
FlowList { FlowList {
list_head: None, list_head: None,
list_tail: Rawlink::none(), list_tail: None,
length: 0, length: 0,
} }
} }
@ -225,7 +204,7 @@ impl FlowList {
FlowListIterator { FlowListIterator {
nelem: self.len(), nelem: self.len(),
head: &self.list_head, head: &self.list_head,
tail: self.list_tail tail: Rawlink::from_optional_flow_ref(&self.list_tail)
} }
} }
@ -233,13 +212,13 @@ impl FlowList {
#[inline] #[inline]
pub fn mut_iter<'a>(&'a mut self) -> MutFlowListIterator<'a> { pub fn mut_iter<'a>(&'a mut self) -> MutFlowListIterator<'a> {
let head_raw = match self.list_head { 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(), None => Rawlink::none(),
}; };
MutFlowListIterator { MutFlowListIterator {
nelem: self.len(), nelem: self.len(),
head: head_raw, head: head_raw,
tail: self.list_tail, tail: Rawlink::from_optional_flow_ref(&self.list_tail),
list: self list: self
} }
} }
@ -251,20 +230,20 @@ impl Drop for FlowList {
// Dissolve the list in backwards direction // Dissolve the list in backwards direction
// Just dropping the list_head can lead to stack exhaustion // Just dropping the list_head can lead to stack exhaustion
// when length is >> 1_000_000 // when length is >> 1_000_000
let mut tail = self.list_tail; let mut tail = mem::replace(&mut self.list_tail, None);
loop { loop {
match tail.resolve() { let new_tail = match tail {
None => break, None => break,
Some(prev) => { Some(ref mut prev) => {
let prev_base = mut_base(prev); let prev_base = mut_base(prev.get_mut());
prev_base.next_sibling.take(); prev_base.next_sibling.take();
tail = prev_base.prev_sibling; prev_base.prev_sibling.clone()
}
} }
};
tail = new_tail
} }
self.length = 0; self.length = 0;
self.list_head = None; self.list_head = None;
self.list_tail = Rawlink::none();
} }
} }
@ -275,10 +254,10 @@ impl<'a> Iterator<&'a Flow> for FlowListIterator<'a> {
return None; return None;
} }
self.head.as_ref().map(|head| { self.head.as_ref().map(|head| {
let head_base = base(*head); let head_base = base(head.get());
self.nelem -= 1; self.nelem -= 1;
self.head = &head_base.next_sibling; self.head = &head_base.next_sibling;
let ret: &Flow = *head; let ret: &Flow = head.get();
ret ret
}) })
} }
@ -295,11 +274,12 @@ impl<'a> Iterator<&'a mut Flow> for MutFlowListIterator<'a> {
if self.nelem == 0 { if self.nelem == 0 {
return None; return None;
} }
self.head.resolve().map(|next| { unsafe {
self.head.resolve_mut().map(|next| {
self.nelem -= 1; self.nelem -= 1;
self.head = match mut_base(next).next_sibling { self.head = match mut_base(next).next_sibling {
Some(ref mut node) => { Some(ref mut node) => {
let x: &mut Flow = *node; let x: &mut Flow = node.get_mut();
Rawlink::some(x) Rawlink::some(x)
} }
None => Rawlink::none(), None => Rawlink::none(),
@ -307,6 +287,7 @@ impl<'a> Iterator<&'a mut Flow> for MutFlowListIterator<'a> {
next next
}) })
} }
}
#[inline] #[inline]
fn size_hint(&self) -> (uint, Option<uint>) { fn size_hint(&self) -> (uint, Option<uint>) {

View file

@ -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,
}
}
}
}

View file

@ -4,6 +4,8 @@
//! The `Box` type, which represents the leaves of the layout tree. //! The `Box` type, which represents the leaves of the layout tree.
#![deny(unsafe_block)]
use css::node_style::StyledNode; use css::node_style::StyledNode;
use layout::construct::FlowConstructor; use layout::construct::FlowConstructor;
use layout::context::LayoutContext; use layout::context::LayoutContext;
@ -38,7 +40,6 @@ use servo_util::range::*;
use servo_util::namespace; use servo_util::namespace;
use servo_util::smallvec::SmallVec; use servo_util::smallvec::SmallVec;
use servo_util::str::is_whitespace; use servo_util::str::is_whitespace;
use std::cast;
use std::fmt; use std::fmt;
use std::from_str::FromStr; use std::from_str::FromStr;
use std::iter::AdditiveIterator; 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 /// Returns a debug ID of this fragment. This ID should not be considered stable across multiple
/// layouts or fragment manipulations. /// layouts or fragment manipulations.
pub fn debug_id(&self) -> uint { pub fn debug_id(&self) -> uint {
unsafe { self as *Fragment as uint
cast::transmute(self)
}
} }
/// Transforms this fragment into another fragment of the given type, with the given size, preserving all /// Transforms this fragment into another fragment of the given type, with the given size, preserving all

View file

@ -2,6 +2,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this * 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/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![deny(unsafe_block)]
use css::node_style::StyledNode; use css::node_style::StyledNode;
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::floats::{FloatLeft, Floats, PlacementInfo}; use layout::floats::{FloatLeft, Floats, PlacementInfo};

View file

@ -14,6 +14,7 @@ use layout::context::LayoutContext;
use layout::flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils}; use layout::flow::{Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
use layout::flow::{PreorderFlowTraversal, PostorderFlowTraversal}; use layout::flow::{PreorderFlowTraversal, PostorderFlowTraversal};
use layout::flow; use layout::flow;
use layout::flow_ref::FlowRef;
use layout::incremental::RestyleDamage; use layout::incremental::RestyleDamage;
use layout::parallel::PaddedUnsafeFlow; use layout::parallel::PaddedUnsafeFlow;
use layout::parallel; use layout::parallel;
@ -246,7 +247,7 @@ impl<'a> BuildDisplayListTraversal<'a> {
} }
for absolute_descendant_link in flow::mut_base(flow).abs_descendants.iter() { 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) flow.build_display_list(self.layout_context)
@ -455,7 +456,7 @@ impl LayoutTask {
} }
/// Retrieves the flow tree root from the root node. /// 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 mut layout_data_ref = node.mutate_layout_data();
let result = match &mut *layout_data_ref { let result = match &mut *layout_data_ref {
&Some(ref mut layout_data) => { &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!"), _ => 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 flow
} }
@ -521,13 +522,13 @@ impl LayoutTask {
/// benchmarked against those two. It is marked `#[inline(never)]` to aid profiling. /// benchmarked against those two. It is marked `#[inline(never)]` to aid profiling.
#[inline(never)] #[inline(never)]
fn solve_constraints_parallel(&mut self, fn solve_constraints_parallel(&mut self,
layout_root: &mut Box<Flow:Share>, layout_root: &mut FlowRef,
layout_context: &mut LayoutContext) { layout_context: &mut LayoutContext) {
if layout_context.opts.bubble_widths_separately { if layout_context.opts.bubble_widths_separately {
let mut traversal = BubbleWidthsTraversal { let mut traversal = BubbleWidthsTraversal {
layout_context: layout_context, layout_context: layout_context,
}; };
layout_root.traverse_postorder(&mut traversal); layout_root.get_mut().traverse_postorder(&mut traversal);
} }
match self.parallel_traversal { match self.parallel_traversal {
@ -547,13 +548,13 @@ impl LayoutTask {
/// This is only on in debug builds. /// This is only on in debug builds.
#[inline(never)] #[inline(never)]
#[cfg(debug)] #[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; let mut traversal = FlowTreeVerificationTraversal;
layout_root.traverse_preorder(&mut traversal); layout_root.traverse_preorder(&mut traversal);
} }
#[cfg(not(debug))] #[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. /// The high-level routine that performs layout tasks.
@ -634,10 +635,10 @@ impl LayoutTask {
// Propagate damage. // Propagate damage.
profile(time::LayoutDamagePropagateCategory, self.profiler_chan.clone(), || { 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 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 // 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 { match self.parallel_traversal {
None => { None => {
// Sequential mode. // Sequential mode.
self.solve_constraints(layout_root, &mut layout_ctx) self.solve_constraints(layout_root.get_mut(), &mut layout_ctx)
} }
Some(_) => { Some(_) => {
// Parallel mode. // Parallel mode.
@ -658,14 +659,14 @@ impl LayoutTask {
// Build the display list if necessary, and send it to the renderer. // Build the display list if necessary, and send it to the renderer.
if data.goal == ReflowForDisplay { if data.goal == ReflowForDisplay {
profile(time::LayoutDispListBuildCategory, self.profiler_chan.clone(), || { 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 { match self.parallel_traversal {
None => { None => {
let mut traversal = BuildDisplayListTraversal { let mut traversal = BuildDisplayListTraversal {
layout_context: &layout_ctx, layout_context: &layout_ctx,
}; };
traversal.process(layout_root); traversal.process(layout_root.get_mut());
} }
Some(ref mut traversal) => { Some(ref mut traversal) => {
parallel::build_display_list_for_subtree(&mut layout_root, parallel::build_display_list_for_subtree(&mut layout_root,
@ -675,7 +676,8 @@ impl LayoutTask {
} }
} }
let root_display_list = mem::replace(&mut flow::mut_base(layout_root).display_list, let root_display_list =
mem::replace(&mut flow::mut_base(layout_root.get_mut()).display_list,
DisplayList::new()); DisplayList::new());
let display_list = Arc::new(root_display_list.flatten(ContentStackingLevel)); let display_list = Arc::new(root_display_list.flatten(ContentStackingLevel));
@ -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, let root_size = Size2D(root_size.width.to_nearest_px() as uint,
root_size.height.to_nearest_px() as uint); root_size.height.to_nearest_px() as uint);
let render_layer = RenderLayer { let render_layer = RenderLayer {
id: layout_root.layer_id(0), id: layout_root.get().layer_id(0),
display_list: display_list.clone(), display_list: display_list.clone(),
position: Rect(Point2D(0u, 0u), root_size), position: Rect(Point2D(0u, 0u), root_size),
background_color: color, background_color: color,
@ -721,7 +723,7 @@ impl LayoutTask {
// reflow. // reflow.
let mut layers = SmallVec1::new(); let mut layers = SmallVec1::new();
layers.push(render_layer); 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() { DList::new()).move_iter() {
layers.push(layer) layers.push(layer)
} }
@ -732,8 +734,6 @@ impl LayoutTask {
}); });
} }
layout_root.destroy();
// Tell script that we're done. // Tell script that we're done.
// //
// FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without // FIXME(pcwalton): This should probably be *one* channel, but we can't fix this without

View file

@ -4,6 +4,8 @@
//! Borders, padding, and margins. //! Borders, padding, and margins.
#![deny(unsafe_block)]
use layout::fragment::Fragment; use layout::fragment::Fragment;
use computed = style::computed_values; use computed = style::computed_values;

View file

@ -12,6 +12,7 @@ use layout::context::LayoutContext;
use layout::extra::LayoutAuxMethods; use layout::extra::LayoutAuxMethods;
use layout::flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal}; use layout::flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal};
use layout::flow; use layout::flow;
use layout::flow_ref::FlowRef;
use layout::layout_task::{AssignHeightsAndStoreOverflowTraversal, AssignWidthsTraversal}; use layout::layout_task::{AssignHeightsAndStoreOverflowTraversal, AssignWidthsTraversal};
use layout::layout_task::{BubbleWidthsTraversal}; use layout::layout_task::{BubbleWidthsTraversal};
use layout::util::{LayoutDataAccess, OpaqueNodeMethods}; use layout::util::{LayoutDataAccess, OpaqueNodeMethods};
@ -63,13 +64,13 @@ fn null_unsafe_flow() -> UnsafeFlow {
(0, 0) (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 { unsafe {
cast::transmute_copy(&*flow) 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 { unsafe {
cast::transmute_copy(&*flow) cast::transmute_copy(&*flow)
} }
@ -141,14 +142,14 @@ trait ParallelPostorderFlowTraversal : PostorderFlowTraversal {
loop { loop {
unsafe { unsafe {
// Get a real flow. // 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. // Perform the appropriate traversal.
if self.should_process(*flow) { if self.should_process(flow.get_mut()) {
self.process(*flow); 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. // Reset the count of children for the next layout traversal.
base.parallel.children_count.store(base.children.len() as int, Relaxed); 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 // 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 // of our parent to finish processing? If so, we can continue
// on with our parent; otherwise, we've gotta wait. // on with our parent; otherwise, we've gotta wait.
let parent: &mut Box<Flow:Share> = cast::transmute(&unsafe_parent); let parent: &mut FlowRef = cast::transmute(&unsafe_parent);
let parent_base = flow::mut_base(*parent); let parent_base = flow::mut_base(parent.get_mut());
if parent_base.parallel.children_count.fetch_sub(1, SeqCst) == 1 { if parent_base.parallel.children_count.fetch_sub(1, SeqCst) == 1 {
// We were the last child of our parent. Reflow our parent. // We were the last child of our parent. Reflow our parent.
unsafe_flow = unsafe_parent unsafe_flow = unsafe_parent
@ -196,13 +197,13 @@ trait ParallelPreorderFlowTraversal : PreorderFlowTraversal {
let mut had_children = false; let mut had_children = false;
unsafe { unsafe {
// Get a real flow. // 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. // Perform the appropriate traversal.
self.process(*flow); self.process(flow.get_mut());
// Possibly enqueue the children. // Possibly enqueue the children.
for kid in flow::child_iter(*flow) { for kid in flow::child_iter(flow.get_mut()) {
had_children = true; had_children = true;
proxy.push(WorkUnit { proxy.push(WorkUnit {
fun: top_down_func, fun: top_down_func,
@ -421,27 +422,28 @@ fn compute_absolute_position(unsafe_flow: PaddedUnsafeFlow,
let mut had_descendants = false; let mut had_descendants = false;
unsafe { unsafe {
// Get a real flow. // 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. // 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 // 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. // from `children_and_absolute_descendant_count` to get the number of real children.
let mut absolutely_positioned_child_count = 0; 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() { if kid.is_absolutely_positioned() {
absolutely_positioned_child_count += 1; absolutely_positioned_child_count += 1;
} }
} }
// Don't enqueue absolutely positioned children. // Don't enqueue absolutely positioned children.
drop(flow::mut_base(*flow).parallel drop(flow::mut_base(flow.get_mut()).parallel
.children_and_absolute_descendant_count .children_and_absolute_descendant_count
.fetch_sub(absolutely_positioned_child_count as int, SeqCst)); .fetch_sub(absolutely_positioned_child_count as int,
SeqCst));
// Possibly enqueue the children. // 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() { if !kid.is_absolutely_positioned() {
had_descendants = true; had_descendants = true;
proxy.push(WorkUnit { proxy.push(WorkUnit {
@ -452,9 +454,9 @@ fn compute_absolute_position(unsafe_flow: PaddedUnsafeFlow,
} }
// Possibly enqueue absolute descendants. // 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; had_descendants = true;
let descendant = absolute_descendant_link.resolve().unwrap(); let descendant = absolute_descendant_link;
proxy.push(WorkUnit { proxy.push(WorkUnit {
fun: compute_absolute_position, fun: compute_absolute_position,
data: UnsafeFlowConversions::from_flow(&borrowed_flow_to_unsafe_flow(descendant)), data: UnsafeFlowConversions::from_flow(&borrowed_flow_to_unsafe_flow(descendant)),
@ -479,13 +481,13 @@ fn build_display_list(mut unsafe_flow: PaddedUnsafeFlow,
loop { loop {
unsafe { unsafe {
// Get a real flow. // 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. // 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 // Reset the count of children and absolute descendants for the next layout
// traversal. // traversal.
@ -497,12 +499,15 @@ fn build_display_list(mut unsafe_flow: PaddedUnsafeFlow,
} }
// Possibly enqueue the parent. // Possibly enqueue the parent.
let unsafe_parent = if flow.is_absolutely_positioned() { let unsafe_parent = if flow.get().is_absolutely_positioned() {
mut_borrowed_flow_to_unsafe_flow(flow::mut_base(*flow).absolute_cb match *flow::mut_base(flow.get_mut()).absolute_cb.get() {
.resolve() None => fail!("no absolute containing block for absolutely positioned?!"),
.unwrap()) Some(ref mut absolute_cb) => {
mut_borrowed_flow_to_unsafe_flow(absolute_cb.get_mut())
}
}
} else { } else {
flow::mut_base(*flow).parallel.parent flow::mut_base(flow.get_mut()).parallel.parent
}; };
if unsafe_parent == null_unsafe_flow() { if unsafe_parent == null_unsafe_flow() {
// We're done! // 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 // 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 // of our parent to finish processing? If so, we can continue
// on with our parent; otherwise, we've gotta wait. // on with our parent; otherwise, we've gotta wait.
let parent: &mut Box<Flow:Share> = cast::transmute(&unsafe_parent); let parent: &mut FlowRef = cast::transmute(&unsafe_parent);
let parent_base = flow::mut_base(*parent); let parent_base = flow::mut_base(parent.get_mut());
if parent_base.parallel if parent_base.parallel
.children_and_absolute_descendant_count .children_and_absolute_descendant_count
.fetch_sub(1, SeqCst) == 1 { .fetch_sub(1, SeqCst) == 1 {
@ -545,7 +550,7 @@ pub fn recalc_style_for_subtree(root_node: &LayoutNode,
queue.data = ptr::mut_null() 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, profiler_chan: ProfilerChan,
layout_context: &mut LayoutContext, layout_context: &mut LayoutContext,
queue: &mut WorkQueue<*mut LayoutContext,PaddedUnsafeFlow>) { 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() 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, profiler_chan: ProfilerChan,
layout_context: &mut LayoutContext, layout_context: &mut LayoutContext,
queue: &mut WorkQueue<*mut LayoutContext,PaddedUnsafeFlow>) { queue: &mut WorkQueue<*mut LayoutContext,PaddedUnsafeFlow>) {

View file

@ -4,6 +4,8 @@
//! CSS table formatting contexts. //! CSS table formatting contexts.
#![deny(unsafe_block)]
use layout::block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer}; use layout::block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer};
use layout::block::{WidthConstraintInput, WidthConstraintSolution}; use layout::block::{WidthConstraintInput, WidthConstraintSolution};
use layout::construct::FlowConstructor; use layout::construct::FlowConstructor;

View file

@ -4,6 +4,8 @@
//! CSS table formatting contexts. //! CSS table formatting contexts.
#![deny(unsafe_block)]
use layout::block::BlockFlow; use layout::block::BlockFlow;
use layout::construct::FlowConstructor; use layout::construct::FlowConstructor;
use layout::context::LayoutContext; use layout::context::LayoutContext;

View file

@ -4,6 +4,8 @@
//! CSS table formatting contexts. //! CSS table formatting contexts.
#![deny(unsafe_block)]
use layout::block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer}; use layout::block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer};
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::flow::{TableCellFlowClass, FlowClass, Flow}; use layout::flow::{TableCellFlowClass, FlowClass, Flow};

View file

@ -4,6 +4,8 @@
//! CSS table formatting contexts. //! CSS table formatting contexts.
#![deny(unsafe_block)]
use layout::context::LayoutContext; use layout::context::LayoutContext;
use layout::flow::{BaseFlow, TableColGroupFlowClass, FlowClass, Flow}; use layout::flow::{BaseFlow, TableColGroupFlowClass, FlowClass, Flow};
use layout::fragment::{Fragment, TableColumnFragment}; use layout::fragment::{Fragment, TableColumnFragment};

View file

@ -4,6 +4,8 @@
//! CSS table formatting contexts. //! CSS table formatting contexts.
#![deny(unsafe_block)]
use layout::block::BlockFlow; use layout::block::BlockFlow;
use layout::block::WidthAndMarginsComputer; use layout::block::WidthAndMarginsComputer;
use layout::construct::FlowConstructor; use layout::construct::FlowConstructor;

View file

@ -4,6 +4,8 @@
//! CSS table formatting contexts. //! CSS table formatting contexts.
#![deny(unsafe_block)]
use layout::block::BlockFlow; use layout::block::BlockFlow;
use layout::block::WidthAndMarginsComputer; use layout::block::WidthAndMarginsComputer;
use layout::construct::FlowConstructor; use layout::construct::FlowConstructor;

View file

@ -4,6 +4,8 @@
//! CSS table formatting contexts. //! CSS table formatting contexts.
#![deny(unsafe_block)]
use layout::block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer}; use layout::block::{BlockFlow, MarginsMayNotCollapse, WidthAndMarginsComputer};
use layout::block::{WidthConstraintInput, WidthConstraintSolution}; use layout::block::{WidthConstraintInput, WidthConstraintSolution};
use layout::construct::FlowConstructor; use layout::construct::FlowConstructor;

View file

@ -4,6 +4,8 @@
//! Text layout. //! Text layout.
#![deny(unsafe_block)]
use layout::flow::Flow; use layout::flow::Flow;
use layout::fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, UnscannedTextFragment}; use layout::fragment::{Fragment, ScannedTextFragment, ScannedTextFragmentInfo, UnscannedTextFragment};

View file

@ -33,6 +33,9 @@
//! o Instead of `html_element_in_html_document()`, use //! o Instead of `html_element_in_html_document()`, use
//! `html_element_in_html_document_for_layout()`. //! `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::{HTMLIFrameElementDerived};
use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementDerived, TextDerived}; use script::dom::bindings::codegen::InheritTypes::{HTMLImageElementDerived, TextDerived};
use script::dom::bindings::js::JS; 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::htmliframeelement::HTMLIFrameElement;
use script::dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers}; use script::dom::htmlimageelement::{HTMLImageElement, LayoutHTMLImageElementHelpers};
use script::dom::node::{DocumentNodeTypeId, ElementNodeTypeId, Node, NodeTypeId}; 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 script::dom::text::Text;
use servo_msg::constellation_msg::{PipelineId, SubpageId}; use servo_msg::constellation_msg::{PipelineId, SubpageId};
use servo_util::namespace;
use servo_util::namespace::Namespace; use servo_util::namespace::Namespace;
use servo_util::namespace;
use servo_util::str::is_whitespace;
use std::cast; use std::cast;
use std::cell::{Ref, RefMut}; use std::cell::{Ref, RefMut};
use std::kinds::marker::ContravariantLifetime; use std::kinds::marker::ContravariantLifetime;
use style::{PropertyDeclarationBlock, TElement, TNode, AttrSelector, SpecificNamespace}; use style::computed_values::{content, display, white_space};
use style::{AnyNamespace}; use style::{AnyNamespace, AttrSelector, PropertyDeclarationBlock, SpecificNamespace, TElement};
use style::computed_values::{content, display}; use style::{TNode};
use layout::util::LayoutDataWrapper;
use url::Url; use url::Url;
/// Allows some convenience methods on generic layout nodes. /// Allows some convenience methods on generic layout nodes.
@ -630,6 +633,31 @@ impl<'ln> ThreadSafeLayoutNode<'ln> {
traversal.process(self) 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> { pub struct ThreadSafeLayoutNodeChildrenIterator<'a> {

View file

@ -100,6 +100,7 @@ pub mod layout {
pub mod floats; pub mod floats;
pub mod flow; pub mod flow;
pub mod flow_list; pub mod flow_list;
pub mod flow_ref;
pub mod fragment; pub mod fragment;
pub mod layout_task; pub mod layout_task;
pub mod inline; pub mod inline;