aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/main/layout/flow.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/main/layout/flow.rs')
-rw-r--r--src/components/main/layout/flow.rs294
1 files changed, 274 insertions, 20 deletions
diff --git a/src/components/main/layout/flow.rs b/src/components/main/layout/flow.rs
index 182a6ccb91b..d8abda6d7e8 100644
--- a/src/components/main/layout/flow.rs
+++ b/src/components/main/layout/flow.rs
@@ -29,6 +29,7 @@ use css::node_style::StyledNode;
use layout::block::{BlockFlow};
use layout::box_::Box;
use layout::context::LayoutContext;
+use layout::construct::OptVector;
use layout::display_list_builder::{DisplayListBuilder, ExtraDisplayListData};
use layout::floats::Floats;
use layout::incremental::RestyleDamage;
@@ -45,12 +46,15 @@ use geom::rect::Rect;
use gfx::display_list::{ClipDisplayItemClass, DisplayListCollection, DisplayList};
use layout::display_list_builder::ToGfxColor;
use gfx::color::Color;
+use servo_util::smallvec::{SmallVec, SmallVec0};
use servo_util::geometry::Au;
use std::cast;
use std::cell::RefCell;
use std::sync::atomics::Relaxed;
+use std::vec::VecMutIterator;
+use std::iter::Zip;
use style::ComputedValues;
-use style::computed_values::text_align;
+use style::computed_values::{text_align, position};
/// Virtual methods that make up a float context.
///
@@ -116,6 +120,63 @@ pub trait Flow {
/// 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
+ }
+
+ /// Return the dimensions of the CB generated _by_ this flow for absolute descendants.
+ fn generated_cb_size(&self) -> Size2D<Au> {
+ fail!("generated_cb_size not yet implemented")
+ }
+
+ /// Return position of the CB generated by this flow from the start of this flow.
+ fn generated_cb_position(&self) -> Point2D<Au> {
+ fail!("this is not the CB-generating flow you're looking for")
+ }
+
/// Returns a debugging string describing this flow.
fn debug_str(&self) -> ~str {
~"???"
@@ -231,6 +292,16 @@ pub trait MutableOwnedFlowUtils {
/// properly computed. (This is not, however, a memory safety problem.)
fn finish(&mut self, context: &mut LayoutContext);
+ /// Set absolute descendants for this flow.
+ ///
+ /// Set this flow as the Containing Block for all the absolute descendants.
+ fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants);
+
+ /// Set fixed descendants for this flow.
+ ///
+ /// Set yourself as the Containing Block for all the fixed descendants.
+ fn set_fixed_descendants(&mut self, fixed_descendants: AbsDescendants);
+
/// Destroys the flow.
fn destroy(&mut self);
}
@@ -484,6 +555,61 @@ impl FlowFlags {
}
}
+/// The Descendants of a flow.
+///
+/// Also, details about their position wrt this flow.
+/// FIXME: This should use @pcwalton's reference counting scheme (Coming Soon).
+pub struct Descendants {
+ /// Links to every Descendant.
+ descendant_links: SmallVec0<Rawlink>,
+ /// Static y offsets of all descendants from the start of this flow box.
+ static_y_offsets: SmallVec0<Au>,
+}
+
+impl Descendants {
+ pub fn new() -> Descendants {
+ Descendants {
+ descendant_links: SmallVec0::new(),
+ static_y_offsets: SmallVec0::new(),
+ }
+ }
+
+ pub fn len(&self) -> uint {
+ self.descendant_links.len()
+ }
+
+ pub fn push(&mut self, given_descendant: Rawlink) {
+ 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, mut 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> {
+ self.descendant_links.mut_slice_from(0).mut_iter()
+ }
+
+ /// Return an iterator over (descendant, static y offset).
+ pub fn iter_with_offset<'a>(&'a mut self) -> DescendantOffsetIter<'a> {
+ self.descendant_links.mut_slice_from(0).mut_iter().zip(
+ self.static_y_offsets.mut_slice_from(0).mut_iter())
+ }
+}
+
+pub type AbsDescendants = Descendants;
+pub type FixedDescendants = Descendants;
+
+type DescendantIter<'a> = VecMutIterator<'a, Rawlink>;
+
+type DescendantOffsetIter<'a> = Zip<VecMutIterator<'a, Rawlink>, VecMutIterator<'a, Au>>;
+
/// Data common to all flows.
pub struct BaseFlow {
restyle_damage: RestyleDamage,
@@ -526,6 +652,22 @@ pub struct BaseFlow {
/// The position of this flow in page coordinates, computed during display list construction.
abs_position: Point2D<Au>,
+ /// Details about descendants with position 'absolute' for which we are
+ /// the CB. This is in tree order. This includes any direct children.
+ abs_descendants: AbsDescendants,
+ /// Details about descendants with position 'fixed'.
+ /// TODO: Optimize this, because this will be set only for the root.
+ fixed_descendants: FixedDescendants,
+
+ /// Offset wrt the nearest positioned ancestor - aka the Containing Block
+ /// for any absolutely positioned elements.
+ absolute_static_x_offset: Au,
+ /// Offset wrt the Initial Containing Block.
+ fixed_static_x_offset: Au,
+
+ /// Reference to the Containing Block, if this flow is absolutely positioned.
+ absolute_cb: Rawlink,
+
/// Whether this flow has been destroyed.
///
/// TODO(pcwalton): Pack this into the flags? Need to be careful because manipulation of this
@@ -582,6 +724,11 @@ impl BaseFlow {
floats: Floats::new(),
num_floats: 0,
abs_position: Point2D(Au::new(0), Au::new(0)),
+ abs_descendants: Descendants::new(),
+ fixed_descendants: Descendants::new(),
+ absolute_static_x_offset: Au::new(0),
+ fixed_static_x_offset: Au::new(0),
+ absolute_cb: Rawlink::none(),
destroyed: false,
@@ -716,25 +863,53 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
/// Calculate and set overflow for current flow.
///
/// CSS Section 11.1
- /// This is ideally the union of all flows for which we define the
+ /// 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.
- /// So, currently this is a union of the overflows of all kids and our own
- /// flow rectangle.
- /// FIXME: Handle the overflow of absolute flow descendants, because their
- /// assign-heights happen after the normal
- /// assign-height-and-store-overflow traversal
+ /// Assumption: Absolute descendants have had their overflow calculated.
fn store_overflow(self, _: &mut LayoutContext) {
let my_position = mut_base(self).position;
let mut overflow = my_position;
- for kid in mut_base(self).child_iter() {
- let mut kid_overflow = base(kid).overflow;
- kid_overflow = kid_overflow.translate(&my_position.origin);
- overflow = overflow.union(&kid_overflow)
+
+ 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.origin);
+ overflow = overflow.union(&kid_overflow)
+ }
+
+ for descendant_link in mut_base(self).abs_descendants.iter() {
+ match descendant_link.resolve() {
+ Some(flow) => {
+ let mut kid_overflow = base(flow).overflow;
+ kid_overflow = kid_overflow.translate(&my_position.origin);
+ overflow = overflow.union(&kid_overflow)
+ }
+ None => fail!("empty Rawlink to a descendant")
+ }
+ }
+
+ if self.is_root() {
+ for fixed_descendant_link in mut_base(self).fixed_descendants.iter() {
+ match fixed_descendant_link.resolve() {
+ Some(flow) => {
+ let mut kid_overflow = base(flow).overflow;
+ kid_overflow = kid_overflow.translate(&my_position.origin);
+ overflow = overflow.union(&kid_overflow)
+ }
+ None => fail!("empty Rawlink to a descendant")
+ }
+ }
+ }
}
- mut_base(self).overflow = overflow
+ mut_base(self).overflow = overflow;
}
/// Push display items for current flow and its children onto `list`.
@@ -773,23 +948,21 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
}
if self.is_block_container() {
+ let block = self.as_block();
let mut child_lists = DisplayListCollection::new();
child_lists.add_list(DisplayList::new());
let child_lists = RefCell::new(child_lists);
- let is_positioned = self.as_block().is_positioned();
let container_block_size;
let abs_cb_position;
- let flow_pos = base(self).abs_position;
- match self.as_block().box_ {
+ // TODO(pradeep): Move this into a generated CB function and stuff in Flow.
+ match block.box_ {
Some(ref box_) => {
// FIXME: This should be the size of the content box (which is the
// Containing Block formed by a BlockFlow), not the border box.
container_block_size = box_.border_box.get().size;
- abs_cb_position = if is_positioned {
- let padding_box_pos = flow_pos + box_.border_box.get().origin
- + Point2D(box_.border.get().left, box_.border.get().top);
- padding_box_pos
+ abs_cb_position = if block.is_positioned() {
+ block.base.abs_position + block.generated_cb_position()
} else {
absolute_cb_abs_position
};
@@ -797,12 +970,48 @@ impl<'a> MutableFlowUtils for &'a mut Flow {
None => fail!("Flow: block container should have a box_")
}
- for kid in child_iter(self) {
+ for kid in block.base.child_iter() {
+ if kid.is_absolutely_positioned() {
+ // All absolute flows will be handled by their CB.
+ continue;
+ }
kid.build_display_lists(builder, &container_block_size,
abs_cb_position,
dirty, 0u, &child_lists);
}
+ // TODO: Maybe we should handle position 'absolute' and 'fixed'
+ // descendants before normal descendants just in case there is a
+ // problem when display-list building is parallel and both the
+ // original parent and this flow access the same absolute flow.
+ // Note that this can only be done once we have paint order
+ // working cos currently the later boxes paint over the absolute
+ // and fixed boxes :|
+ for abs_descendant_link in block.base.abs_descendants.iter() {
+ match abs_descendant_link.resolve() {
+ Some(flow) => {
+ // TODO(pradeep): Send in your abs_position directly.
+ flow.build_display_lists(builder, &container_block_size,
+ abs_cb_position,
+ dirty, 0u, &child_lists);
+ }
+ None => fail!("empty Rawlink to a descendant")
+ }
+ }
+
+ if block.is_root() {
+ for fixed_descendant_link in block.base.fixed_descendants.iter() {
+ match fixed_descendant_link.resolve() {
+ Some(flow) => {
+ flow.build_display_lists(builder, &container_block_size,
+ abs_cb_position,
+ dirty, 0u, &child_lists);
+ }
+ None => fail!("empty Rawlink to a descendant")
+ }
+ }
+ }
+
let mut child_lists = Some(child_lists.unwrap());
// Find parent ClipDisplayItemClass and push all child display items
// under it
@@ -863,6 +1072,51 @@ impl MutableOwnedFlowUtils for ~Flow {
}
}
+ /// Set absolute descendants for this flow.
+ ///
+ /// Set yourself as the Containing Block for all the absolute descendants.
+ ///
+ /// Assumption: This is called in a bottom-up traversal, so that nothing
+ /// else is accessing the descendant flows.
+ fn set_abs_descendants(&mut self, abs_descendants: AbsDescendants) {
+ let self_link = Rawlink::some(*self);
+ let block = self.as_block();
+ block.base.abs_descendants = abs_descendants;
+
+ for descendant_link in block.base.abs_descendants.iter() {
+ match descendant_link.resolve() {
+ Some(flow) => {
+ let base = mut_base(flow);
+ base.absolute_cb = self_link.clone();
+ }
+ None => fail!("empty Rawlink to a descendant")
+ }
+ }
+ }
+
+ /// Set fixed descendants for this flow.
+ ///
+ /// Set yourself as the Containing Block for all the fixed descendants.
+ ///
+ /// Assumption: This is called in a bottom-up traversal, so that nothing
+ /// else is accessing the descendant flows.
+ /// Assumption: This is the root flow.
+ fn set_fixed_descendants(&mut self, fixed_descendants: FixedDescendants) {
+ let self_link = Rawlink::some(*self);
+ let block = self.as_block();
+ block.base.fixed_descendants = fixed_descendants;
+
+ for descendant_link in block.base.fixed_descendants.iter() {
+ match descendant_link.resolve() {
+ Some(flow) => {
+ let base = mut_base(flow);
+ base.absolute_cb = self_link.clone();
+ }
+ None => fail!("empty Rawlink to a descendant")
+ }
+ }
+ }
+
/// Destroys the flow.
fn destroy(&mut self) {
let self_borrowed: &mut Flow = *self;