diff options
Diffstat (limited to 'src/components/main/layout/flow.rs')
-rw-r--r-- | src/components/main/layout/flow.rs | 294 |
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; |