mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
layout: Reference count flows, and forbid unsafe code in many places.
This commit is contained in:
parent
5a97f5fd79
commit
735cc28654
20 changed files with 486 additions and 454 deletions
|
@ -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,17 +658,12 @@ 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) => {
|
// The stored y_offset is wrt to the flow box.
|
||||||
let block = flow.as_block();
|
// Translate it to the CB (which is the padding box).
|
||||||
// The stored y_offset is wrt to the flow box.
|
block.static_y_offset = **y_offset - cb_top_edge_offset;
|
||||||
// Translate it to the CB (which is the padding box).
|
if !block.traverse_preorder_absolute_flows(traversal) {
|
||||||
block.static_y_offset = **y_offset - cb_top_edge_offset;
|
return false
|
||||||
if !block.traverse_preorder_absolute_flows(traversal) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => fail!("empty Rawlink to a descendant")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,14 +682,9 @@ 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) => {
|
if !block.traverse_postorder_absolute_flows(traversal) {
|
||||||
let block = abs_flow.as_block();
|
return false
|
||||||
if !block.traverse_postorder_absolute_flows(traversal) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => fail!("empty Rawlink to a descendant")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1125,15 +1117,10 @@ 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() {
|
// TODO(pradeep): Send in our absolute position directly.
|
||||||
Some(kid) => {
|
accumulator.push_child(&mut display_list, abs_descendant_link);
|
||||||
// TODO(pradeep): Send in our absolute position directly.
|
child_layers.append(mem::replace(&mut flow::mut_base(abs_descendant_link).layers,
|
||||||
accumulator.push_child(&mut display_list, kid);
|
DList::new()));
|
||||||
child_layers.append(mem::replace(&mut flow::mut_base(kid).layers,
|
|
||||||
DList::new()));
|
|
||||||
}
|
|
||||||
None => fail!("empty Rawlink to a descendant")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
accumulator.finish(&mut *self, display_list);
|
accumulator.finish(&mut *self, display_list);
|
||||||
|
@ -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")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,14 +979,9 @@ 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) => {
|
kid_overflow = kid_overflow.translate(&my_position.origin);
|
||||||
let mut kid_overflow = base(flow).overflow;
|
overflow = overflow.union(&kid_overflow)
|
||||||
kid_overflow = kid_overflow.translate(&my_position.origin);
|
|
||||||
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> {
|
impl MutableOwnedFlowUtils for FlowRef {
|
||||||
/// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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,21 +1041,10 @@ 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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A link to a flow's containing block.
|
/// 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
|
/// 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(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
if self.obj.is_null() {
|
None => Rawlink::none(),
|
||||||
None
|
Some(ref flow_ref) => Rawlink::some(flow_ref.get()),
|
||||||
} else {
|
|
||||||
let me: &Flow = unsafe { cast::transmute_copy(self) };
|
|
||||||
Some(me)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolve(&mut self) -> Option<&mut Flow> {
|
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: &mut Flow = unsafe { cast::transmute_copy(self) };
|
let me: &mut Flow = cast::transmute_copy(self);
|
||||||
Some(me)
|
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) {
|
||||||
match self.list_head {
|
unsafe {
|
||||||
None => {
|
match self.list_head {
|
||||||
self.list_tail = Rawlink::some(new_head);
|
None => {
|
||||||
self.list_head = link_with_prev(new_head, Rawlink::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).prev_sibling = Rawlink::none();
|
Some(ref mut head) => {
|
||||||
mut_base(*head).prev_sibling = Rawlink::some(new_head);
|
mut_base(new_head.get_mut()).prev_sibling = None;
|
||||||
mem::swap(head, &mut new_head);
|
mut_base(head.get_mut()).prev_sibling = Some(new_head.clone());
|
||||||
mut_base(*head).next_sibling = Some(new_head);
|
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
|
/// 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,17 +274,19 @@ 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.nelem -= 1;
|
self.head.resolve_mut().map(|next| {
|
||||||
self.head = match mut_base(next).next_sibling {
|
self.nelem -= 1;
|
||||||
Some(ref mut node) => {
|
self.head = match mut_base(next).next_sibling {
|
||||||
let x: &mut Flow = *node;
|
Some(ref mut node) => {
|
||||||
Rawlink::some(x)
|
let x: &mut Flow = node.get_mut();
|
||||||
}
|
Rawlink::some(x)
|
||||||
None => Rawlink::none(),
|
}
|
||||||
};
|
None => Rawlink::none(),
|
||||||
next
|
};
|
||||||
})
|
next
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
79
src/components/main/layout/flow_ref.rs
Normal file
79
src/components/main/layout/flow_ref.rs
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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,8 +676,9 @@ impl LayoutTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let root_display_list = mem::replace(&mut flow::mut_base(layout_root).display_list,
|
let root_display_list =
|
||||||
DisplayList::new());
|
mem::replace(&mut flow::mut_base(layout_root.get_mut()).display_list,
|
||||||
|
DisplayList::new());
|
||||||
let display_list = Arc::new(root_display_list.flatten(ContentStackingLevel));
|
let display_list = Arc::new(root_display_list.flatten(ContentStackingLevel));
|
||||||
|
|
||||||
// FIXME(pcwalton): This is really ugly and can't handle overflow: scroll. Refactor
|
// 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,
|
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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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>) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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};
|
||||||
|
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue