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

@ -33,7 +33,7 @@ use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
use display_list_builder::{FragmentDisplayListBuilding}; use display_list_builder::{FragmentDisplayListBuilding};
use floats::{ClearType, FloatKind, Floats, PlacementInfo}; use floats::{ClearType, FloatKind, Floats, PlacementInfo};
use flow::{self, AbsolutePositionInfo, BaseFlow, ForceNonfloatedFlag, FlowClass, Flow}; 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::{PostorderFlowTraversal, mut_base};
use flow::{BLOCK_POSITION_IS_STATIC, HAS_LEFT_FLOATED_DESCENDANTS, HAS_RIGHT_FLOATED_DESCENDANTS}; 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}; 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 /// Note that flows with position 'fixed' just form a flat list as they all
/// have the Root flow as their CB. /// 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> { impl<'a> PreorderFlowTraversal for AbsoluteAssignBSizesTraversal<'a> {
#[inline] #[inline]
fn process(&self, flow: &mut Flow) { fn process(&self, flow: &mut Flow) {
let block_flow = flow.as_block(); {
// The root of the absolute flow tree is definitely not absolutely
// The root of the absolute flow tree is definitely not absolutely // positioned. Nothing to process here.
// positioned. Nothing to process here. let flow: &Flow = flow;
if block_flow.is_root_of_absolute_flow_tree() { if flow.contains_roots_of_absolute_flow_tree() {
return; return;
}
if !flow.is_block_like() {
return
}
} }
assert!(block_flow.base.flags.contains(IS_ABSOLUTELY_POSITIONED)); let block = flow.as_block();
if !block_flow.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) { debug_assert!(block.base.flags.contains(IS_ABSOLUTELY_POSITIONED));
if !block.base.restyle_damage.intersects(REFLOW_OUT_OF_FLOW | REFLOW) {
return return
} }
let AbsoluteAssignBSizesTraversal(ref layout_context) = *self; 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. /// not including the root of the Absolute flow tree.
/// After that, it is up to the normal store-overflow traversal to propagate /// After that, it is up to the normal store-overflow traversal to propagate
/// it further up. /// it further up.
struct AbsoluteStoreOverflowTraversal<'a>{ pub struct AbsoluteStoreOverflowTraversal<'a>{
layout_context: &'a LayoutContext<'a>, pub layout_context: &'a LayoutContext<'a>,
} }
impl<'a> PostorderFlowTraversal for AbsoluteStoreOverflowTraversal<'a> { impl<'a> PostorderFlowTraversal for AbsoluteStoreOverflowTraversal<'a> {
#[inline] #[inline]
fn process(&self, flow: &mut Flow) { 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() { // This will be taken care of by the normal store-overflow traversal.
return; let flow: &Flow = flow;
if flow.contains_roots_of_absolute_flow_tree() {
return;
}
} }
flow.store_overflow(self.layout_context); flow.store_overflow(self.layout_context);
@ -656,56 +664,23 @@ impl BlockFlow {
&mut self.fragment &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 /// Right now, this only gets the containing block size for absolutely positioned elements.
/// positioned elements. /// Note: We assume this is called in a top-down traversal, so it is ok to reference the CB.
/// Note: Assume this is called in a top-down traversal, so it is ok to
/// reference the CB.
#[inline] #[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)); debug_assert!(self.base.flags.contains(IS_ABSOLUTELY_POSITIONED));
if self.is_fixed() { if self.is_fixed() {
// Initial containing block is the CB for the root // 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 { } else {
self.base.absolute_cb.generated_containing_block_rect().size self.base.absolute_cb.generated_containing_block_size(descendant)
} }
} }
/// 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)
}
}
/// 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. /// Return true if this has a replaced fragment.
/// ///
/// Text, Images, Inline Block and /// 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. // 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 // 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. // the block-size of its containing block, which may also be an absolute flow.
self.traverse_preorder_absolute_flows(&mut AbsoluteAssignBSizesTraversal( (&mut *self as &mut Flow).traverse_preorder_absolute_flows(
layout_context)); &mut AbsoluteAssignBSizesTraversal(layout_context));
// Store overflow for all absolute descendants. // Store overflow for all absolute descendants.
self.traverse_postorder_absolute_flows(&mut AbsoluteStoreOverflowTraversal { (&mut *self as &mut Flow).traverse_postorder_absolute_flows(
layout_context: layout_context, &mut AbsoluteStoreOverflowTraversal {
}); layout_context: layout_context,
});
} }
// Don't remove the dirty bits yet if we're absolutely-positioned, since our final size // 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 /// + block-size for the flow
/// + position in the block direction of the flow with respect to its Containing Block. /// + 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. /// + block-size, vertical margins, and y-coordinate for the flow's box.
fn calculate_absolute_block_size_and_margins(&mut self, ctx: &LayoutContext) { fn calculate_absolute_block_size_and_margins(&mut self, layout_context: &LayoutContext) {
let containing_block_block_size = self.containing_block_size(ctx.shared.screen_size).block; 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 // This is the stored content block-size value from assign-block-size
let content_block_size = self.fragment.border_box.size.block; let content_block_size = self.fragment.border_box.size.block;
@ -1250,8 +1228,9 @@ impl BlockFlow {
}; };
// Calculate containing block inline size. // Calculate containing block inline size.
let opaque_self = OpaqueFlow::from_flow(self);
let containing_block_size = if flags.contains(IS_ABSOLUTELY_POSITIONED) { 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 { } else {
content_inline_size content_inline_size
}; };
@ -1724,13 +1703,15 @@ impl Flow for BlockFlow {
self.fragment.relative_position(&self.base self.fragment.relative_position(&self.base
.absolute_position_info .absolute_position_info
.relative_containing_block_size); .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 self.base
.absolute_position_info .absolute_position_info
.stacking_relative_position_of_absolute_containing_block = .stacking_relative_position_of_absolute_containing_block =
self.base.stacking_relative_position + self.base.stacking_relative_position +
(self.generated_containing_block_rect().start + (border_box_origin + relative_offset).to_physical(self.base.writing_mode,
relative_offset).to_physical(self.base.writing_mode, container_size) container_size)
} }
// Compute absolute position info for children. // Compute absolute position info for children.
@ -1741,7 +1722,7 @@ impl Flow for BlockFlow {
logical_border_width.inline_start, logical_border_width.inline_start,
logical_border_width.block_start); logical_border_width.block_start);
let position = position.to_physical(self.base.writing_mode, container_size); let position = position.to_physical(self.base.writing_mode, container_size);
if self.is_positioned() { if self.contains_positioned_fragments() {
position position
} else { } else {
// We establish a stacking context but are not positioned. (This will happen // 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 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- /// Return the dimensions of the containing block generated by this flow for absolutely-
/// positioned descendants. For block flows, this is the padding box. /// positioned descendants. For block flows, this is the padding box.
fn generated_containing_block_rect(&self) -> LogicalRect<Au> { fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au> {
self.fragment.border_box - self.fragment.style().logical_border_width() (self.fragment.border_box - self.fragment.style().logical_border_width()).size
} }
fn layer_id(&self, fragment_index: u32) -> LayerId { fn layer_id(&self, fragment_index: u32) -> LayerId {
@ -1871,7 +1845,7 @@ impl Flow for BlockFlow {
} }
fn is_absolute_containing_block(&self) -> bool { 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) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
@ -2491,7 +2465,8 @@ impl ISizeAndMarginsComputer for AbsoluteNonReplaced {
_: Au, _: Au,
layout_context: &LayoutContext) layout_context: &LayoutContext)
-> Au { -> 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, fn set_inline_position_of_flow_if_necessary(&self,
@ -2601,8 +2576,9 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
_: Au, _: Au,
layout_context: &LayoutContext) layout_context: &LayoutContext)
-> MaybeAuto { -> MaybeAuto {
let opaque_block = OpaqueFlow::from_flow(block);
let containing_block_inline_size = 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(); let fragment = block.fragment();
fragment.assign_replaced_inline_size_if_necessary(containing_block_inline_size); fragment.assign_replaced_inline_size_if_necessary(containing_block_inline_size);
// For replaced absolute flow, the rest of the constraint solving will // For replaced absolute flow, the rest of the constraint solving will
@ -2610,9 +2586,13 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
MaybeAuto::Specified(fragment.content_inline_size()) 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 { -> 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, fn set_inline_position_of_flow_if_necessary(&self,

View file

@ -24,12 +24,9 @@ use flow::{IS_ABSOLUTELY_POSITIONED};
use flow; use flow;
use flow_ref::FlowRef; use flow_ref::FlowRef;
use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo}; use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo};
use fragment::CanvasFragmentInfo; use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo};
use fragment::ImageFragmentInfo; use fragment::{InlineAbsoluteHypotheticalFragmentInfo, TableColumnFragmentInfo};
use fragment::InlineAbsoluteHypotheticalFragmentInfo; use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
use fragment::TableColumnFragmentInfo;
use fragment::UnscannedTextFragmentInfo;
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo};
use incremental::{RECONSTRUCT_FLOW, RestyleDamage}; use incremental::{RECONSTRUCT_FLOW, RestyleDamage};
use inline::{InlineFlow, InlineFragmentNodeInfo}; use inline::{InlineFlow, InlineFragmentNodeInfo};
use list_item::{ListItemFlow, ListStyleTypeContent}; use list_item::{ListItemFlow, ListStyleTypeContent};
@ -121,7 +118,7 @@ pub struct InlineFragmentsConstructionResult {
pub splits: LinkedList<InlineBlockSplit>, pub splits: LinkedList<InlineBlockSplit>,
/// Any fragments that succeed the {ib} splits. /// Any fragments that succeed the {ib} splits.
pub fragments: LinkedList<Fragment>, pub fragments: IntermediateInlineFragments,
/// Any absolute descendants that we're bubbling up. /// Any absolute descendants that we're bubbling up.
pub abs_descendants: AbsDescendants, pub abs_descendants: AbsDescendants,
@ -156,16 +153,44 @@ pub struct InlineFragmentsConstructionResult {
#[derive(Clone)] #[derive(Clone)]
pub struct InlineBlockSplit { pub struct InlineBlockSplit {
/// The inline fragments that precede the flow. /// The inline fragments that precede the flow.
pub predecessors: LinkedList<Fragment>, pub predecessors: IntermediateInlineFragments,
/// The flow that caused this {ib} split. /// The flow that caused this {ib} split.
pub flow: FlowRef, pub flow: FlowRef,
} }
/// Holds inline fragments and absolute descendants.
#[derive(Clone)]
pub struct IntermediateInlineFragments {
/// The list of fragments.
pub fragments: LinkedList<Fragment>,
/// The list of absolute descendants of those inline fragments.
pub absolute_descendants: AbsDescendants,
}
impl IntermediateInlineFragments {
fn new() -> IntermediateInlineFragments {
IntermediateInlineFragments {
fragments: LinkedList::new(),
absolute_descendants: Descendants::new(),
}
}
fn is_empty(&self) -> bool {
self.fragments.is_empty() && self.absolute_descendants.is_empty()
}
fn push_all(&mut self, mut other: IntermediateInlineFragments) {
self.fragments.append(&mut other.fragments);
self.absolute_descendants.push_descendants(other.absolute_descendants);
}
}
/// Holds inline fragments that we're gathering for children of an inline node. /// Holds inline fragments that we're gathering for children of an inline node.
struct InlineFragmentsAccumulator { struct InlineFragmentsAccumulator {
/// The list of fragments. /// The list of fragments.
fragments: LinkedList<Fragment>, fragments: IntermediateInlineFragments,
/// Whether we've created a range to enclose all the fragments. This will be Some() if the /// Whether we've created a range to enclose all the fragments. This will be Some() if the
/// outer node is an inline and None otherwise. /// outer node is an inline and None otherwise.
@ -175,37 +200,38 @@ struct InlineFragmentsAccumulator {
impl InlineFragmentsAccumulator { impl InlineFragmentsAccumulator {
fn new() -> InlineFragmentsAccumulator { fn new() -> InlineFragmentsAccumulator {
InlineFragmentsAccumulator { InlineFragmentsAccumulator {
fragments: LinkedList::new(), fragments: IntermediateInlineFragments::new(),
enclosing_node: None, enclosing_node: None,
} }
} }
fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator { fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator {
let fragments = LinkedList::new();
InlineFragmentsAccumulator { InlineFragmentsAccumulator {
fragments: fragments, fragments: IntermediateInlineFragments::new(),
enclosing_node: Some(InlineFragmentNodeInfo { enclosing_node: Some(InlineFragmentNodeInfo {
address: OpaqueNodeMethods::from_thread_safe_layout_node(node), address: OpaqueNodeMethods::from_thread_safe_layout_node(node),
style: node.style().clone() }), style: node.style().clone(),
}),
} }
} }
fn push_all(&mut self, mut fragments: LinkedList<Fragment>) { fn push(&mut self, fragment: Fragment) {
if fragments.len() == 0 { self.fragments.fragments.push_back(fragment)
return
}
self.fragments.append(&mut fragments)
} }
fn to_dlist(self) -> LinkedList<Fragment> { fn push_all(&mut self, mut fragments: IntermediateInlineFragments) {
self.fragments.fragments.append(&mut fragments.fragments);
self.fragments.absolute_descendants.push_descendants(fragments.absolute_descendants);
}
fn to_intermediate_inline_fragments(self) -> IntermediateInlineFragments {
let InlineFragmentsAccumulator { let InlineFragmentsAccumulator {
mut fragments, mut fragments,
enclosing_node, enclosing_node,
} = self; } = self;
if let Some(enclosing_node) = enclosing_node { if let Some(enclosing_style) = enclosing_style {
let frag_len = fragments.len(); let frag_len = fragments.fragments.len();
for (idx, frag) in fragments.iter_mut().enumerate() { for (idx, frag) in fragments.fragments.iter_mut().enumerate() {
// frag is first inline fragment in the inline node // frag is first inline fragment in the inline node
let is_first = idx == 0; let is_first = idx == 0;
@ -355,7 +381,7 @@ impl<'a> FlowConstructor<'a> {
flow_list: &mut Vec<FlowRef>, flow_list: &mut Vec<FlowRef>,
whitespace_stripping: WhitespaceStrippingMode, whitespace_stripping: WhitespaceStrippingMode,
node: &ThreadSafeLayoutNode) { node: &ThreadSafeLayoutNode) {
let mut fragments = fragment_accumulator.to_dlist(); let mut fragments = fragment_accumulator.to_intermediate_inline_fragments();
if fragments.is_empty() { if fragments.is_empty() {
return return
}; };
@ -363,13 +389,13 @@ impl<'a> FlowConstructor<'a> {
match whitespace_stripping { match whitespace_stripping {
WhitespaceStrippingMode::None => {} WhitespaceStrippingMode::None => {}
WhitespaceStrippingMode::FromStart => { WhitespaceStrippingMode::FromStart => {
strip_ignorable_whitespace_from_start(&mut fragments); strip_ignorable_whitespace_from_start(&mut fragments.fragments);
if fragments.is_empty() { if fragments.is_empty() {
return return
}; };
} }
WhitespaceStrippingMode::FromEnd => { WhitespaceStrippingMode::FromEnd => {
strip_ignorable_whitespace_from_end(&mut fragments); strip_ignorable_whitespace_from_end(&mut fragments.fragments);
if fragments.is_empty() { if fragments.is_empty() {
return return
}; };
@ -378,7 +404,7 @@ impl<'a> FlowConstructor<'a> {
// Build a list of all the inline-block fragments before fragments is moved. // Build a list of all the inline-block fragments before fragments is moved.
let mut inline_block_flows = vec!(); let mut inline_block_flows = vec!();
for fragment in fragments.iter() { for fragment in fragments.fragments.iter() {
match fragment.specific { match fragment.specific {
SpecificFragmentInfo::InlineBlock(ref info) => { SpecificFragmentInfo::InlineBlock(ref info) => {
inline_block_flows.push(info.flow_ref.clone()) inline_block_flows.push(info.flow_ref.clone())
@ -386,6 +412,9 @@ impl<'a> FlowConstructor<'a> {
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => { SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => {
inline_block_flows.push(info.flow_ref.clone()) inline_block_flows.push(info.flow_ref.clone())
} }
SpecificFragmentInfo::InlineAbsolute(ref info) => {
inline_block_flows.push(info.flow_ref.clone())
}
_ => {} _ => {}
} }
} }
@ -393,16 +422,25 @@ impl<'a> FlowConstructor<'a> {
// We must scan for runs before computing minimum ascent and descent because scanning // We must scan for runs before computing minimum ascent and descent because scanning
// for runs might collapse so much whitespace away that only hypothetical fragments // for runs might collapse so much whitespace away that only hypothetical fragments
// remain. In that case the inline flow will compute its ascent and descent to be zero. // remain. In that case the inline flow will compute its ascent and descent to be zero.
let fragments = TextRunScanner::new().scan_for_runs(self.layout_context.font_context(), let scanned_fragments =
fragments); TextRunScanner::new().scan_for_runs(self.layout_context.font_context(),
fragments.fragments);
let mut inline_flow_ref = let mut inline_flow_ref =
FlowRef::new(box InlineFlow::from_fragments(fragments, node.style().writing_mode)); FlowRef::new(box InlineFlow::from_fragments(scanned_fragments,
node.style().writing_mode));
// Add all the inline-block fragments as children of the inline flow. // Add all the inline-block fragments as children of the inline flow.
for inline_block_flow in inline_block_flows.iter() { for inline_block_flow in inline_block_flows.iter() {
inline_flow_ref.add_new_child(inline_block_flow.clone()); inline_flow_ref.add_new_child(inline_block_flow.clone());
} }
// Set up absolute descendants as necessary.
let contains_positioned_fragments = inline_flow_ref.contains_positioned_fragments();
if contains_positioned_fragments {
// This is the containing block for all the absolute descendants.
inline_flow_ref.set_absolute_descendants(fragments.absolute_descendants);
}
{ {
let inline_flow = inline_flow_ref.as_inline(); let inline_flow = inline_flow_ref.as_inline();
@ -447,7 +485,7 @@ impl<'a> FlowConstructor<'a> {
// Flush any inline fragments that we were gathering up. This allows us to // Flush any inline fragments that we were gathering up. This allows us to
// handle {ib} splits. // handle {ib} splits.
debug!("flushing {} inline box(es) to flow A", debug!("flushing {} inline box(es) to flow A",
inline_fragment_accumulator.fragments.len()); inline_fragment_accumulator.fragments.fragments.len());
self.flush_inline_fragments_to_flow_or_list( self.flush_inline_fragments_to_flow_or_list(
mem::replace(inline_fragment_accumulator, mem::replace(inline_fragment_accumulator,
InlineFragmentsAccumulator::new()), InlineFragmentsAccumulator::new()),
@ -491,7 +529,7 @@ impl<'a> FlowConstructor<'a> {
// Flush any inline fragments that we were gathering up. // Flush any inline fragments that we were gathering up.
debug!("flushing {} inline box(es) to flow A", debug!("flushing {} inline box(es) to flow A",
inline_fragment_accumulator.fragments.len()); inline_fragment_accumulator.fragments.fragments.len());
self.flush_inline_fragments_to_flow_or_list( self.flush_inline_fragments_to_flow_or_list(
mem::replace(inline_fragment_accumulator, mem::replace(inline_fragment_accumulator,
InlineFragmentsAccumulator::new()), InlineFragmentsAccumulator::new()),
@ -526,7 +564,7 @@ impl<'a> FlowConstructor<'a> {
whitespace_style, whitespace_style,
whitespace_damage, whitespace_damage,
fragment_info); fragment_info);
inline_fragment_accumulator.fragments.push_back(fragment); inline_fragment_accumulator.fragments.fragments.push_back(fragment);
} }
ConstructionResult::ConstructionItem(ConstructionItem::TableColumnFragment(_)) => { ConstructionResult::ConstructionItem(ConstructionItem::TableColumnFragment(_)) => {
// TODO: Implement anonymous table objects for missing parents // TODO: Implement anonymous table objects for missing parents
@ -538,16 +576,17 @@ impl<'a> FlowConstructor<'a> {
/// Constructs a block flow, beginning with the given `initial_fragments` if present and then /// Constructs a block flow, beginning with the given `initial_fragments` if present and then
/// appending the construction results of children to the child list of the block flow. {ib} /// appending the construction results of children to the child list of the block flow. {ib}
/// splits and absolutely-positioned descendants are handled correctly. /// splits and absolutely-positioned descendants are handled correctly.
fn build_flow_for_block_starting_with_fragments(&mut self, fn build_flow_for_block_starting_with_fragments(
mut flow: FlowRef, &mut self,
node: &ThreadSafeLayoutNode, mut flow: FlowRef,
mut initial_fragments: LinkedList<Fragment>) node: &ThreadSafeLayoutNode,
-> ConstructionResult { initial_fragments: IntermediateInlineFragments)
-> ConstructionResult {
// Gather up fragments for the inline flows we might need to create. // Gather up fragments for the inline flows we might need to create.
let mut inline_fragment_accumulator = InlineFragmentsAccumulator::new(); let mut inline_fragment_accumulator = InlineFragmentsAccumulator::new();
let mut consecutive_siblings = vec!(); let mut consecutive_siblings = vec!();
inline_fragment_accumulator.fragments.append(&mut initial_fragments); inline_fragment_accumulator.fragments.push_all(initial_fragments);
let mut first_fragment = inline_fragment_accumulator.fragments.is_empty(); let mut first_fragment = inline_fragment_accumulator.fragments.is_empty();
// List of absolute descendants, in tree order. // List of absolute descendants, in tree order.
@ -582,9 +621,9 @@ impl<'a> FlowConstructor<'a> {
flow.finish(); flow.finish();
// Set up the absolute descendants. // Set up the absolute descendants.
let is_positioned = flow.as_block().is_positioned(); let contains_positioned_fragments = flow.contains_positioned_fragments();
let is_absolutely_positioned = flow::base(&*flow).flags.contains(IS_ABSOLUTELY_POSITIONED); let is_absolutely_positioned = flow::base(&*flow).flags.contains(IS_ABSOLUTELY_POSITIONED);
if is_positioned { if contains_positioned_fragments {
// This is the containing block for all the absolute descendants. // This is the containing block for all the absolute descendants.
flow.set_absolute_descendants(abs_descendants); flow.set_absolute_descendants(abs_descendants);
@ -611,7 +650,7 @@ impl<'a> FlowConstructor<'a> {
/// `<textarea>`. /// `<textarea>`.
fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ThreadSafeLayoutNode) fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ThreadSafeLayoutNode)
-> ConstructionResult { -> ConstructionResult {
let mut initial_fragments = LinkedList::new(); let mut initial_fragments = IntermediateInlineFragments::new();
if node.get_pseudo_element_type() != PseudoElementType::Normal || if node.get_pseudo_element_type() != PseudoElementType::Normal ||
node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement( node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
HTMLElementTypeId::HTMLInputElement))) || HTMLElementTypeId::HTMLInputElement))) ||
@ -634,7 +673,7 @@ impl<'a> FlowConstructor<'a> {
/// Pushes fragments appropriate for the content of the given node onto the given list. /// Pushes fragments appropriate for the content of the given node onto the given list.
fn create_fragments_for_node_text_content(&self, fn create_fragments_for_node_text_content(&self,
fragments: &mut LinkedList<Fragment>, fragments: &mut IntermediateInlineFragments,
node: &ThreadSafeLayoutNode, node: &ThreadSafeLayoutNode,
style: &Arc<ComputedValues>) { style: &Arc<ComputedValues>) {
for content_item in node.text_content().into_iter() { for content_item in node.text_content().into_iter() {
@ -650,7 +689,8 @@ impl<'a> FlowConstructor<'a> {
}; };
let opaque_node = OpaqueNodeMethods::from_thread_safe_layout_node(node); let opaque_node = OpaqueNodeMethods::from_thread_safe_layout_node(node);
fragments.push_back(Fragment::from_opaque_node_and_style(opaque_node, fragments.fragments
.push_back(Fragment::from_opaque_node_and_style(opaque_node,
style.clone(), style.clone(),
node.restyle_damage(), node.restyle_damage(),
specific)) specific))
@ -672,6 +712,30 @@ impl<'a> FlowConstructor<'a> {
self.build_flow_for_block_like(FlowRef::new(flow), node) self.build_flow_for_block_like(FlowRef::new(flow), node)
} }
/// Bubbles up {ib} splits.
fn accumulate_inline_block_splits(&mut self,
splits: LinkedList<InlineBlockSplit>,
node: &ThreadSafeLayoutNode,
fragment_accumulator: &mut InlineFragmentsAccumulator,
opt_inline_block_splits: &mut LinkedList<InlineBlockSplit>) {
for split in splits.into_iter() {
let InlineBlockSplit {
predecessors,
flow: kid_flow
} = split;
fragment_accumulator.push_all(predecessors);
let split = InlineBlockSplit {
predecessors: mem::replace(
fragment_accumulator,
InlineFragmentsAccumulator::from_inline_node(
node)).to_intermediate_inline_fragments(),
flow: kid_flow,
};
opt_inline_block_splits.push_back(split)
}
}
/// Concatenates the fragments of kids, adding in our own borders/padding/margins if necessary. /// Concatenates the fragments of kids, adding in our own borders/padding/margins if necessary.
/// Returns the `InlineFragmentsConstructionResult`, if any. There will be no /// Returns the `InlineFragmentsConstructionResult`, if any. There will be no
/// `InlineFragmentsConstructionResult` if this node consisted entirely of ignorable /// `InlineFragmentsConstructionResult` if this node consisted entirely of ignorable
@ -689,18 +753,36 @@ impl<'a> FlowConstructor<'a> {
} }
match kid.swap_out_construction_result() { match kid.swap_out_construction_result() {
ConstructionResult::None => {} ConstructionResult::None => {}
ConstructionResult::Flow(flow, kid_abs_descendants) => { ConstructionResult::Flow(mut flow, kid_abs_descendants) => {
// {ib} split. Flush the accumulator to our new split and make a new if !flow::base(&*flow).flags.contains(IS_ABSOLUTELY_POSITIONED) {
// accumulator to hold any subsequent fragments we come across. // {ib} split. Flush the accumulator to our new split and make a new
let split = InlineBlockSplit { // accumulator to hold any subsequent fragments we come across.
predecessors: let split = InlineBlockSplit {
mem::replace( predecessors:
&mut fragment_accumulator, mem::replace(
InlineFragmentsAccumulator::from_inline_node(node)).to_dlist(), &mut fragment_accumulator,
flow: flow, InlineFragmentsAccumulator::from_inline_node(
}; node)).to_intermediate_inline_fragments(),
opt_inline_block_splits.push_back(split); flow: flow,
abs_descendants.push_descendants(kid_abs_descendants); };
opt_inline_block_splits.push_back(split);
abs_descendants.push_descendants(kid_abs_descendants);
} else {
// Push the absolutely-positioned kid as an inline containing block.
let kid_node = flow.as_block().fragment.node;
let kid_style = flow.as_block().fragment.style.clone();
let kid_restyle_damage = flow.as_block().fragment.restyle_damage;
let fragment_info = SpecificFragmentInfo::InlineAbsolute(
InlineAbsoluteFragmentInfo::new(flow));
fragment_accumulator.push(Fragment::from_opaque_node_and_style(
kid_node,
kid_style,
kid_restyle_damage,
fragment_info));
fragment_accumulator.fragments
.absolute_descendants
.push_descendants(kid_abs_descendants);
}
} }
ConstructionResult::ConstructionItem(ConstructionItem::InlineFragments( ConstructionResult::ConstructionItem(ConstructionItem::InlineFragments(
InlineFragmentsConstructionResult { InlineFragmentsConstructionResult {
@ -710,22 +792,10 @@ impl<'a> FlowConstructor<'a> {
})) => { })) => {
// Bubble up {ib} splits. // Bubble up {ib} splits.
for split in splits.into_iter() { self.accumulate_inline_block_splits(splits,
let InlineBlockSplit { node,
predecessors, &mut fragment_accumulator,
flow: kid_flow &mut opt_inline_block_splits);
} = split;
fragment_accumulator.push_all(predecessors);
let split = InlineBlockSplit {
predecessors:
mem::replace(&mut fragment_accumulator,
InlineFragmentsAccumulator::from_inline_node(node))
.to_dlist(),
flow: kid_flow,
};
opt_inline_block_splits.push_back(split)
}
// Push residual fragments. // Push residual fragments.
fragment_accumulator.push_all(successors); fragment_accumulator.push_all(successors);
@ -743,7 +813,7 @@ impl<'a> FlowConstructor<'a> {
whitespace_style, whitespace_style,
whitespace_damage, whitespace_damage,
fragment_info); fragment_info);
fragment_accumulator.fragments.push_back(fragment) fragment_accumulator.fragments.fragments.push_back(fragment)
} }
ConstructionResult::ConstructionItem(ConstructionItem::TableColumnFragment(_)) => { ConstructionResult::ConstructionItem(ConstructionItem::TableColumnFragment(_)) => {
// TODO: Implement anonymous table objects for missing parents // TODO: Implement anonymous table objects for missing parents
@ -753,12 +823,12 @@ impl<'a> FlowConstructor<'a> {
} }
// Finally, make a new construction result. // Finally, make a new construction result.
if opt_inline_block_splits.len() > 0 || fragment_accumulator.fragments.len() > 0 if opt_inline_block_splits.len() > 0 || !fragment_accumulator.fragments.is_empty()
|| abs_descendants.len() > 0 { || abs_descendants.len() > 0 {
let construction_item = ConstructionItem::InlineFragments( let construction_item = ConstructionItem::InlineFragments(
InlineFragmentsConstructionResult { InlineFragmentsConstructionResult {
splits: opt_inline_block_splits, splits: opt_inline_block_splits,
fragments: fragment_accumulator.to_dlist(), fragments: fragment_accumulator.to_intermediate_inline_fragments(),
abs_descendants: abs_descendants, abs_descendants: abs_descendants,
}); });
ConstructionResult::ConstructionItem(construction_item) ConstructionResult::ConstructionItem(construction_item)
@ -795,13 +865,13 @@ impl<'a> FlowConstructor<'a> {
// If this is generated content, then we need to initialize the accumulator with the // If this is generated content, then we need to initialize the accumulator with the
// fragment corresponding to that content. Otherwise, just initialize with the ordinary // fragment corresponding to that content. Otherwise, just initialize with the ordinary
// fragment that needs to be generated for this inline node. // fragment that needs to be generated for this inline node.
let mut fragments = LinkedList::new(); let mut fragments = IntermediateInlineFragments::new();
match (node.get_pseudo_element_type(), node.type_id()) { match (node.get_pseudo_element_type(), node.type_id()) {
(_, Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text))) => { (_, Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text))) => {
self.create_fragments_for_node_text_content(&mut fragments, node, &style) self.create_fragments_for_node_text_content(&mut fragments, node, &style)
} }
(PseudoElementType::Normal, _) => { (PseudoElementType::Normal, _) => {
fragments.push_back(self.build_fragment_for_block(node)); fragments.fragments.push_back(self.build_fragment_for_block(node));
} }
(_, _) => self.create_fragments_for_node_text_content(&mut fragments, node, &style), (_, _) => self.create_fragments_for_node_text_content(&mut fragments, node, &style),
} }
@ -827,13 +897,13 @@ impl<'a> FlowConstructor<'a> {
block_flow)); block_flow));
let fragment = Fragment::new(node, fragment_info); let fragment = Fragment::new(node, fragment_info);
let mut fragment_accumulator = InlineFragmentsAccumulator::new(); let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
fragment_accumulator.fragments.push_back(fragment); fragment_accumulator.fragments.fragments.push_back(fragment);
let construction_item = let construction_item =
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
splits: LinkedList::new(), splits: LinkedList::new(),
fragments: fragment_accumulator.to_dlist(), fragments: fragment_accumulator.to_intermediate_inline_fragments(),
abs_descendants: abs_descendants, abs_descendants: abs_descendants,
}); });
ConstructionResult::ConstructionItem(construction_item) ConstructionResult::ConstructionItem(construction_item)
@ -854,12 +924,12 @@ impl<'a> FlowConstructor<'a> {
let fragment = Fragment::new(node, fragment_info); let fragment = Fragment::new(node, fragment_info);
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node); let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
fragment_accumulator.fragments.push_back(fragment); fragment_accumulator.fragments.fragments.push_back(fragment);
let construction_item = let construction_item =
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult { ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
splits: LinkedList::new(), splits: LinkedList::new(),
fragments: fragment_accumulator.to_dlist(), fragments: fragment_accumulator.to_intermediate_inline_fragments(),
abs_descendants: abs_descendants, abs_descendants: abs_descendants,
}); });
ConstructionResult::ConstructionItem(construction_item) ConstructionResult::ConstructionItem(construction_item)
@ -973,11 +1043,11 @@ impl<'a> FlowConstructor<'a> {
// The flow is done. // The flow is done.
wrapper_flow.finish(); wrapper_flow.finish();
let is_positioned = wrapper_flow.as_block().is_positioned(); let contains_positioned_fragments = wrapper_flow.contains_positioned_fragments();
let is_fixed_positioned = wrapper_flow.as_block().is_fixed(); let is_fixed_positioned = wrapper_flow.as_block().is_fixed();
let is_absolutely_positioned = let is_absolutely_positioned =
flow::base(&*wrapper_flow).flags.contains(IS_ABSOLUTELY_POSITIONED); flow::base(&*wrapper_flow).flags.contains(IS_ABSOLUTELY_POSITIONED);
if is_positioned { if contains_positioned_fragments {
// This is the containing block for all the absolute descendants. // This is the containing block for all the absolute descendants.
wrapper_flow.set_absolute_descendants(abs_descendants); wrapper_flow.set_absolute_descendants(abs_descendants);
@ -1085,7 +1155,7 @@ impl<'a> FlowConstructor<'a> {
// we adopt Gecko's behavior rather than WebKit's when the marker causes an {ib} split, // we adopt Gecko's behavior rather than WebKit's when the marker causes an {ib} split,
// which has caused some malaise (Bugzilla #36854) but CSS 2.1 § 12.5.1 lets me do it, so // which has caused some malaise (Bugzilla #36854) but CSS 2.1 § 12.5.1 lets me do it, so
// there. // there.
let mut initial_fragments = LinkedList::new(); let mut initial_fragments = IntermediateInlineFragments::new();
let main_fragment = self.build_fragment_for_block(node); let main_fragment = self.build_fragment_for_block(node);
let flow = match node.style().get_list().list_style_position { let flow = match node.style().get_list().list_style_position {
list_style_position::T::outside => { list_style_position::T::outside => {
@ -1096,7 +1166,7 @@ impl<'a> FlowConstructor<'a> {
} }
list_style_position::T::inside => { list_style_position::T::inside => {
if let Some(marker_fragment) = marker_fragment { if let Some(marker_fragment) = marker_fragment {
initial_fragments.push_back(marker_fragment) initial_fragments.fragments.push_back(marker_fragment)
} }
box ListItemFlow::from_node_fragments_and_flotation(node, box ListItemFlow::from_node_fragments_and_flotation(node,
main_fragment, main_fragment,
@ -1194,7 +1264,9 @@ impl<'a> FlowConstructor<'a> {
} }
let damage = node.restyle_damage(); let damage = node.restyle_damage();
for fragment in inline_fragments_construction_result.fragments.iter_mut() { for fragment in inline_fragments_construction_result.fragments
.fragments
.iter_mut() {
match fragment.specific { match fragment.specific {
SpecificFragmentInfo::InlineBlock(ref mut inline_block_fragment) => { SpecificFragmentInfo::InlineBlock(ref mut inline_block_fragment) => {
flow::mut_base(&mut *inline_block_fragment.flow_ref).restyle_damage flow::mut_base(&mut *inline_block_fragment.flow_ref).restyle_damage

View file

@ -81,7 +81,7 @@ impl LayoutDataWrapper {
ConstructionResult::ConstructionItem(ref construction_item) => { ConstructionResult::ConstructionItem(ref construction_item) => {
match construction_item { match construction_item {
&ConstructionItem::InlineFragments(ref inline_fragments) => { &ConstructionItem::InlineFragments(ref inline_fragments) => {
for fragment in inline_fragments.fragments.iter() { for fragment in inline_fragments.fragments.fragments.iter() {
fragment.remove_compositor_layers(constellation_chan.clone()); fragment.remove_compositor_layers(constellation_chan.clone());
} }
} }

View file

@ -1001,7 +1001,8 @@ impl FragmentDisplayListBuilding for Fragment {
SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableRow |
SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::TableWrapper |
SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => { SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineAbsolute(_) => {
if opts::get().show_debug_fragment_borders { if opts::get().show_debug_fragment_borders {
self.build_debug_borders_around_fragment(display_list, self.build_debug_borders_around_fragment(display_list,
stacking_relative_border_box, stacking_relative_border_box,
@ -1364,8 +1365,10 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
background_border_level); background_border_level);
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() { self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
DisplayListBuildingResult::StackingContext( DisplayListBuildingResult::StackingContext(self.fragment.create_stacking_context(
self.fragment.create_stacking_context(&self.base, display_list, None)) &self.base,
display_list,
None))
} else { } else {
match self.fragment.style.get_box().position { match self.fragment.style.get_box().position {
position::T::static_ => {} position::T::static_ => {}
@ -1391,8 +1394,10 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
!self.base.flags.contains(NEEDS_LAYER) { !self.base.flags.contains(NEEDS_LAYER) {
// We didn't need a layer. // We didn't need a layer.
self.base.display_list_building_result = self.base.display_list_building_result =
DisplayListBuildingResult::StackingContext( DisplayListBuildingResult::StackingContext(self.fragment.create_stacking_context(
self.fragment.create_stacking_context(&self.base, display_list, None)); &self.base,
display_list,
None));
return return
} }
@ -1492,6 +1497,11 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
flow::mut_base(block_flow).display_list_building_result flow::mut_base(block_flow).display_list_building_result
.add_to(&mut *display_list) .add_to(&mut *display_list)
} }
SpecificFragmentInfo::InlineAbsolute(ref mut block_flow) => {
let block_flow = &mut *block_flow.flow_ref;
flow::mut_base(block_flow).display_list_building_result
.add_to(&mut *display_list)
}
_ => {} _ => {}
} }
} }

View file

@ -324,19 +324,15 @@ pub trait Flow: fmt::Debug + Sync {
self.positioning() == position::T::fixed self.positioning() == position::T::fixed
} }
fn is_positioned(&self) -> bool { fn contains_positioned_fragments(&self) -> bool {
self.is_relatively_positioned() || base(self).flags.contains(IS_ABSOLUTELY_POSITIONED) 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 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. /// Returns true if this is an absolute containing block.
fn is_absolute_containing_block(&self) -> bool { fn is_absolute_containing_block(&self) -> bool {
false false
@ -350,14 +346,12 @@ pub trait Flow: fmt::Debug + Sync {
/// this is only used for absolutely-positioned inline-blocks. /// this is only used for absolutely-positioned inline-blocks.
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au); 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- /// Return the size of the containing block generated by this flow for the absolutely-
/// positioned descendants. For block flows, this is the padding box. /// 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 /// 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! /// implications because this can be called on parents concurrently from descendants!
fn generated_containing_block_rect(&self) -> LogicalRect<Au> { fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au>;
panic!("generated_containing_block_rect not yet implemented for this flow")
}
/// Returns a layer ID for the given fragment. /// Returns a layer ID for the given fragment.
#[allow(unsafe_code)] #[allow(unsafe_code)]
@ -440,6 +434,9 @@ pub trait ImmutableFlowUtils {
/// Generates missing child flow of this flow. /// Generates missing child flow of this flow.
fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> FlowRef; 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. /// Returns true if this flow has no children.
fn is_leaf(self) -> bool; fn is_leaf(self) -> bool;
@ -471,6 +468,21 @@ pub trait MutableFlowUtils {
/// Traverses the tree in postorder. /// Traverses the tree in postorder.
fn traverse_postorder<T:PostorderFlowTraversal>(self, traversal: &T); 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 // Mutators
/// Calls `repair_style` and `bubble_inline_sizes`. You should use this method instead of /// 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) 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. /// Returns true if this flow has no children.
fn is_leaf(self) -> bool { fn is_leaf(self) -> bool {
base(self).children.len() == 0 base(self).children.len() == 0
@ -1276,6 +1293,34 @@ impl<'a> MutableFlowUtils for &'a mut (Flow + 'a) {
self.repair_style(style); self.repair_style(style);
self.bubble_inline_sizes(); 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 { impl MutableOwnedFlowUtils for FlowRef {
@ -1288,13 +1333,11 @@ impl MutableOwnedFlowUtils for FlowRef {
/// construction is allowed to possess. /// construction is allowed to possess.
fn set_absolute_descendants(&mut self, abs_descendants: AbsDescendants) { fn set_absolute_descendants(&mut self, abs_descendants: AbsDescendants) {
let this = self.clone(); let this = self.clone();
let base = mut_base(&mut **self);
let block = self.as_block(); base.abs_descendants = abs_descendants;
block.base.abs_descendants = abs_descendants; for descendant_link in base.abs_descendants.iter() {
let descendant_base = mut_base(descendant_link);
for descendant_link in block.base.abs_descendants.iter() { descendant_base.absolute_cb.set(this.clone());
let base = mut_base(descendant_link);
base.absolute_cb.set(this.clone());
} }
} }
} }
@ -1329,10 +1372,33 @@ impl ContainingBlockLink {
} }
#[inline] #[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 { match self.link {
None => panic!("haven't done it"), None => {
Some(ref mut link) => link.generated_containing_block_rect(), 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)
}
}

View file

@ -149,6 +149,11 @@ pub enum SpecificFragmentInfo {
InlineAbsoluteHypothetical(InlineAbsoluteHypotheticalFragmentInfo), InlineAbsoluteHypothetical(InlineAbsoluteHypotheticalFragmentInfo),
InlineBlock(InlineBlockFragmentInfo), InlineBlock(InlineBlockFragmentInfo),
/// An inline fragment that establishes an absolute containing block for its descendants (i.e.
/// a positioned inline fragment).
InlineAbsolute(InlineAbsoluteFragmentInfo),
ScannedText(Box<ScannedTextFragmentInfo>), ScannedText(Box<ScannedTextFragmentInfo>),
Table, Table,
TableCell, TableCell,
@ -175,6 +180,7 @@ impl SpecificFragmentInfo {
SpecificFragmentInfo::UnscannedText(_) | SpecificFragmentInfo::UnscannedText(_) |
SpecificFragmentInfo::Generic => return RestyleDamage::empty(), SpecificFragmentInfo::Generic => return RestyleDamage::empty(),
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => &info.flow_ref, SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => &info.flow_ref,
SpecificFragmentInfo::InlineAbsolute(ref info) => &info.flow_ref,
SpecificFragmentInfo::InlineBlock(ref info) => &info.flow_ref, SpecificFragmentInfo::InlineBlock(ref info) => &info.flow_ref,
}; };
@ -188,6 +194,7 @@ impl SpecificFragmentInfo {
SpecificFragmentInfo::GeneratedContent(_) => "SpecificFragmentInfo::GeneratedContent", SpecificFragmentInfo::GeneratedContent(_) => "SpecificFragmentInfo::GeneratedContent",
SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe", SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe",
SpecificFragmentInfo::Image(_) => "SpecificFragmentInfo::Image", SpecificFragmentInfo::Image(_) => "SpecificFragmentInfo::Image",
SpecificFragmentInfo::InlineAbsolute(_) => "SpecificFragmentInfo::InlineAbsolute",
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => { SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {
"SpecificFragmentInfo::InlineAbsoluteHypothetical" "SpecificFragmentInfo::InlineAbsoluteHypothetical"
} }
@ -260,6 +267,24 @@ impl InlineBlockFragmentInfo {
} }
} }
/// An inline fragment that establishes an absolute containing block for its descendants (i.e.
/// a positioned inline fragment).
///
/// FIXME(pcwalton): Stop leaking this `FlowRef` to layout; that is not memory safe because layout
/// can clone it.
#[derive(Clone)]
pub struct InlineAbsoluteFragmentInfo {
pub flow_ref: FlowRef,
}
impl InlineAbsoluteFragmentInfo {
pub fn new(flow_ref: FlowRef) -> InlineAbsoluteFragmentInfo {
InlineAbsoluteFragmentInfo {
flow_ref: flow_ref,
}
}
}
#[derive(Clone)] #[derive(Clone)]
pub struct CanvasFragmentInfo { pub struct CanvasFragmentInfo {
pub replaced_image_fragment_info: ReplacedImageFragmentInfo, pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
@ -868,7 +893,8 @@ impl Fragment {
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Generic |
SpecificFragmentInfo::GeneratedContent(_) | SpecificFragmentInfo::GeneratedContent(_) |
SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Image(_) => { SpecificFragmentInfo::Image(_) |
SpecificFragmentInfo::InlineAbsolute(_) => {
QuantitiesIncludedInIntrinsicInlineSizes::all() QuantitiesIncludedInIntrinsicInlineSizes::all()
} }
SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => { SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => {
@ -1247,6 +1273,10 @@ impl Fragment {
let block_flow = info.flow_ref.as_block(); let block_flow = info.flow_ref.as_block();
result.union_block(&block_flow.base.intrinsic_inline_sizes) result.union_block(&block_flow.base.intrinsic_inline_sizes)
} }
SpecificFragmentInfo::InlineAbsolute(ref mut info) => {
let block_flow = info.flow_ref.as_block();
result.union_block(&block_flow.base.intrinsic_inline_sizes)
}
SpecificFragmentInfo::Image(ref mut image_fragment_info) => { SpecificFragmentInfo::Image(ref mut image_fragment_info) => {
let image_inline_size = match image_fragment_info.replaced_image_fragment_info let image_inline_size = match image_fragment_info.replaced_image_fragment_info
.dom_inline_size { .dom_inline_size {
@ -1318,7 +1348,8 @@ impl Fragment {
SpecificFragmentInfo::TableRow | SpecificFragmentInfo::TableRow |
SpecificFragmentInfo::TableWrapper | SpecificFragmentInfo::TableWrapper |
SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => Au(0), SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineAbsolute(_) => Au(0),
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => { SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
canvas_fragment_info.replaced_image_fragment_info.computed_inline_size() canvas_fragment_info.replaced_image_fragment_info.computed_inline_size()
} }
@ -1608,6 +1639,7 @@ impl Fragment {
SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineAbsolute(_) |
SpecificFragmentInfo::ScannedText(_) => {} SpecificFragmentInfo::ScannedText(_) => {}
}; };
@ -1631,6 +1663,14 @@ impl Fragment {
block_flow.base.block_container_inline_size = self.border_box.size.inline; block_flow.base.block_container_inline_size = self.border_box.size.inline;
block_flow.base.block_container_writing_mode = self.style.writing_mode; block_flow.base.block_container_writing_mode = self.style.writing_mode;
} }
SpecificFragmentInfo::InlineAbsolute(ref mut info) => {
let block_flow = info.flow_ref.as_block();
self.border_box.size.inline =
max(block_flow.base.intrinsic_inline_sizes.minimum_inline_size,
block_flow.base.intrinsic_inline_sizes.preferred_inline_size);
block_flow.base.block_container_inline_size = self.border_box.size.inline;
block_flow.base.block_container_writing_mode = self.style.writing_mode;
}
SpecificFragmentInfo::ScannedText(ref info) => { SpecificFragmentInfo::ScannedText(ref info) => {
// Scanned text fragments will have already had their content inline-sizes assigned // Scanned text fragments will have already had their content inline-sizes assigned
// by this point. // by this point.
@ -1690,6 +1730,7 @@ impl Fragment {
SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::Image(_) |
SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineAbsolute(_) |
SpecificFragmentInfo::ScannedText(_) => {} SpecificFragmentInfo::ScannedText(_) => {}
} }
@ -1735,6 +1776,12 @@ impl Fragment {
let block_flow = info.flow_ref.as_block(); let block_flow = info.flow_ref.as_block();
self.border_box.size.block = block_flow.base.position.size.block; self.border_box.size.block = block_flow.base.position.size.block;
} }
SpecificFragmentInfo::InlineAbsolute(ref mut info) => {
// Not the primary fragment, so we do not take the noncontent size into account.
let block_flow = info.flow_ref.as_block();
self.border_box.size.block = block_flow.base.position.size.block +
block_flow.fragment.margin.block_start_end()
}
SpecificFragmentInfo::Iframe(_) => { SpecificFragmentInfo::Iframe(_) => {
self.border_box.size.block = IframeFragmentInfo::calculate_replaced_block_size( self.border_box.size.block = IframeFragmentInfo::calculate_replaced_block_size(
style, containing_block_block_size) + style, containing_block_block_size) +
@ -1774,7 +1821,8 @@ impl Fragment {
block_flow.fragment.margin.block_start, block_flow.fragment.margin.block_start,
block_flow.fragment.margin.block_end) block_flow.fragment.margin.block_end)
} }
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => { SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineAbsolute(_) => {
// Hypothetical boxes take up no space. // Hypothetical boxes take up no space.
InlineMetrics { InlineMetrics {
block_size_above_baseline: Au(0), block_size_above_baseline: Au(0),
@ -1829,6 +1877,7 @@ impl Fragment {
match self.specific { match self.specific {
SpecificFragmentInfo::InlineBlock(_) | SpecificFragmentInfo::InlineBlock(_) |
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) | SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
SpecificFragmentInfo::InlineAbsolute(_) |
SpecificFragmentInfo::TableWrapper => false, SpecificFragmentInfo::TableWrapper => false,
SpecificFragmentInfo::Canvas(_) | SpecificFragmentInfo::Canvas(_) |
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Generic |

View file

@ -4,11 +4,13 @@
#![deny(unsafe_code)] #![deny(unsafe_code)]
use block::{AbsoluteAssignBSizesTraversal, AbsoluteStoreOverflowTraversal};
use css::node_style::StyledNode; use css::node_style::StyledNode;
use context::LayoutContext; use context::LayoutContext;
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding}; use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
use floats::{FloatKind, Floats, PlacementInfo}; use floats::{FloatKind, Floats, PlacementInfo};
use flow::{self, BaseFlow, FlowClass, Flow, ForceNonfloatedFlag, IS_ABSOLUTELY_POSITIONED}; use flow::{self, BaseFlow, FlowClass, Flow, ForceNonfloatedFlag, IS_ABSOLUTELY_POSITIONED};
use flow::{MutableFlowUtils, OpaqueFlow};
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW, RESOLVE_GENERATED_CONTENT}; use incremental::{REFLOW, REFLOW_OUT_OF_FLOW, RESOLVE_GENERATED_CONTENT};
use layout_debug; use layout_debug;
@ -16,7 +18,7 @@ use model::IntrinsicISizesContribution;
use text; use text;
use collections::VecDeque; use collections::VecDeque;
use geom::{Point2D, Rect}; use geom::{Point2D, Rect, Size2D};
use gfx::display_list::OpaqueNode; use gfx::display_list::OpaqueNode;
use gfx::font::FontMetrics; use gfx::font::FontMetrics;
use gfx::font_context::FontContext; use gfx::font_context::FontContext;
@ -27,10 +29,10 @@ use std::fmt;
use std::mem; use std::mem;
use std::sync::Arc; use std::sync::Arc;
use std::u16; use std::u16;
use style::computed_values::{display, overflow_x, text_align, text_justify, text_overflow}; use style::computed_values::{display, overflow_x, position, text_align, text_justify};
use style::computed_values::{vertical_align, white_space}; use style::computed_values::{text_overflow, vertical_align, white_space};
use style::properties::ComputedValues; use style::properties::ComputedValues;
use util::geometry::{Au, MAX_AU, ZERO_RECT}; use util::geometry::{Au, MAX_AU, ZERO_POINT, ZERO_RECT};
use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; use util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
use util::range::{Range, RangeIndex}; use util::range::{Range, RangeIndex};
use util; use util;
@ -1121,6 +1123,45 @@ impl InlineFlow {
self.base.restyle_damage = damage; self.base.restyle_damage = damage;
} }
fn containing_block_range_for_flow_surrounding_fragment_at_index(&self,
fragment_index: FragmentIndex)
-> Range<FragmentIndex> {
let mut start_index = fragment_index;
while start_index > FragmentIndex(0) &&
self.fragments
.fragments[(start_index - FragmentIndex(1)).get() as usize]
.style
.get_box()
.position == position::T::static_ {
start_index = start_index - FragmentIndex(1)
}
let mut end_index = fragment_index + FragmentIndex(1);
while end_index < FragmentIndex(self.fragments.fragments.len() as isize) &&
self.fragments
.fragments[end_index.get() as usize]
.style
.get_box()
.position == position::T::static_ {
end_index = end_index + FragmentIndex(1)
}
Range::new(start_index, end_index - start_index)
}
fn containing_block_range_for_flow(&self, opaque_flow: OpaqueFlow) -> Range<FragmentIndex> {
let index = FragmentIndex(self.fragments.fragments.iter().position(|fragment| {
match fragment.specific {
SpecificFragmentInfo::InlineAbsolute(ref inline_absolute) => {
OpaqueFlow::from_flow(&*inline_absolute.flow_ref) == opaque_flow
}
_ => false,
}
}).expect("containing_block_range_for_flow(): couldn't find inline absolute fragment!")
as isize);
self.containing_block_range_for_flow_surrounding_fragment_at_index(index)
}
} }
impl Flow for InlineFlow { impl Flow for InlineFlow {
@ -1398,6 +1439,19 @@ impl Flow for InlineFlow {
kid.assign_block_size_for_inorder_child_if_necessary(layout_context, thread_id); kid.assign_block_size_for_inorder_child_if_necessary(layout_context, thread_id);
} }
if self.contains_positioned_fragments() {
// 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.
(&mut *self as &mut Flow).traverse_preorder_absolute_flows(
&mut AbsoluteAssignBSizesTraversal(layout_context));
// Store overflow for all absolute descendants.
(&mut *self as &mut Flow).traverse_postorder_absolute_flows(
&mut AbsoluteStoreOverflowTraversal {
layout_context: layout_context,
});
}
self.base.position.size.block = match self.lines.last() { self.base.position.size.block = match self.lines.last() {
Some(ref last_line) => last_line.bounds.start.b + last_line.bounds.size.block, Some(ref last_line) => last_line.bounds.start.b + last_line.bounds.size.block,
None => Au(0), None => Au(0),
@ -1412,6 +1466,26 @@ impl Flow for InlineFlow {
} }
fn compute_absolute_position(&mut self) { fn compute_absolute_position(&mut self) {
// First, gather up the positions of all the containing blocks (if any).
let mut containing_block_positions = Vec::new();
let container_size = Size2D(self.base.block_container_inline_size, Au(0));
for (fragment_index, fragment) in self.fragments.fragments.iter().enumerate() {
if let SpecificFragmentInfo::InlineAbsolute(_) = fragment.specific {
let containing_block_range =
self.containing_block_range_for_flow_surrounding_fragment_at_index(
FragmentIndex(fragment_index as isize));
let first_fragment_index = containing_block_range.begin().get() as usize;
debug_assert!(first_fragment_index < self.fragments.fragments.len());
let first_fragment = &self.fragments.fragments[first_fragment_index];
let padding_box_origin = (first_fragment.border_box -
first_fragment.style.logical_border_width()).start;
containing_block_positions.push(
padding_box_origin.to_physical(self.base.writing_mode, container_size));
}
}
// Then compute the positions of all of our fragments.
let mut containing_block_positions = containing_block_positions.iter();
for fragment in self.fragments.fragments.iter_mut() { for fragment in self.fragments.fragments.iter_mut() {
let stacking_relative_border_box = let stacking_relative_border_box =
fragment.stacking_relative_border_box(&self.base.stacking_relative_position, fragment.stacking_relative_border_box(&self.base.stacking_relative_position,
@ -1440,6 +1514,22 @@ impl Flow for InlineFlow {
stacking_relative_border_box.origin stacking_relative_border_box.origin
} }
SpecificFragmentInfo::InlineAbsolute(ref mut info) => {
flow::mut_base(&mut *info.flow_ref).clip = clip;
let block_flow = info.flow_ref.as_block();
block_flow.base.absolute_position_info = self.base.absolute_position_info;
let stacking_relative_position = self.base.stacking_relative_position;
let padding_box_origin = containing_block_positions.next().unwrap();
block_flow.base
.absolute_position_info
.stacking_relative_position_of_absolute_containing_block =
stacking_relative_position + *padding_box_origin;
block_flow.base.stacking_relative_position =
stacking_relative_border_box.origin
}
_ => {} _ => {}
} }
} }
@ -1491,6 +1581,30 @@ impl Flow for InlineFlow {
(*mutator)(fragment) (*mutator)(fragment)
} }
} }
fn contains_positioned_fragments(&self) -> bool {
self.fragments.fragments.iter().any(|fragment| {
fragment.style.get_box().position != position::T::static_
})
}
fn contains_relatively_positioned_fragments(&self) -> bool {
self.fragments.fragments.iter().any(|fragment| {
fragment.style.get_box().position == position::T::relative
})
}
fn generated_containing_block_size(&self, for_flow: OpaqueFlow) -> LogicalSize<Au> {
let mut containing_block_size = LogicalSize::new(self.base.writing_mode, Au(0), Au(0));
for index in self.containing_block_range_for_flow(for_flow).each_index() {
let fragment = &self.fragments.fragments[index.get() as usize];
containing_block_size.inline = containing_block_size.inline +
fragment.border_box.size.inline;
containing_block_size.block = max(containing_block_size.block,
fragment.border_box.size.block)
}
containing_block_size
}
} }
impl fmt::Debug for InlineFlow { impl fmt::Debug for InlineFlow {

View file

@ -11,7 +11,7 @@ use block::BlockFlow;
use context::LayoutContext; use context::LayoutContext;
use display_list_builder::ListItemFlowDisplayListBuilding; use display_list_builder::ListItemFlowDisplayListBuilding;
use floats::FloatKind; use floats::FloatKind;
use flow::{Flow, FlowClass}; use flow::{Flow, FlowClass, OpaqueFlow};
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedContentInfo}; use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedContentInfo};
use generated_content; use generated_content;
use incremental::RESOLVE_GENERATED_CONTENT; use incremental::RESOLVE_GENERATED_CONTENT;
@ -22,7 +22,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect}; use geom::{Point2D, Rect};
use gfx::display_list::DisplayList; use gfx::display_list::DisplayList;
use util::geometry::Au; use util::geometry::Au;
use util::logical_geometry::LogicalRect; use util::logical_geometry::LogicalSize;
use util::opts; use util::opts;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::computed_values::list_style_type; use style::computed_values::list_style_type;
@ -148,8 +148,8 @@ impl Flow for ListItemFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> { fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_rect() self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,

View file

@ -9,13 +9,13 @@
use block::BlockFlow; use block::BlockFlow;
use context::LayoutContext; use context::LayoutContext;
use floats::FloatKind; use floats::FloatKind;
use flow::{FlowClass, Flow}; use flow::{FlowClass, Flow, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator}; use fragment::{Fragment, FragmentBorderBoxIterator};
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect}; use geom::{Point2D, Rect};
use util::geometry::Au; use util::geometry::Au;
use util::logical_geometry::LogicalRect; use util::logical_geometry::LogicalSize;
use std::fmt; use std::fmt;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use std::sync::Arc; use std::sync::Arc;
@ -88,8 +88,8 @@ impl Flow for MulticolFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> { fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_rect() self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,

View file

@ -11,7 +11,7 @@ use block::{ISizeConstraintInput, ISizeConstraintSolution};
use context::LayoutContext; use context::LayoutContext;
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode}; use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
use flow::{self, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; use flow::{self, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
use flow::{ImmutableFlowUtils}; use flow::{ImmutableFlowUtils, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator}; use fragment::{Fragment, FragmentBorderBoxIterator};
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW}; use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
use layout_debug; use layout_debug;
@ -32,7 +32,7 @@ use style::properties::ComputedValues;
use style::values::CSSFloat; use style::values::CSSFloat;
use style::values::computed::LengthOrPercentageOrAuto; use style::values::computed::LengthOrPercentageOrAuto;
use util::geometry::Au; use util::geometry::Au;
use util::logical_geometry::LogicalRect; use util::logical_geometry::LogicalSize;
/// A table flow corresponded to the table's internal table fragment under a table wrapper flow. /// A table flow corresponded to the table's internal table fragment under a table wrapper flow.
/// The properties `position`, `float`, and `margin-*` are used on the table wrapper fragment, /// The properties `position`, `float`, and `margin-*` are used on the table wrapper fragment,
@ -507,8 +507,8 @@ impl Flow for TableFlow {
self.block_flow.compute_absolute_position() self.block_flow.compute_absolute_position()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> { fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_rect() self.block_flow.generated_containing_block_size(flow)
} }
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) { fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {

View file

@ -8,13 +8,13 @@
use block::BlockFlow; use block::BlockFlow;
use context::LayoutContext; use context::LayoutContext;
use flow::{FlowClass, Flow}; use flow::{FlowClass, Flow, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator}; use fragment::{Fragment, FragmentBorderBoxIterator};
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect}; use geom::{Point2D, Rect};
use util::geometry::Au; use util::geometry::Au;
use util::logical_geometry::LogicalRect; use util::logical_geometry::LogicalSize;
use std::fmt; use std::fmt;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use std::sync::Arc; use std::sync::Arc;
@ -89,8 +89,8 @@ impl Flow for TableCaptionFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> { fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_rect() self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,

View file

@ -10,7 +10,7 @@ use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
use context::LayoutContext; use context::LayoutContext;
use css::node_style::StyledNode; use css::node_style::StyledNode;
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode}; use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
use flow::{Flow, FlowClass}; use flow::{Flow, FlowClass, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator}; use fragment::{Fragment, FragmentBorderBoxIterator};
use model::MaybeAuto; use model::MaybeAuto;
use layout_debug; use layout_debug;
@ -27,7 +27,7 @@ use style::computed_values::{border_collapse, border_top_style};
use style::legacy::UnsignedIntegerAttribute; use style::legacy::UnsignedIntegerAttribute;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use util::geometry::Au; use util::geometry::Au;
use util::logical_geometry::{LogicalMargin, LogicalRect, WritingMode}; use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
/// A table formatting context. /// A table formatting context.
#[derive(RustcEncodable)] #[derive(RustcEncodable)]
@ -204,8 +204,8 @@ impl Flow for TableCellFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> { fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_rect() self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,

View file

@ -8,7 +8,7 @@
use context::LayoutContext; use context::LayoutContext;
use css::node_style::StyledNode; use css::node_style::StyledNode;
use flow::{BaseFlow, FlowClass, Flow, ForceNonfloatedFlag}; use flow::{BaseFlow, FlowClass, Flow, ForceNonfloatedFlag, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo}; use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
use layout_debug; use layout_debug;
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
@ -20,6 +20,7 @@ use std::fmt;
use style::values::computed::LengthOrPercentageOrAuto; use style::values::computed::LengthOrPercentageOrAuto;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use std::sync::Arc; use std::sync::Arc;
use util::logical_geometry::LogicalSize;
/// A table formatting context. /// A table formatting context.
pub struct TableColGroupFlow { pub struct TableColGroupFlow {
@ -101,6 +102,10 @@ impl Flow for TableColGroupFlow {
ZERO_RECT ZERO_RECT
} }
fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au> {
panic!("Table column groups can't be containing blocks!")
}
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,
_: &mut FragmentBorderBoxIterator, _: &mut FragmentBorderBoxIterator,
_: &Point2D<Au>) {} _: &Point2D<Au>) {}

View file

@ -9,7 +9,7 @@
use block::{BlockFlow, ISizeAndMarginsComputer}; use block::{BlockFlow, ISizeAndMarginsComputer};
use context::LayoutContext; use context::LayoutContext;
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode}; use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
use flow::{self, FlowClass, Flow, ImmutableFlowUtils}; use flow::{self, FlowClass, Flow, ImmutableFlowUtils, OpaqueFlow};
use flow_list::MutFlowListIterator; use flow_list::MutFlowListIterator;
use fragment::{Fragment, FragmentBorderBoxIterator}; use fragment::{Fragment, FragmentBorderBoxIterator};
use layout_debug; use layout_debug;
@ -30,7 +30,7 @@ use style::computed_values::{border_collapse, border_spacing, border_top_style};
use style::properties::ComputedValues; use style::properties::ComputedValues;
use style::values::computed::LengthOrPercentageOrAuto; use style::values::computed::LengthOrPercentageOrAuto;
use util::geometry::Au; use util::geometry::Au;
use util::logical_geometry::{LogicalRect, PhysicalSide, WritingMode}; use util::logical_geometry::{LogicalSize, PhysicalSide, WritingMode};
/// A single row of a table. /// A single row of a table.
pub struct TableRowFlow { pub struct TableRowFlow {
@ -438,8 +438,8 @@ impl Flow for TableRowFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> { fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_rect() self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,

View file

@ -8,7 +8,7 @@
use block::{BlockFlow, ISizeAndMarginsComputer}; use block::{BlockFlow, ISizeAndMarginsComputer};
use context::LayoutContext; use context::LayoutContext;
use flow::{FlowClass, Flow}; use flow::{FlowClass, Flow, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator}; use fragment::{Fragment, FragmentBorderBoxIterator};
use layout_debug; use layout_debug;
use style::computed_values::{border_collapse, border_spacing}; use style::computed_values::{border_collapse, border_spacing};
@ -23,7 +23,7 @@ use std::iter::{IntoIterator, Iterator, Peekable};
use std::sync::Arc; use std::sync::Arc;
use style::properties::ComputedValues; use style::properties::ComputedValues;
use util::geometry::Au; use util::geometry::Au;
use util::logical_geometry::{LogicalRect, WritingMode}; use util::logical_geometry::{LogicalSize, WritingMode};
/// A table formatting context. /// A table formatting context.
pub struct TableRowGroupFlow { pub struct TableRowGroupFlow {
@ -228,8 +228,8 @@ impl Flow for TableRowGroupFlow {
self.block_flow.compute_overflow() self.block_flow.compute_overflow()
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> { fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_rect() self.block_flow.generated_containing_block_size(flow)
} }
fn iterate_through_fragment_border_boxes(&self, fn iterate_through_fragment_border_boxes(&self,

View file

@ -18,7 +18,7 @@ use block::{ISizeConstraintSolution, MarginsMayCollapseFlag};
use context::LayoutContext; use context::LayoutContext;
use floats::FloatKind; use floats::FloatKind;
use flow::{FlowClass, Flow, ImmutableFlowUtils}; use flow::{FlowClass, Flow, ImmutableFlowUtils};
use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS, OpaqueFlow};
use fragment::{Fragment, FragmentBorderBoxIterator}; use fragment::{Fragment, FragmentBorderBoxIterator};
use model::MaybeAuto; use model::MaybeAuto;
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize}; use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
@ -27,7 +27,7 @@ use wrapper::ThreadSafeLayoutNode;
use geom::{Point2D, Rect}; use geom::{Point2D, Rect};
use util::geometry::Au; use util::geometry::Au;
use util::logical_geometry::LogicalRect; use util::logical_geometry::LogicalSize;
use std::cmp::{max, min}; use std::cmp::{max, min};
use std::fmt; use std::fmt;
use std::ops::Add; use std::ops::Add;
@ -397,8 +397,8 @@ impl Flow for TableWrapperFlow {
self.block_flow.update_late_computed_block_position_if_necessary(block_position) self.block_flow.update_late_computed_block_position_if_necessary(block_position)
} }
fn generated_containing_block_rect(&self) -> LogicalRect<Au> { fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
self.block_flow.generated_containing_block_rect() self.block_flow.generated_containing_block_size(flow)
} }
fn build_display_list(&mut self, layout_context: &LayoutContext) { fn build_display_list(&mut self, layout_context: &LayoutContext) {

View file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<style>
html, body {
margin: 0;
font-size: 0.1px;
line-height: 0;
}
#a {
padding-left: 100px;
}
#b {
position: relative;
}
#c {
position: absolute;
left: 0;
top: 0;
width: 100px;
height: 100px;
background: purple;
}
</style>
</head>
<body>
<div><span id=a>&nbsp;</span><span id=b>&nbsp;<div id=c></div></span></span></div>
</body>
</html>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<style>
html, body {
margin: 0;
font-size: 0.1px;
}
#a {
position: absolute;
left: 100px;
top: 0;
width: 100px;
height: 100px;
background: purple;
}
</style>
</head>
<body>
<div id=a></div>
</body>
</html>

View file

@ -12,6 +12,7 @@ fragment=top != ../html/acid2.html acid2_ref.html
== 2dcontext/lineto_a.html 2dcontext/lineto_ref.html == 2dcontext/lineto_a.html 2dcontext/lineto_ref.html
== 2dcontext/transform_a.html 2dcontext/transform_ref.html == 2dcontext/transform_a.html 2dcontext/transform_ref.html
== absolute_inline_containing_block_a.html absolute_inline_containing_block_ref.html
== acid1_a.html acid1_b.html == acid1_a.html acid1_b.html
== acid2_noscroll.html acid2_ref_broken.html == acid2_noscroll.html acid2_ref_broken.html
== after_block_iteration.html after_block_iteration_ref.html == after_block_iteration.html after_block_iteration_ref.html