Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layout: Allow inline elements to be containing blocks for absolutely-positioned elements. #5911

Merged
merged 3 commits into from May 13, 2015
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

@@ -58,6 +58,8 @@ pub mod optimizer;
/// items that involve a blur. This ensures that the display item boundaries include all the ink.
pub static BLUR_INFLATION_FACTOR: i32 = 3;

const MIN_INDENTATION_LENGTH: usize = 4;

/// An opaque handle to a node. The only safe operation that can be performed on this node is to
/// compare it to another opaque handle or to another node.
///
@@ -172,20 +174,7 @@ impl DisplayList {
}

// Print the display list. Only makes sense to call it after performing reflow.
pub fn print_items(&self, mut indentation: String) {
let min_length = 4;
// We cover the case of an empty string.
if indentation.len() == 0 {
indentation = String::from_str("####");
}

// We grow the indentation by 4 characters if needed.
// I wish to push it all as a slice, but it won't work if the string is a single char.
while indentation.len() < min_length {
let c = indentation.char_at(0);
indentation.push(c);
}

pub fn print_items(&self, indentation: String) {
// Closures are so nice!
let doit = |items: &Vec<DisplayItem>| {
for item in items.iter() {
@@ -221,8 +210,9 @@ impl DisplayList {
println!("{} Children stacking contexts list length: {}",
indentation,
self.children.len());
for sublist in self.children.iter() {
sublist.display_list.print_items(indentation.clone()+&indentation[0..min_length]);
for stacking_context in self.children.iter() {
stacking_context.print(indentation.clone() +
&indentation[0..MIN_INDENTATION_LENGTH]);
}
}
}
@@ -250,6 +240,7 @@ pub struct StackingContext {

/// The position and size of this stacking context.
pub bounds: Rect<Au>,

/// The overflow rect for this stacking context in its coordinate system.
pub overflow: Rect<Au>,

@@ -571,6 +562,27 @@ impl StackingContext {
topmost_only,
self.display_list.background_and_borders.iter().rev())
}

pub fn print(&self, mut indentation: String) {
// We cover the case of an empty string.
if indentation.len() == 0 {
indentation = String::from_str("####");
}

// We grow the indentation by 4 characters if needed.
// I wish to push it all as a slice, but it won't work if the string is a single char.
while indentation.len() < MIN_INDENTATION_LENGTH {
let c = indentation.char_at(0);
indentation.push(c);
}

println!("{:?} Stacking context at {:?} with overflow {:?}:",
indentation,
self.bounds,
self.overflow);

self.display_list.print_items(indentation);
}
}

impl HeapSizeOf for StackingContext {
@@ -33,7 +33,7 @@ use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
use display_list_builder::{FragmentDisplayListBuilding};
use floats::{ClearType, FloatKind, Floats, PlacementInfo};
use flow::{self, AbsolutePositionInfo, BaseFlow, ForceNonfloatedFlag, FlowClass, Flow};
use flow::{ImmutableFlowUtils, PreorderFlowTraversal};
use flow::{ImmutableFlowUtils, MutableFlowUtils, OpaqueFlow, PreorderFlowTraversal};
use flow::{PostorderFlowTraversal, mut_base};
use flow::{BLOCK_POSITION_IS_STATIC, HAS_LEFT_FLOATED_DESCENDANTS, HAS_RIGHT_FLOATED_DESCENDANTS};
use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS, INLINE_POSITION_IS_STATIC};
@@ -433,26 +433,31 @@ fn translate_including_floats(cur_b: &mut Au, delta: Au, floats: &mut Floats) {
///
/// Note that flows with position 'fixed' just form a flat list as they all
/// have the Root flow as their CB.
struct AbsoluteAssignBSizesTraversal<'a>(&'a LayoutContext<'a>);
pub struct AbsoluteAssignBSizesTraversal<'a>(pub &'a LayoutContext<'a>);

impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> {
#[inline]
fn process(&self, flow: &mut Flow) {
let block_flow = flow.as_block();

// The root of the absolute flow tree is definitely not absolutely
// positioned. Nothing to process here.
if block_flow.is_root_of_absolute_flow_tree() {
return;
{
// The root of the absolute flow tree is definitely not absolutely
// positioned. Nothing to process here.
let flow: &Flow = flow;
if flow.contains_roots_of_absolute_flow_tree() {
return;
}
if !flow.is_block_like() {
return
}
}

assert!(block_flow.base.flags.contains(IS_ABSOLUTELY_POSITIONED));
if !block_flow.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) {
let block = flow.as_block();
debug_assert!(block.base.flags.contains(IS_ABSOLUTELY_POSITIONED));
if !block.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) {
return
}

let AbsoluteAssignBSizesTraversal(ref layout_context) = *self;
block_flow.calculate_absolute_block_size_and_margins(*layout_context);
block.calculate_absolute_block_size_and_margins(*layout_context);
}
}

@@ -462,16 +467,19 @@ impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> {
/// not including the root of the Absolute flow tree.
/// After that, it is up to the normal store-overflow traversal to propagate
/// it further up.
struct AbsoluteStoreOverflowTraversal<'a>{
layout_context: &'a LayoutContext<'a>,
pub struct AbsoluteStoreOverflowTraversal<'a>{
pub layout_context: &'a LayoutContext<'a>,
}

impl<'a> PostorderFlowTraversal for AbsoluteStoreOverflowTraversal<'a> {
#[inline]
fn process(&self, flow: &mut Flow) {
// This will be taken care of by the normal store-overflow traversal.
if flow.is_root_of_absolute_flow_tree() {
return;
{
// This will be taken care of by the normal store-overflow traversal.
let flow: &Flow = flow;
if flow.contains_roots_of_absolute_flow_tree() {
return;
}
}

flow.store_overflow(self.layout_context);
@@ -656,56 +664,23 @@ impl BlockFlow {
&mut self.fragment
}

/// Return the size of the Containing Block for this flow.
/// Return the size of the containing block for the given immediate absolute descendant of this
/// flow.
///
/// Right now, this only gets the Containing Block size for absolutely
/// positioned elements.
/// Note: Assume this is called in a top-down traversal, so it is ok to
/// reference the CB.
/// Right now, this only gets the containing block size for absolutely positioned elements.
/// Note: We assume this is called in a top-down traversal, so it is ok to reference the CB.
#[inline]
pub fn containing_block_size(&mut self, viewport_size: Size2D<Au>) -> LogicalSize<Au> {
pub fn containing_block_size(&mut self, viewport_size: &Size2D<Au>, descendant: OpaqueFlow)
-> LogicalSize<Au> {
debug_assert!(self.base.flags.contains(IS_ABSOLUTELY_POSITIONED));
if self.is_fixed() {
// Initial containing block is the CB for the root
LogicalSize::from_physical(self.base.writing_mode, viewport_size)
LogicalSize::from_physical(self.base.writing_mode, *viewport_size)
} else {
self.base.absolute_cb.generated_containing_block_rect().size
}
}

/// 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 {
let flow = self as &mut Flow;

traversal.process(flow);

let descendant_offset_iter = mut_base(flow).abs_descendants.iter();
for ref mut descendant_link in descendant_offset_iter {
descendant_link.as_block().traverse_preorder_absolute_flows(traversal)
self.base.absolute_cb.generated_containing_block_size(descendant)
}
}

/// 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 {
let flow = self as &mut Flow;

for descendant_link in mut_base(flow).abs_descendants.iter() {
let block = descendant_link.as_block();
block.traverse_postorder_absolute_flows(traversal);
}

traversal.process(flow)
}

/// Return true if this has a replaced fragment.
///
/// Text, Images, Inline Block and
@@ -1006,16 +981,17 @@ impl BlockFlow {
}
}

if self.is_root_of_absolute_flow_tree() {
if (&*self as &Flow).contains_roots_of_absolute_flow_tree() {
// Assign block-sizes for all flows in this absolute flow tree.
// This is preorder because the block-size of an absolute flow may depend on
// the block-size of its containing block, which may also be an absolute flow.
self.traverse_preorder_absolute_flows(&mut AbsoluteAssignBSizesTraversal(
layout_context));
(&mut *self as &mut Flow).traverse_preorder_absolute_flows(
&mut AbsoluteAssignBSizesTraversal(layout_context));
// Store overflow for all absolute descendants.
self.traverse_postorder_absolute_flows(&mut AbsoluteStoreOverflowTraversal {
layout_context: layout_context,
});
(&mut *self as &mut Flow).traverse_postorder_absolute_flows(
&mut AbsoluteStoreOverflowTraversal {
layout_context: layout_context,
});
}

// Don't remove the dirty bits yet if we're absolutely-positioned, since our final size
@@ -1086,8 +1062,10 @@ impl BlockFlow {
/// + block-size for the flow
/// + position in the block direction of the flow with respect to its Containing Block.
/// + block-size, vertical margins, and y-coordinate for the flow's box.
fn calculate_absolute_block_size_and_margins(&mut self, ctx: &LayoutContext) {
let containing_block_block_size = self.containing_block_size(ctx.shared.screen_size).block;
fn calculate_absolute_block_size_and_margins(&mut self, layout_context: &LayoutContext) {
let opaque_self = OpaqueFlow::from_flow(self);
let containing_block_block_size =
self.containing_block_size(&layout_context.shared.screen_size, opaque_self).block;

// This is the stored content block-size value from assign-block-size
let content_block_size = self.fragment.border_box.size.block;
@@ -1250,8 +1228,9 @@ impl BlockFlow {
};

// Calculate containing block inline size.
let opaque_self = OpaqueFlow::from_flow(self);
let containing_block_size = if flags.contains(IS_ABSOLUTELY_POSITIONED) {
self.containing_block_size(layout_context.shared.screen_size).inline
self.containing_block_size(&layout_context.shared.screen_size, opaque_self).inline
} else {
content_inline_size
};
@@ -1724,13 +1703,15 @@ impl Flow for BlockFlow {
self.fragment.relative_position(&self.base
.absolute_position_info
.relative_containing_block_size);
if self.is_positioned() {
if self.contains_positioned_fragments() {
let border_box_origin = (self.fragment.border_box -
self.fragment.style.logical_border_width()).start;
self.base
.absolute_position_info
.stacking_relative_position_of_absolute_containing_block =
self.base.stacking_relative_position +
(self.generated_containing_block_rect().start +
relative_offset).to_physical(self.base.writing_mode, container_size)
(border_box_origin + relative_offset).to_physical(self.base.writing_mode,
container_size)
}

// Compute absolute position info for children.
@@ -1741,7 +1722,7 @@ impl Flow for BlockFlow {
logical_border_width.inline_start,
logical_border_width.block_start);
let position = position.to_physical(self.base.writing_mode, container_size);
if self.is_positioned() {
if self.contains_positioned_fragments() {
position
} else {
// We establish a stacking context but are not positioned. (This will happen
@@ -1850,17 +1831,10 @@ impl Flow for BlockFlow {
self.fragment.style.get_box().position
}

/// Return true if this is the root of an Absolute flow tree.
///
/// It has to be either relatively positioned or the Root flow.
fn is_root_of_absolute_flow_tree(&self) -> bool {
self.is_relatively_positioned() || self.is_root()
}

/// 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> {
self.fragment.border_box - self.fragment.style().logical_border_width()
fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au> {
(self.fragment.border_box - self.fragment.style().logical_border_width()).size
}

fn layer_id(&self, fragment_index: u32) -> LayerId {
@@ -1871,7 +1845,7 @@ impl Flow for BlockFlow {
}

fn is_absolute_containing_block(&self) -> bool {
self.is_positioned()
self.contains_positioned_fragments()
}

fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
@@ -2491,7 +2465,8 @@ impl ISizeAndMarginsComputer for AbsoluteNonReplaced {
_: Au,
layout_context: &LayoutContext)
-> Au {
block.containing_block_size(layout_context.shared.screen_size).inline
let opaque_block = OpaqueFlow::from_flow(block);
block.containing_block_size(&layout_context.shared.screen_size, opaque_block).inline
}

fn set_inline_position_of_flow_if_necessary(&self,
@@ -2601,18 +2576,23 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
_: Au,
layout_context: &LayoutContext)
-> MaybeAuto {
let opaque_block = OpaqueFlow::from_flow(block);
let containing_block_inline_size =
block.containing_block_size(layout_context.shared.screen_size).inline;
block.containing_block_size(&layout_context.shared.screen_size, opaque_block).inline;
let fragment = block.fragment();
fragment.assign_replaced_inline_size_if_necessary(containing_block_inline_size);
// For replaced absolute flow, the rest of the constraint solving will
// take inline-size to be specified as the value computed here.
MaybeAuto::Specified(fragment.content_inline_size())
}

fn containing_block_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &LayoutContext)
fn containing_block_inline_size(&self,
block: &mut BlockFlow,
_: Au,
layout_context: &LayoutContext)
-> Au {
block.containing_block_size(ctx.shared.screen_size).inline
let opaque_block = OpaqueFlow::from_flow(block);
block.containing_block_size(&layout_context.shared.screen_size, opaque_block).inline
}

fn set_inline_position_of_flow_if_necessary(&self,
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.