aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/layout/flow.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/layout/flow.rs')
-rw-r--r--src/components/layout/flow.rs1138
1 files changed, 0 insertions, 1138 deletions
diff --git a/src/components/layout/flow.rs b/src/components/layout/flow.rs
deleted file mode 100644
index 2759ebbe74b..00000000000
--- a/src/components/layout/flow.rs
+++ /dev/null
@@ -1,1138 +0,0 @@
-/* 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/. */
-
-//! Servo's experimental layout system builds a tree of `Flow` and `Fragment` objects and solves
-//! layout constraints to obtain positions and display attributes of tree nodes. Positions are
-//! computed in several tree traversals driven by the fundamental data dependencies required by
-/// inline and block layout.
-///
-/// Flows are interior nodes in the layout tree and correspond closely to *flow contexts* in the
-/// CSS specification. Flows are responsible for positioning their child flow contexts and fragments.
-/// Flows have purpose-specific fields, such as auxiliary line structs, out-of-flow child
-/// lists, and so on.
-///
-/// Currently, the important types of flows are:
-///
-/// * `BlockFlow`: A flow that establishes a block context. It has several child flows, each of
-/// which are positioned according to block formatting context rules (CSS block boxes). Block
-/// flows also contain a single box to represent their rendered borders, padding, etc.
-/// The BlockFlow at the root of the tree has special behavior: it stretches to the boundaries of
-/// the viewport.
-///
-/// * `InlineFlow`: A flow that establishes an inline context. It has a flat list of child
-/// fragments/flows that are subject to inline layout and line breaking and structs to represent
-/// line breaks and mapping to CSS boxes, for the purpose of handling `getClientRects()` and
-/// similar methods.
-
-use css::node_style::StyledNode;
-use block::BlockFlow;
-use context::LayoutContext;
-use floats::Floats;
-use flow_list::{FlowList, Link, FlowListIterator, MutFlowListIterator};
-use flow_ref::FlowRef;
-use fragment::{Fragment, TableRowFragment, TableCellFragment};
-use incremental::RestyleDamage;
-use inline::InlineFlow;
-use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
-use parallel::FlowParallelInfo;
-use table_wrapper::TableWrapperFlow;
-use table::TableFlow;
-use table_colgroup::TableColGroupFlow;
-use table_rowgroup::TableRowGroupFlow;
-use table_row::TableRowFlow;
-use table_caption::TableCaptionFlow;
-use table_cell::TableCellFlow;
-use wrapper::ThreadSafeLayoutNode;
-
-use collections::dlist::DList;
-use geom::Point2D;
-use gfx::display_list::DisplayList;
-use gfx::render_task::RenderLayer;
-use serialize::{Encoder, Encodable};
-use servo_msg::compositor_msg::LayerId;
-use servo_util::geometry::Au;
-use servo_util::logical_geometry::WritingMode;
-use servo_util::logical_geometry::{LogicalRect, LogicalSize};
-use std::mem;
-use std::num::Zero;
-use std::fmt;
-use std::iter::Zip;
-use std::raw;
-use std::sync::atomics::{AtomicUint, Relaxed, SeqCst};
-use std::slice::MutItems;
-use style::computed_values::{clear, position, text_align};
-
-/// Virtual methods that make up a float context.
-///
-/// Note that virtual methods have a cost; we should not overuse them in Servo. Consider adding
-/// methods to `ImmutableFlowUtils` or `MutableFlowUtils` before adding more methods here.
-pub trait Flow: fmt::Show + ToString + Share {
- // RTTI
- //
- // TODO(pcwalton): Use Rust's RTTI, once that works.
-
- /// Returns the class of flow that this is.
- fn class(&self) -> FlowClass;
-
- /// If this is a block flow, returns the underlying object, borrowed immutably. Fails
- /// otherwise.
- fn as_immutable_block<'a>(&'a self) -> &'a BlockFlow {
- fail!("called as_immutable_block() on a non-block flow")
- }
-
- /// If this is a block flow, returns the underlying object. Fails otherwise.
- fn as_block<'a>(&'a mut self) -> &'a mut BlockFlow {
- debug!("called as_block() on a flow of type {}", self.class());
- fail!("called as_block() on a non-block flow")
- }
-
- /// If this is an inline flow, returns the underlying object, borrowed immutably. Fails
- /// otherwise.
- fn as_immutable_inline<'a>(&'a self) -> &'a InlineFlow {
- fail!("called as_immutable_inline() on a non-inline flow")
- }
-
- /// If this is an inline flow, returns the underlying object. Fails otherwise.
- fn as_inline<'a>(&'a mut self) -> &'a mut InlineFlow {
- fail!("called as_inline() on a non-inline flow")
- }
-
- /// If this is a table wrapper flow, returns the underlying object. Fails otherwise.
- fn as_table_wrapper<'a>(&'a mut self) -> &'a mut TableWrapperFlow {
- fail!("called as_table_wrapper() on a non-tablewrapper flow")
- }
-
- /// If this is a table flow, returns the underlying object. Fails otherwise.
- fn as_table<'a>(&'a mut self) -> &'a mut TableFlow {
- fail!("called as_table() on a non-table flow")
- }
-
- /// If this is a table colgroup flow, returns the underlying object. Fails otherwise.
- fn as_table_colgroup<'a>(&'a mut self) -> &'a mut TableColGroupFlow {
- fail!("called as_table_colgroup() on a non-tablecolgroup flow")
- }
-
- /// If this is a table rowgroup flow, returns the underlying object. Fails otherwise.
- fn as_table_rowgroup<'a>(&'a mut self) -> &'a mut TableRowGroupFlow {
- fail!("called as_table_rowgroup() on a non-tablerowgroup flow")
- }
-
- /// If this is a table row flow, returns the underlying object. Fails otherwise.
- fn as_table_row<'a>(&'a mut self) -> &'a mut TableRowFlow {
- fail!("called as_table_row() on a non-tablerow flow")
- }
-
- /// If this is a table cell flow, returns the underlying object. Fails otherwise.
- fn as_table_caption<'a>(&'a mut self) -> &'a mut TableCaptionFlow {
- fail!("called as_table_caption() on a non-tablecaption flow")
- }
-
- /// If this is a table cell flow, returns the underlying object. Fails otherwise.
- fn as_table_cell<'a>(&'a mut self) -> &'a mut TableCellFlow {
- fail!("called as_table_cell() on a non-tablecell flow")
- }
-
- /// If this is a table row or table rowgroup or table flow, returns column inline-sizes.
- /// Fails otherwise.
- fn col_inline_sizes<'a>(&'a mut self) -> &'a mut Vec<Au> {
- fail!("called col_inline_sizes() on an other flow than table-row/table-rowgroup/table")
- }
-
- /// If this is a table row flow or table rowgroup flow or table flow, returns column min inline-sizes.
- /// Fails otherwise.
- fn col_min_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
- fail!("called col_min_inline_sizes() on an other flow than table-row/table-rowgroup/table")
- }
-
- /// If this is a table row flow or table rowgroup flow or table flow, returns column min inline-sizes.
- /// Fails otherwise.
- fn col_pref_inline_sizes<'a>(&'a self) -> &'a Vec<Au> {
- fail!("called col_pref_inline_sizes() on an other flow than table-row/table-rowgroup/table")
- }
-
- // Main methods
-
- /// Pass 1 of reflow: computes minimum and preferred inline-sizes.
- ///
- /// Recursively (bottom-up) determine the flow's minimum and preferred inline-sizes. When called on
- /// this flow, all child flows have had their minimum and preferred inline-sizes set. This function
- /// must decide minimum/preferred inline-sizes based on its children's inline-sizes and the dimensions of
- /// any boxes it is responsible for flowing.
- fn bubble_inline_sizes(&mut self, _ctx: &LayoutContext) {
- fail!("bubble_inline_sizes not yet implemented")
- }
-
- /// Pass 2 of reflow: computes inline-size.
- fn assign_inline_sizes(&mut self, _ctx: &LayoutContext) {
- fail!("assign_inline_sizes not yet implemented")
- }
-
- /// Pass 3a of reflow: computes block-size.
- fn assign_block_size<'a>(&mut self, _ctx: &'a LayoutContext<'a>) {
- fail!("assign_block_size not yet implemented")
- }
-
- /// Assigns block-sizes in-order; or, if this is a float, places the float. The default
- /// implementation simply assigns block-sizes if this flow is impacted by floats. Returns true if
- /// this child was impacted by floats or false otherwise.
- fn assign_block_size_for_inorder_child_if_necessary<'a>(&mut self, layout_context: &'a LayoutContext<'a>)
- -> bool {
- let impacted = base(&*self).flags.impacted_by_floats();
- if impacted {
- self.assign_block_size(layout_context);
- }
- impacted
- }
-
- /// Phase 4 of reflow: computes absolute positions.
- fn compute_absolute_position(&mut self) {
- // The default implementation is a no-op.
- }
-
- /// Returns the direction that this flow clears floats in, if any.
- fn float_clearance(&self) -> clear::T {
- clear::none
- }
-
- /// Returns true if this float is a block formatting context and false otherwise. The default
- /// implementation returns false.
- fn is_block_formatting_context(&self, _only_impactable_by_floats: bool) -> bool {
- false
- }
-
- fn compute_collapsible_block_start_margin(&mut self,
- _layout_context: &mut LayoutContext,
- _margin_collapse_info: &mut MarginCollapseInfo) {
- // The default implementation is a no-op.
- }
-
- /// Marks this flow as the root flow. The default implementation is a no-op.
- fn mark_as_root(&mut self) {}
-
- // Note that the following functions are mostly called using static method
- // dispatch, so it's ok to have them in this trait. Plus, they have
- // different behaviour for different types of Flow, so they can't go into
- // the Immutable / Mutable Flow Utils traits without additional casts.
-
- /// Return true if store overflow is delayed for this flow.
- ///
- /// Currently happens only for absolutely positioned flows.
- fn is_store_overflow_delayed(&mut self) -> bool {
- false
- }
-
- fn is_root(&self) -> bool {
- false
- }
-
- fn is_float(&self) -> bool {
- false
- }
-
- /// The 'position' property of this flow.
- fn positioning(&self) -> position::T {
- position::static_
- }
-
- /// Return true if this flow has position 'fixed'.
- fn is_fixed(&self) -> bool {
- self.positioning() == position::fixed
- }
-
- fn is_positioned(&self) -> bool {
- self.is_relatively_positioned() || self.is_absolutely_positioned()
- }
-
- fn is_relatively_positioned(&self) -> bool {
- self.positioning() == position::relative
- }
-
- fn is_absolutely_positioned(&self) -> bool {
- self.positioning() == position::absolute || self.is_fixed()
- }
-
- /// Return true if this is the root of an Absolute flow tree.
- fn is_root_of_absolute_flow_tree(&self) -> bool {
- false
- }
-
- /// Returns true if this is an absolute containing block.
- fn is_absolute_containing_block(&self) -> bool {
- false
- }
-
- /// Return the dimensions of the containing block generated by this flow for absolutely-
- /// positioned descendants. For block flows, this is the padding box.
- fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
- fail!("generated_containing_block_position not yet implemented for this flow")
- }
-
- /// Returns a layer ID for the given fragment.
- fn layer_id(&self, fragment_id: uint) -> LayerId {
- unsafe {
- let pointer: uint = mem::transmute(self);
- LayerId(pointer, fragment_id)
- }
- }
-}
-
-impl<'a, E, S: Encoder<E>> Encodable<S, E> for &'a Flow {
- fn encode(&self, e: &mut S) -> Result<(), E> {
- e.emit_struct("flow", 0, |e| {
- try!(e.emit_struct_field("class", 0, |e| self.class().encode(e)))
- e.emit_struct_field("data", 1, |e| {
- match self.class() {
- BlockFlowClass => self.as_immutable_block().encode(e),
- InlineFlowClass => self.as_immutable_inline().encode(e),
- _ => { Ok(()) } // TODO: Support tables
- }
- })
- })
- }
-}
-
-// Base access
-
-#[inline(always)]
-pub fn base<'a>(this: &'a Flow) -> &'a BaseFlow {
- unsafe {
- let obj = mem::transmute::<&'a Flow, raw::TraitObject>(this);
- mem::transmute::<*mut (), &'a BaseFlow>(obj.data)
- }
-}
-
-/// Iterates over the children of this immutable flow.
-pub fn imm_child_iter<'a>(flow: &'a Flow) -> FlowListIterator<'a> {
- base(flow).children.iter()
-}
-
-#[inline(always)]
-pub fn mut_base<'a>(this: &'a mut Flow) -> &'a mut BaseFlow {
- unsafe {
- let obj = mem::transmute::<&'a mut Flow, raw::TraitObject>(this);
- mem::transmute::<*mut (), &'a mut BaseFlow>(obj.data)
- }
-}
-
-/// Iterates over the children of this flow.
-pub fn child_iter<'a>(flow: &'a mut Flow) -> MutFlowListIterator<'a> {
- mut_base(flow).children.mut_iter()
-}
-
-pub trait ImmutableFlowUtils {
- // Convenience functions
-
- /// Returns true if this flow is a block or a float flow.
- fn is_block_like(self) -> bool;
-
- /// Returns true if this flow is a table flow.
- fn is_table(self) -> bool;
-
- /// Returns true if this flow is a table caption flow.
- fn is_table_caption(self) -> bool;
-
- /// Returns true if this flow is a proper table child.
- fn is_proper_table_child(self) -> bool;
-
- /// Returns true if this flow is a table row flow.
- fn is_table_row(self) -> bool;
-
- /// Returns true if this flow is a table cell flow.
- fn is_table_cell(self) -> bool;
-
- /// Returns true if this flow is a table colgroup flow.
- fn is_table_colgroup(self) -> bool;
-
- /// Returns true if this flow is a table rowgroup flow.
- fn is_table_rowgroup(self) -> bool;
-
- /// Returns true if this flow is one of table-related flows.
- fn is_table_kind(self) -> bool;
-
- /// Returns true if anonymous flow is needed between this flow and child flow.
- fn need_anonymous_flow(self, child: &Flow) -> bool;
-
- /// Generates missing child flow of this flow.
- fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> FlowRef;
-
- /// Returns true if this flow has no children.
- fn is_leaf(self) -> bool;
-
- /// Returns the number of children that this flow possesses.
- fn child_count(self) -> uint;
-
- /// Return true if this flow is a Block Container.
- fn is_block_container(self) -> bool;
-
- /// Returns true if this flow is a block flow.
- fn is_block_flow(self) -> bool;
-
- /// Returns true if this flow is an inline flow.
- fn is_inline_flow(self) -> bool;
-
- /// Dumps the flow tree for debugging.
- fn dump(self);
-
- /// Dumps the flow tree for debugging, with a prefix to indicate that we're at the given level.
- fn dump_with_level(self, level: uint);
-}
-
-pub trait MutableFlowUtils {
- // Traversals
-
- /// Traverses the tree in preorder.
- fn traverse_preorder<T:PreorderFlowTraversal>(self, traversal: &mut T) -> bool;
-
- /// Traverses the tree in postorder.
- fn traverse_postorder<T:PostorderFlowTraversal>(self, traversal: &mut T) -> bool;
-
- // Mutators
-
- /// Computes the overflow region for this flow.
- fn store_overflow(self, _: &LayoutContext);
-
- /// Builds the display lists for this flow.
- fn build_display_list(self, layout_context: &LayoutContext);
-}
-
-pub trait MutableOwnedFlowUtils {
- /// Set absolute descendants for this flow.
- ///
- /// Set this flow as the Containing Block for all the absolute descendants.
- fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants);
-}
-
-#[deriving(Encodable, PartialEq, Show)]
-pub enum FlowClass {
- BlockFlowClass,
- InlineFlowClass,
- TableWrapperFlowClass,
- TableFlowClass,
- TableColGroupFlowClass,
- TableRowGroupFlowClass,
- TableRowFlowClass,
- TableCaptionFlowClass,
- TableCellFlowClass,
-}
-
-/// A top-down traversal.
-pub trait PreorderFlowTraversal {
- /// The operation to perform. Return true to continue or false to stop.
- fn process(&mut self, flow: &mut Flow) -> bool;
-
- /// Returns true if this node should be pruned. If this returns true, we skip the operation
- /// entirely and do not process any descendant nodes. This is called *before* child nodes are
- /// visited. The default implementation never prunes any nodes.
- fn should_prune(&mut self, _flow: &mut Flow) -> bool {
- false
- }
-}
-
-/// A bottom-up traversal, with a optional in-order pass.
-pub trait PostorderFlowTraversal {
- /// The operation to perform. Return true to continue or false to stop.
- fn process(&mut self, flow: &mut Flow) -> bool;
-
- /// Returns false if this node must be processed in-order. If this returns false, we skip the
- /// operation for this node, but continue processing the ancestors. This is called *after*
- /// child nodes are visited.
- fn should_process(&mut self, _flow: &mut Flow) -> bool {
- true
- }
-
- /// Returns true if this node should be pruned. If this returns true, we skip the operation
- /// entirely and do not process any descendant nodes. This is called *before* child nodes are
- /// visited. The default implementation never prunes any nodes.
- fn should_prune(&mut self, _flow: &mut Flow) -> bool {
- false
- }
-}
-
-/// Flags used in flows, tightly packed to save space.
-#[deriving(Clone, Encodable)]
-pub struct FlowFlags(pub u8);
-
-/// The bitmask of flags that represent the `has_left_floated_descendants` and
-/// `has_right_floated_descendants` fields.
-///
-/// NB: If you update this field, you must update the bitfields below.
-static HAS_FLOATED_DESCENDANTS_BITMASK: u8 = 0b0000_0011;
-
-// Whether this flow has descendants that float left in the same block formatting context.
-bitfield!(FlowFlags, has_left_floated_descendants, set_has_left_floated_descendants, 0b0000_0001)
-
-// Whether this flow has descendants that float right in the same block formatting context.
-bitfield!(FlowFlags, has_right_floated_descendants, set_has_right_floated_descendants, 0b0000_0010)
-
-// Whether this flow is impacted by floats to the left in the same block formatting context (i.e.
-// its block-size depends on some prior flows with `float: left`).
-bitfield!(FlowFlags, impacted_by_left_floats, set_impacted_by_left_floats, 0b0000_0100)
-
-// Whether this flow is impacted by floats to the right in the same block formatting context (i.e.
-// its block-size depends on some prior flows with `float: right`).
-bitfield!(FlowFlags, impacted_by_right_floats, set_impacted_by_right_floats, 0b0000_1000)
-
-/// The bitmask of flags that represent the text alignment field.
-///
-/// NB: If you update this field, you must update the bitfields below.
-static TEXT_ALIGN_BITMASK: u8 = 0b0011_0000;
-
-/// The number of bits we must shift off to handle the text alignment field.
-///
-/// NB: If you update this field, you must update the bitfields below.
-static TEXT_ALIGN_SHIFT: u8 = 4;
-
-// Whether this flow contains a flow that has its own layer within the same absolute containing
-// block.
-bitfield!(FlowFlags,
- layers_needed_for_descendants,
- set_layers_needed_for_descendants,
- 0b0100_0000)
-
-// Whether this flow must have its own layer. Even if this flag is not set, it might get its own
-// layer if it's deemed to be likely to overlap flows with their own layer.
-bitfield!(FlowFlags, needs_layer, set_needs_layer, 0b1000_0000)
-
-impl FlowFlags {
- /// Creates a new set of flow flags.
- pub fn new() -> FlowFlags {
- FlowFlags(0)
- }
-
- /// Propagates text alignment flags from an appropriate parent flow per CSS 2.1.
- ///
- /// FIXME(#2265, pcwalton): It would be cleaner and faster to make this a derived CSS property
- /// `-servo-text-align-in-effect`.
- pub fn propagate_text_alignment_from_parent(&mut self, parent_flags: FlowFlags) {
- self.set_text_align_override(parent_flags);
- }
-
- #[inline]
- pub fn text_align(self) -> text_align::T {
- let FlowFlags(ff) = self;
- FromPrimitive::from_u8((ff & TEXT_ALIGN_BITMASK) >> TEXT_ALIGN_SHIFT as uint).unwrap()
- }
-
- #[inline]
- pub fn set_text_align(&mut self, value: text_align::T) {
- let FlowFlags(ff) = *self;
- *self = FlowFlags((ff & !TEXT_ALIGN_BITMASK) | ((value as u8) << TEXT_ALIGN_SHIFT as uint))
- }
-
- #[inline]
- pub fn set_text_align_override(&mut self, parent: FlowFlags) {
- let FlowFlags(ff) = *self;
- let FlowFlags(pff) = parent;
- *self = FlowFlags(ff | (pff & TEXT_ALIGN_BITMASK))
- }
-
- #[inline]
- pub fn union_floated_descendants_flags(&mut self, other: FlowFlags) {
- let FlowFlags(my_flags) = *self;
- let FlowFlags(other_flags) = other;
- *self = FlowFlags(my_flags | (other_flags & HAS_FLOATED_DESCENDANTS_BITMASK))
- }
-
- #[inline]
- pub fn impacted_by_floats(&self) -> bool {
- self.impacted_by_left_floats() || self.impacted_by_right_floats()
- }
-}
-
-/// The Descendants of a flow.
-///
-/// Also, details about their position wrt this flow.
-pub struct Descendants {
- /// Links to every descendant. This must be private because it is unsafe to leak `FlowRef`s to
- /// layout.
- descendant_links: Vec<FlowRef>,
-
- /// Static y offsets of all descendants from the start of this flow box.
- pub static_b_offsets: Vec<Au>,
-}
-
-impl Descendants {
- pub fn new() -> Descendants {
- Descendants {
- descendant_links: Vec::new(),
- static_b_offsets: Vec::new(),
- }
- }
-
- pub fn len(&self) -> uint {
- self.descendant_links.len()
- }
-
- pub fn push(&mut self, given_descendant: FlowRef) {
- self.descendant_links.push(given_descendant);
- }
-
- /// Push the given descendants on to the existing descendants.
- ///
- /// Ignore any static y offsets, because they are None before layout.
- pub fn push_descendants(&mut self, given_descendants: Descendants) {
- for elem in given_descendants.descendant_links.move_iter() {
- self.descendant_links.push(elem);
- }
- }
-
- /// Return an iterator over the descendant flows.
- pub fn iter<'a>(&'a mut self) -> DescendantIter<'a> {
- DescendantIter {
- iter: self.descendant_links.mut_slice_from(0).mut_iter(),
- }
- }
-
- /// Return an iterator over (descendant, static y offset).
- pub fn iter_with_offset<'a>(&'a mut self) -> DescendantOffsetIter<'a> {
- let descendant_iter = DescendantIter {
- iter: self.descendant_links.mut_slice_from(0).mut_iter(),
- };
- descendant_iter.zip(self.static_b_offsets.mut_slice_from(0).mut_iter())
- }
-}
-
-pub type AbsDescendants = Descendants;
-
-pub struct DescendantIter<'a> {
- iter: MutItems<'a, FlowRef>,
-}
-
-impl<'a> Iterator<&'a mut Flow> for DescendantIter<'a> {
- fn next(&mut self) -> Option<&'a mut Flow> {
- match self.iter.next() {
- None => None,
- Some(ref mut flow) => {
- unsafe {
- let result: &'a mut Flow = mem::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
-/// confused with absolutely-positioned flows).
-#[deriving(Encodable)]
-pub struct AbsolutePositionInfo {
- /// The size of the containing block for relatively-positioned descendants.
- pub relative_containing_block_size: LogicalSize<Au>,
- /// The position of the absolute containing block.
- pub absolute_containing_block_position: Point2D<Au>,
- /// Whether the absolute containing block forces positioned descendants to be layerized.
- ///
- /// FIXME(pcwalton): Move into `FlowFlags`.
- pub layers_needed_for_positioned_flows: bool,
-}
-
-impl AbsolutePositionInfo {
- pub fn new(writing_mode: WritingMode) -> AbsolutePositionInfo {
- // FIXME(pcwalton): The initial relative containing block-size should be equal to the size
- // of the root layer.
- AbsolutePositionInfo {
- relative_containing_block_size: LogicalSize::zero(writing_mode),
- absolute_containing_block_position: Zero::zero(),
- layers_needed_for_positioned_flows: false,
- }
- }
-}
-
-/// Data common to all flows.
-pub struct BaseFlow {
- /// NB: Must be the first element.
- ///
- /// The necessity of this will disappear once we have dynamically-sized types.
- ref_count: AtomicUint,
-
- pub restyle_damage: RestyleDamage,
-
- /// The children of this flow.
- pub children: FlowList,
- pub next_sibling: Link,
- pub prev_sibling: Link,
-
- /* layout computations */
- // TODO: min/pref and position are used during disjoint phases of
- // layout; maybe combine into a single enum to save space.
- pub intrinsic_inline_sizes: IntrinsicISizes,
-
- /// The upper left corner of the box representing this flow, relative to the box representing
- /// its parent flow.
- ///
- /// For absolute flows, this represents the position with respect to its *containing block*.
- ///
- /// This does not include margins in the block flow direction, because those can collapse. So
- /// for the block direction (usually vertical), this represents the *border box*. For the
- /// inline direction (usually horizontal), this represents the *margin box*.
- pub position: LogicalRect<Au>,
-
- /// The amount of overflow of this flow, relative to the containing block. Must include all the
- /// pixels of all the display list items for correct invalidation.
- pub overflow: LogicalRect<Au>,
-
- /// Data used during parallel traversals.
- ///
- /// TODO(pcwalton): Group with other transient data to save space.
- pub parallel: FlowParallelInfo,
-
- /// The floats next to this flow.
- pub floats: Floats,
-
- /// The collapsible margins for this flow, if any.
- pub collapsible_margins: CollapsibleMargins,
-
- /// The position of this flow in page coordinates, computed during display list construction.
- pub abs_position: Point2D<Au>,
-
- /// Details about descendants with position 'absolute' or 'fixed' for which we are the
- /// containing block. This is in tree order. This includes any direct children.
- pub abs_descendants: AbsDescendants,
-
- /// Offset wrt the nearest positioned ancestor - aka the Containing Block
- /// for any absolutely positioned elements.
- pub absolute_static_i_offset: Au,
-
- /// Offset wrt the Initial Containing Block.
- pub fixed_static_i_offset: Au,
-
- /// Reference to the Containing Block, if this flow is absolutely positioned.
- pub absolute_cb: ContainingBlockLink,
-
- /// Information needed to compute absolute (i.e. viewport-relative) flow positions (not to be
- /// confused with absolutely-positioned flows).
- ///
- /// FIXME(pcwalton): Merge with `absolute_static_i_offset` and `fixed_static_i_offset` above?
- pub absolute_position_info: AbsolutePositionInfo,
-
- /// The unflattened display items for this flow.
- pub display_list: DisplayList,
-
- /// Any layers that we're bubbling up, in a linked list.
- pub layers: DList<RenderLayer>,
-
- /// Various flags for flows, tightly packed to save space.
- pub flags: FlowFlags,
-
- pub writing_mode: WritingMode,
-}
-
-impl<E, S: Encoder<E>> Encodable<S, E> for BaseFlow {
- fn encode(&self, e: &mut S) -> Result<(), E> {
- e.emit_struct("base", 0, |e| {
- try!(e.emit_struct_field("id", 0, |e| self.debug_id().encode(e)))
- try!(e.emit_struct_field("abs_position", 1, |e| self.abs_position.encode(e)))
- try!(e.emit_struct_field("intrinsic_inline_sizes", 2, |e| self.intrinsic_inline_sizes.encode(e)))
- try!(e.emit_struct_field("position", 3, |e| self.position.encode(e)))
- e.emit_struct_field("children", 4, |e| {
- e.emit_seq(self.children.len(), |e| {
- for (i, c) in self.children.iter().enumerate() {
- try!(e.emit_seq_elt(i, |e| c.encode(e)))
- }
- Ok(())
- })
-
- })
- })
- }
-}
-
-#[unsafe_destructor]
-impl Drop for BaseFlow {
- fn drop(&mut self) {
- if self.ref_count.load(SeqCst) != 0 {
- fail!("Flow destroyed before its ref count hit zero—this is unsafe!")
- }
- }
-}
-
-impl BaseFlow {
- #[inline]
- pub fn new(node: ThreadSafeLayoutNode) -> BaseFlow {
- let writing_mode = node.style().writing_mode;
- BaseFlow {
- ref_count: AtomicUint::new(1),
-
- restyle_damage: node.restyle_damage(),
-
- children: FlowList::new(),
- next_sibling: None,
- prev_sibling: None,
-
- intrinsic_inline_sizes: IntrinsicISizes::new(),
- position: LogicalRect::zero(writing_mode),
- overflow: LogicalRect::zero(writing_mode),
-
- parallel: FlowParallelInfo::new(),
-
- floats: Floats::new(writing_mode),
- collapsible_margins: CollapsibleMargins::new(),
- abs_position: Zero::zero(),
- abs_descendants: Descendants::new(),
- absolute_static_i_offset: Au::new(0),
- fixed_static_i_offset: Au::new(0),
- absolute_cb: ContainingBlockLink::new(),
- display_list: DisplayList::new(),
- layers: DList::new(),
- absolute_position_info: AbsolutePositionInfo::new(writing_mode),
-
- flags: FlowFlags::new(),
- writing_mode: writing_mode,
- }
- }
-
- pub fn child_iter<'a>(&'a mut self) -> MutFlowListIterator<'a> {
- self.children.mut_iter()
- }
-
- pub unsafe fn ref_count<'a>(&'a self) -> &'a AtomicUint {
- &self.ref_count
- }
-
- pub fn debug_id(&self) -> String {
- format!("{:p}", self as *const _)
- }
-}
-
-impl<'a> ImmutableFlowUtils for &'a Flow {
- /// Returns true if this flow is a block or a float flow.
- fn is_block_like(self) -> bool {
- match self.class() {
- BlockFlowClass => true,
- _ => false,
- }
- }
-
- /// Returns true if this flow is a proper table child.
- /// 'Proper table child' is defined as table-row flow, table-rowgroup flow,
- /// table-column-group flow, or table-caption flow.
- fn is_proper_table_child(self) -> bool {
- match self.class() {
- TableRowFlowClass | TableRowGroupFlowClass |
- TableColGroupFlowClass | TableCaptionFlowClass => true,
- _ => false,
- }
- }
-
- /// Returns true if this flow is a table row flow.
- fn is_table_row(self) -> bool {
- match self.class() {
- TableRowFlowClass => true,
- _ => false,
- }
- }
-
- /// Returns true if this flow is a table cell flow.
- fn is_table_cell(self) -> bool {
- match self.class() {
- TableCellFlowClass => true,
- _ => false,
- }
- }
-
- /// Returns true if this flow is a table colgroup flow.
- fn is_table_colgroup(self) -> bool {
- match self.class() {
- TableColGroupFlowClass => true,
- _ => false,
- }
- }
-
- /// Returns true if this flow is a table flow.
- fn is_table(self) -> bool {
- match self.class() {
- TableFlowClass => true,
- _ => false,
- }
- }
-
- /// Returns true if this flow is a table caption flow.
- fn is_table_caption(self) -> bool {
- match self.class() {
- TableCaptionFlowClass => true,
- _ => false,
- }
- }
-
- /// Returns true if this flow is a table rowgroup flow.
- fn is_table_rowgroup(self) -> bool {
- match self.class() {
- TableRowGroupFlowClass => true,
- _ => false,
- }
- }
-
- /// Returns true if this flow is one of table-related flows.
- fn is_table_kind(self) -> bool {
- match self.class() {
- TableWrapperFlowClass | TableFlowClass |
- TableColGroupFlowClass | TableRowGroupFlowClass |
- TableRowFlowClass | TableCaptionFlowClass | TableCellFlowClass => true,
- _ => false,
- }
- }
-
- /// Returns true if anonymous flow is needed between this flow and child flow.
- /// Spec: http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes
- fn need_anonymous_flow(self, child: &Flow) -> bool {
- match self.class() {
- TableFlowClass => !child.is_proper_table_child(),
- TableRowGroupFlowClass => !child.is_table_row(),
- TableRowFlowClass => !child.is_table_cell(),
- _ => false
- }
- }
-
- /// Generates missing child flow of this flow.
- fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> FlowRef {
- let flow = match self.class() {
- TableFlowClass | TableRowGroupFlowClass => {
- let fragment = Fragment::new_anonymous_table_fragment(node, TableRowFragment);
- box TableRowFlow::from_node_and_fragment(node, fragment) as Box<Flow>
- },
- TableRowFlowClass => {
- let fragment = Fragment::new_anonymous_table_fragment(node, TableCellFragment);
- box TableCellFlow::from_node_and_fragment(node, fragment) as Box<Flow>
- },
- _ => {
- fail!("no need to generate a missing child")
- }
- };
- FlowRef::new(flow)
- }
-
- /// Returns true if this flow has no children.
- fn is_leaf(self) -> bool {
- base(self).children.len() == 0
- }
-
- /// Returns the number of children that this flow possesses.
- fn child_count(self) -> uint {
- base(self).children.len()
- }
-
- /// Return true if this flow is a Block Container.
- ///
- /// Except for table fragments and replaced elements, block-level fragments (`BlockFlow`) are
- /// also block container fragments.
- /// Non-replaced inline blocks and non-replaced table cells are also block
- /// containers.
- fn is_block_container(self) -> bool {
- match self.class() {
- // TODO: Change this when inline-blocks are supported.
- BlockFlowClass | TableCaptionFlowClass | TableCellFlowClass => {
- // FIXME: Actually check the type of the node
- self.child_count() != 0
- }
- _ => false,
- }
- }
-
- /// Returns true if this flow is a block flow.
- fn is_block_flow(self) -> bool {
- match self.class() {
- BlockFlowClass => true,
- _ => false,
- }
- }
-
- /// Returns true if this flow is an inline flow.
- fn is_inline_flow(self) -> bool {
- match self.class() {
- InlineFlowClass => true,
- _ => false,
- }
- }
-
- /// Dumps the flow tree for debugging.
- fn dump(self) {
- self.dump_with_level(0)
- }
-
- /// Dumps the flow tree for debugging, with a prefix to indicate that we're at the given level.
- fn dump_with_level(self, level: uint) {
- let mut indent = String::new();
- for _ in range(0, level) {
- indent.push_str("| ")
- }
- debug!("{}+ {}", indent, self.to_string());
- for kid in imm_child_iter(self) {
- kid.dump_with_level(level + 1)
- }
- }
-}
-
-impl<'a> MutableFlowUtils for &'a mut Flow {
- /// Traverses the tree in preorder.
- fn traverse_preorder<T:PreorderFlowTraversal>(self, traversal: &mut T) -> bool {
- if traversal.should_prune(self) {
- return true
- }
-
- if !traversal.process(self) {
- return false
- }
-
- for kid in child_iter(self) {
- if !kid.traverse_preorder(traversal) {
- return false
- }
- }
-
- true
- }
-
- /// Traverses the tree in postorder.
- fn traverse_postorder<T:PostorderFlowTraversal>(self, traversal: &mut T) -> bool {
- if traversal.should_prune(self) {
- return true
- }
-
- for kid in child_iter(self) {
- if !kid.traverse_postorder(traversal) {
- return false
- }
- }
-
- if !traversal.should_process(self) {
- return true
- }
-
- traversal.process(self)
- }
-
- /// Calculate and set overflow for current flow.
- ///
- /// CSS Section 11.1
- /// This is the union of rectangles of the flows for which we define the
- /// Containing Block.
- ///
- /// Assumption: This is called in a bottom-up traversal, so kids' overflows have
- /// already been set.
- /// Assumption: Absolute descendants have had their overflow calculated.
- fn store_overflow(self, _: &LayoutContext) {
- let my_position = mut_base(self).position;
- let mut overflow = my_position;
-
- if self.is_block_container() {
- for kid in child_iter(self) {
- if kid.is_store_overflow_delayed() {
- // Absolute flows will be handled by their CB. If we are
- // their CB, they will show up in `abs_descendants`.
- continue;
- }
- let mut kid_overflow = base(kid).overflow;
- kid_overflow = kid_overflow.translate(&my_position.start);
- overflow = overflow.union(&kid_overflow)
- }
-
- // FIXME(#2004, pcwalton): This is wrong for `position: fixed`.
- for descendant_link in mut_base(self).abs_descendants.iter() {
- let mut kid_overflow = base(descendant_link).overflow;
- kid_overflow = kid_overflow.translate(&my_position.start);
- overflow = overflow.union(&kid_overflow)
- }
- }
- mut_base(self).overflow = overflow;
- }
-
- /// Push display items for current flow and its descendants onto the appropriate display lists
- /// of the given stacking context.
- ///
- /// Arguments:
- ///
- /// * `builder`: The display list builder, which contains information used during the entire
- /// display list building pass.
- ///
- /// * `info`: Per-flow display list building information.
- fn build_display_list(self, layout_context: &LayoutContext) {
- debug!("Flow: building display list");
- match self.class() {
- BlockFlowClass => self.as_block().build_display_list_block(layout_context),
- InlineFlowClass => self.as_inline().build_display_list_inline(layout_context),
- TableWrapperFlowClass => {
- self.as_table_wrapper().build_display_list_table_wrapper(layout_context)
- }
- TableFlowClass => self.as_table().build_display_list_table(layout_context),
- TableRowGroupFlowClass => {
- self.as_table_rowgroup().build_display_list_table_rowgroup(layout_context)
- }
- TableRowFlowClass => self.as_table_row().build_display_list_table_row(layout_context),
- TableCaptionFlowClass => {
- self.as_table_caption().build_display_list_table_caption(layout_context)
- }
- TableCellFlowClass => {
- self.as_table_cell().build_display_list_table_cell(layout_context)
- }
- TableColGroupFlowClass => {
- // Nothing to do here, as column groups don't render.
- }
- }
- }
-}
-
-impl MutableOwnedFlowUtils for FlowRef {
- /// Set absolute descendants for this flow.
- ///
- /// Set yourself as the Containing Block for all the absolute descendants.
- ///
- /// This is called during flow construction, so nothing else can be accessing the descendant
- /// flows. This is enforced by the fact that we have a mutable `FlowRef`, which only flow
- /// construction is allowed to possess.
- fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants) {
- let this = self.clone();
-
- let block = self.get_mut().as_block();
- block.base.abs_descendants = abs_descendants;
- block.base
- .parallel
- .children_and_absolute_descendant_count
- .fetch_add(block.base.abs_descendants.len() as int, Relaxed);
-
- for descendant_link in block.base.abs_descendants.iter() {
- let base = mut_base(descendant_link);
- base.absolute_cb.set(this.clone());
- }
- }
-}
-
-/// A link to a flow's containing block.
-///
-/// This cannot safely be a `Flow` pointer because this is a pointer *up* the tree, not *down* the
-/// tree. A pointer up the tree is unsafe during layout because it can be used to access a node
-/// with an immutable reference while that same node is being laid out, causing possible iterator
-/// invalidation and use-after-free.
-///
-/// FIXME(pcwalton): I think this would be better with a borrow flag instead of `unsafe`.
-pub struct ContainingBlockLink {
- /// The pointer up to the containing block.
- link: Option<FlowRef>,
-}
-
-impl ContainingBlockLink {
- fn new() -> ContainingBlockLink {
- ContainingBlockLink {
- link: None,
- }
- }
-
- fn set(&mut self, link: FlowRef) {
- self.link = Some(link)
- }
-
- pub unsafe fn get<'a>(&'a mut self) -> &'a mut Option<FlowRef> {
- &mut self.link
- }
-
- #[inline]
- pub fn generated_containing_block_rect(&mut self) -> LogicalRect<Au> {
- match self.link {
- None => fail!("haven't done it"),
- Some(ref mut link) => link.get_mut().generated_containing_block_rect(),
- }
- }
-}
-