layout: Allow inline elements to be containing blocks for

absolutely-positioned elements.

This also implements a little bit of the infrastructure needed to
support for fragmentation via support for multiple positioned fragments
in one flow.

Improves Google.
This commit is contained in:
Patrick Walton 2015-04-30 16:44:59 -07:00
parent b3b9deafa7
commit 1f0b5889da
19 changed files with 592 additions and 241 deletions

View file

@ -324,19 +324,15 @@ pub trait Flow: fmt::Debug + Sync {
self.positioning() == position::T::fixed
}
fn is_positioned(&self) -> bool {
self.is_relatively_positioned() || base(self).flags.contains(IS_ABSOLUTELY_POSITIONED)
fn contains_positioned_fragments(&self) -> bool {
self.contains_relatively_positioned_fragments() ||
base(self).flags.contains(IS_ABSOLUTELY_POSITIONED)
}
fn is_relatively_positioned(&self) -> bool {
fn contains_relatively_positioned_fragments(&self) -> bool {
self.positioning() == position::T::relative
}
/// 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
@ -350,14 +346,12 @@ pub trait Flow: fmt::Debug + Sync {
/// this is only used for absolutely-positioned inline-blocks.
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au);
/// Return the dimensions of the containing block generated by this flow for absolutely-
/// positioned descendants. For block flows, this is the padding box.
/// Return the size of the containing block generated by this flow for the absolutely-
/// positioned descendant referenced by `for_flow`. For block flows, this is the padding box.
///
/// NB: Do not change this `&self` to `&mut self` under any circumstances! It has security
/// implications because this can be called on parents concurrently from descendants!
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
panic!("generated_containing_block_rect not yet implemented for this flow")
}
fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au>;
/// Returns a layer ID for the given fragment.
#[allow(unsafe_code)]
@ -440,6 +434,9 @@ pub trait ImmutableFlowUtils {
/// Generates missing child flow of this flow.
fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> FlowRef;
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
fn contains_roots_of_absolute_flow_tree(&self) -> bool;
/// Returns true if this flow has no children.
fn is_leaf(self) -> bool;
@ -471,6 +468,21 @@ pub trait MutableFlowUtils {
/// Traverses the tree in postorder.
fn traverse_postorder<T:PostorderFlowTraversal>(self, traversal: &T);
/// Traverse the Absolute flow tree in preorder.
///
/// Traverse all your direct absolute descendants, who will then traverse
/// their direct absolute descendants.
///
/// Return true if the traversal is to continue or false to stop.
fn traverse_preorder_absolute_flows<T>(&mut self, traversal: &mut T)
where T: PreorderFlowTraversal;
/// Traverse the Absolute flow tree in postorder.
///
/// Return true if the traversal is to continue or false to stop.
fn traverse_postorder_absolute_flows<T>(&mut self, traversal: &mut T)
where T: PostorderFlowTraversal;
// Mutators
/// Calls `repair_style` and `bubble_inline_sizes`. You should use this method instead of
@ -1183,6 +1195,11 @@ impl<'a> ImmutableFlowUtils for &'a (Flow + 'a) {
FlowRef::new(flow)
}
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
self.contains_relatively_positioned_fragments() || self.is_root()
}
/// Returns true if this flow has no children.
fn is_leaf(self) -> bool {
base(self).children.len() == 0
@ -1276,6 +1293,34 @@ impl<'a> MutableFlowUtils for &'a mut (Flow + 'a) {
self.repair_style(style);
self.bubble_inline_sizes();
}
/// Traverse the Absolute flow tree in preorder.
///
/// Traverse all your direct absolute descendants, who will then traverse
/// their direct absolute descendants.
///
/// Return true if the traversal is to continue or false to stop.
fn traverse_preorder_absolute_flows<T>(&mut self, traversal: &mut T)
where T: PreorderFlowTraversal {
traversal.process(*self);
let descendant_offset_iter = mut_base(*self).abs_descendants.iter();
for ref mut descendant_link in descendant_offset_iter {
descendant_link.traverse_preorder_absolute_flows(traversal)
}
}
/// Traverse the Absolute flow tree in postorder.
///
/// Return true if the traversal is to continue or false to stop.
fn traverse_postorder_absolute_flows<T>(&mut self, traversal: &mut T)
where T: PostorderFlowTraversal {
for mut descendant_link in mut_base(*self).abs_descendants.iter() {
descendant_link.traverse_postorder_absolute_flows(traversal);
}
traversal.process(*self)
}
}
impl MutableOwnedFlowUtils for FlowRef {
@ -1288,13 +1333,11 @@ impl MutableOwnedFlowUtils for FlowRef {
/// construction is allowed to possess.
fn set_absolute_descendants(&mut self, abs_descendants: AbsDescendants) {
let this = self.clone();
let block = self.as_block();
block.base.abs_descendants = abs_descendants;
for descendant_link in block.base.abs_descendants.iter() {
let base = mut_base(descendant_link);
base.absolute_cb.set(this.clone());
let base = mut_base(&mut **self);
base.abs_descendants = abs_descendants;
for descendant_link in base.abs_descendants.iter() {
let descendant_base = mut_base(descendant_link);
descendant_base.absolute_cb.set(this.clone());
}
}
}
@ -1329,10 +1372,33 @@ impl ContainingBlockLink {
}
#[inline]
pub fn generated_containing_block_rect(&mut self) -> LogicalRect<Au> {
pub fn generated_containing_block_size(&mut self, for_flow: OpaqueFlow) -> LogicalSize<Au> {
match self.link {
None => panic!("haven't done it"),
Some(ref mut link) => link.generated_containing_block_rect(),
None => {
panic!("Link to containing block not established; perhaps you forgot to call \
`set_absolute_descendants`?")
}
Some(ref mut link) => link.generated_containing_block_size(for_flow),
}
}
}
/// A wrapper for the pointer address of a flow. These pointer addresses may only be compared for
/// equality with other such pointer addresses, never dereferenced.
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct OpaqueFlow(pub usize);
impl OpaqueFlow {
#[allow(unsafe_code)]
pub fn from_flow(flow: &Flow) -> OpaqueFlow {
unsafe {
let object = mem::transmute::<&Flow,raw::TraitObject>(flow);
OpaqueFlow(object.data as usize)
}
}
pub fn from_base_flow(base_flow: &BaseFlow) -> OpaqueFlow {
OpaqueFlow(base_flow as *const BaseFlow as usize)
}
}