зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #5911 - layout: Allow inline elements to be containing blocks for absolutely-positioned elements (from pcwalton:absolute-inline-containing-blocks); r=mbrubeck
r? @mbrubeck Source-Repo: https://github.com/servo/servo Source-Revision: c0ee952a2a7054dcc7e97990a625c281322dd526
This commit is contained in:
Родитель
30d6380a36
Коммит
c918f5d92e
|
@ -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
|
||||
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.
|
||||
///
|
||||
/// 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,8 +2576,9 @@ 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
|
||||
|
@ -2610,9 +2586,13 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
|
|||
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,
|
||||
|
|
|
@ -24,12 +24,9 @@ use flow::{IS_ABSOLUTELY_POSITIONED};
|
|||
use flow;
|
||||
use flow_ref::FlowRef;
|
||||
use fragment::{Fragment, GeneratedContentInfo, IframeFragmentInfo};
|
||||
use fragment::CanvasFragmentInfo;
|
||||
use fragment::ImageFragmentInfo;
|
||||
use fragment::InlineAbsoluteHypotheticalFragmentInfo;
|
||||
use fragment::TableColumnFragmentInfo;
|
||||
use fragment::UnscannedTextFragmentInfo;
|
||||
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo};
|
||||
use fragment::{CanvasFragmentInfo, ImageFragmentInfo, InlineAbsoluteFragmentInfo};
|
||||
use fragment::{InlineAbsoluteHypotheticalFragmentInfo, TableColumnFragmentInfo};
|
||||
use fragment::{InlineBlockFragmentInfo, SpecificFragmentInfo, UnscannedTextFragmentInfo};
|
||||
use incremental::{RECONSTRUCT_FLOW, RestyleDamage};
|
||||
use inline::{InlineFlow, InlineFragmentNodeInfo};
|
||||
use list_item::{ListItemFlow, ListStyleTypeContent};
|
||||
|
@ -121,7 +118,7 @@ pub struct InlineFragmentsConstructionResult {
|
|||
pub splits: LinkedList<InlineBlockSplit>,
|
||||
|
||||
/// Any fragments that succeed the {ib} splits.
|
||||
pub fragments: LinkedList<Fragment>,
|
||||
pub fragments: IntermediateInlineFragments,
|
||||
|
||||
/// Any absolute descendants that we're bubbling up.
|
||||
pub abs_descendants: AbsDescendants,
|
||||
|
@ -156,16 +153,44 @@ pub struct InlineFragmentsConstructionResult {
|
|||
#[derive(Clone)]
|
||||
pub struct InlineBlockSplit {
|
||||
/// The inline fragments that precede the flow.
|
||||
pub predecessors: LinkedList<Fragment>,
|
||||
pub predecessors: IntermediateInlineFragments,
|
||||
|
||||
/// The flow that caused this {ib} split.
|
||||
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.
|
||||
struct InlineFragmentsAccumulator {
|
||||
/// 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
|
||||
/// outer node is an inline and None otherwise.
|
||||
|
@ -175,37 +200,38 @@ struct InlineFragmentsAccumulator {
|
|||
impl InlineFragmentsAccumulator {
|
||||
fn new() -> InlineFragmentsAccumulator {
|
||||
InlineFragmentsAccumulator {
|
||||
fragments: LinkedList::new(),
|
||||
fragments: IntermediateInlineFragments::new(),
|
||||
enclosing_node: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn from_inline_node(node: &ThreadSafeLayoutNode) -> InlineFragmentsAccumulator {
|
||||
let fragments = LinkedList::new();
|
||||
InlineFragmentsAccumulator {
|
||||
fragments: fragments,
|
||||
fragments: IntermediateInlineFragments::new(),
|
||||
enclosing_node: Some(InlineFragmentNodeInfo {
|
||||
address: OpaqueNodeMethods::from_thread_safe_layout_node(node),
|
||||
style: node.style().clone() }),
|
||||
address: OpaqueNodeMethods::from_thread_safe_layout_node(node),
|
||||
style: node.style().clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
fn push_all(&mut self, mut fragments: LinkedList<Fragment>) {
|
||||
if fragments.len() == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
self.fragments.append(&mut fragments)
|
||||
fn push(&mut self, fragment: Fragment) {
|
||||
self.fragments.fragments.push_back(fragment)
|
||||
}
|
||||
|
||||
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 {
|
||||
mut fragments,
|
||||
enclosing_node,
|
||||
} = self;
|
||||
if let Some(enclosing_node) = enclosing_node {
|
||||
let frag_len = fragments.len();
|
||||
for (idx, frag) in fragments.iter_mut().enumerate() {
|
||||
let frag_len = fragments.fragments.len();
|
||||
for (idx, frag) in fragments.fragments.iter_mut().enumerate() {
|
||||
|
||||
// frag is first inline fragment in the inline node
|
||||
let is_first = idx == 0;
|
||||
|
@ -355,7 +381,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
flow_list: &mut Vec<FlowRef>,
|
||||
whitespace_stripping: WhitespaceStrippingMode,
|
||||
node: &ThreadSafeLayoutNode) {
|
||||
let mut fragments = fragment_accumulator.to_dlist();
|
||||
let mut fragments = fragment_accumulator.to_intermediate_inline_fragments();
|
||||
if fragments.is_empty() {
|
||||
return
|
||||
};
|
||||
|
@ -363,13 +389,13 @@ impl<'a> FlowConstructor<'a> {
|
|||
match whitespace_stripping {
|
||||
WhitespaceStrippingMode::None => {}
|
||||
WhitespaceStrippingMode::FromStart => {
|
||||
strip_ignorable_whitespace_from_start(&mut fragments);
|
||||
strip_ignorable_whitespace_from_start(&mut fragments.fragments);
|
||||
if fragments.is_empty() {
|
||||
return
|
||||
};
|
||||
}
|
||||
WhitespaceStrippingMode::FromEnd => {
|
||||
strip_ignorable_whitespace_from_end(&mut fragments);
|
||||
strip_ignorable_whitespace_from_end(&mut fragments.fragments);
|
||||
if fragments.is_empty() {
|
||||
return
|
||||
};
|
||||
|
@ -378,7 +404,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
|
||||
// Build a list of all the inline-block fragments before fragments is moved.
|
||||
let mut inline_block_flows = vec!();
|
||||
for fragment in fragments.iter() {
|
||||
for fragment in fragments.fragments.iter() {
|
||||
match fragment.specific {
|
||||
SpecificFragmentInfo::InlineBlock(ref info) => {
|
||||
inline_block_flows.push(info.flow_ref.clone())
|
||||
|
@ -386,6 +412,9 @@ impl<'a> FlowConstructor<'a> {
|
|||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => {
|
||||
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
|
||||
// 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.
|
||||
let fragments = TextRunScanner::new().scan_for_runs(self.layout_context.font_context(),
|
||||
fragments);
|
||||
let scanned_fragments =
|
||||
TextRunScanner::new().scan_for_runs(self.layout_context.font_context(),
|
||||
fragments.fragments);
|
||||
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.
|
||||
for inline_block_flow in inline_block_flows.iter() {
|
||||
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();
|
||||
|
||||
|
@ -447,7 +485,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
// Flush any inline fragments that we were gathering up. This allows us to
|
||||
// handle {ib} splits.
|
||||
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(
|
||||
mem::replace(inline_fragment_accumulator,
|
||||
InlineFragmentsAccumulator::new()),
|
||||
|
@ -491,7 +529,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
|
||||
// Flush any inline fragments that we were gathering up.
|
||||
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(
|
||||
mem::replace(inline_fragment_accumulator,
|
||||
InlineFragmentsAccumulator::new()),
|
||||
|
@ -526,7 +564,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
whitespace_style,
|
||||
whitespace_damage,
|
||||
fragment_info);
|
||||
inline_fragment_accumulator.fragments.push_back(fragment);
|
||||
inline_fragment_accumulator.fragments.fragments.push_back(fragment);
|
||||
}
|
||||
ConstructionResult::ConstructionItem(ConstructionItem::TableColumnFragment(_)) => {
|
||||
// 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
|
||||
/// appending the construction results of children to the child list of the block flow. {ib}
|
||||
/// splits and absolutely-positioned descendants are handled correctly.
|
||||
fn build_flow_for_block_starting_with_fragments(&mut self,
|
||||
mut flow: FlowRef,
|
||||
node: &ThreadSafeLayoutNode,
|
||||
mut initial_fragments: LinkedList<Fragment>)
|
||||
-> ConstructionResult {
|
||||
fn build_flow_for_block_starting_with_fragments(
|
||||
&mut self,
|
||||
mut flow: FlowRef,
|
||||
node: &ThreadSafeLayoutNode,
|
||||
initial_fragments: IntermediateInlineFragments)
|
||||
-> ConstructionResult {
|
||||
// Gather up fragments for the inline flows we might need to create.
|
||||
let mut inline_fragment_accumulator = InlineFragmentsAccumulator::new();
|
||||
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();
|
||||
|
||||
// List of absolute descendants, in tree order.
|
||||
|
@ -582,9 +621,9 @@ impl<'a> FlowConstructor<'a> {
|
|||
flow.finish();
|
||||
|
||||
// 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);
|
||||
if is_positioned {
|
||||
if contains_positioned_fragments {
|
||||
// This is the containing block for all the absolute descendants.
|
||||
flow.set_absolute_descendants(abs_descendants);
|
||||
|
||||
|
@ -611,7 +650,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
/// `<textarea>`.
|
||||
fn build_flow_for_block_like(&mut self, flow: FlowRef, node: &ThreadSafeLayoutNode)
|
||||
-> ConstructionResult {
|
||||
let mut initial_fragments = LinkedList::new();
|
||||
let mut initial_fragments = IntermediateInlineFragments::new();
|
||||
if node.get_pseudo_element_type() != PseudoElementType::Normal ||
|
||||
node.type_id() == Some(NodeTypeId::Element(ElementTypeId::HTMLElement(
|
||||
HTMLElementTypeId::HTMLInputElement))) ||
|
||||
|
@ -626,7 +665,9 @@ impl<'a> FlowConstructor<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
self.create_fragments_for_node_text_content(&mut initial_fragments, node, node.style());
|
||||
self.create_fragments_for_node_text_content(&mut initial_fragments,
|
||||
node,
|
||||
node.style());
|
||||
}
|
||||
|
||||
self.build_flow_for_block_starting_with_fragments(flow, node, initial_fragments)
|
||||
|
@ -634,7 +675,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
|
||||
/// Pushes fragments appropriate for the content of the given node onto the given list.
|
||||
fn create_fragments_for_node_text_content(&self,
|
||||
fragments: &mut LinkedList<Fragment>,
|
||||
fragments: &mut IntermediateInlineFragments,
|
||||
node: &ThreadSafeLayoutNode,
|
||||
style: &Arc<ComputedValues>) {
|
||||
for content_item in node.text_content().into_iter() {
|
||||
|
@ -650,7 +691,8 @@ impl<'a> FlowConstructor<'a> {
|
|||
};
|
||||
|
||||
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(),
|
||||
node.restyle_damage(),
|
||||
specific))
|
||||
|
@ -672,6 +714,30 @@ impl<'a> FlowConstructor<'a> {
|
|||
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.
|
||||
/// Returns the `InlineFragmentsConstructionResult`, if any. There will be no
|
||||
/// `InlineFragmentsConstructionResult` if this node consisted entirely of ignorable
|
||||
|
@ -689,18 +755,36 @@ impl<'a> FlowConstructor<'a> {
|
|||
}
|
||||
match kid.swap_out_construction_result() {
|
||||
ConstructionResult::None => {}
|
||||
ConstructionResult::Flow(flow, kid_abs_descendants) => {
|
||||
// {ib} split. Flush the accumulator to our new split and make a new
|
||||
// accumulator to hold any subsequent fragments we come across.
|
||||
let split = InlineBlockSplit {
|
||||
predecessors:
|
||||
mem::replace(
|
||||
&mut fragment_accumulator,
|
||||
InlineFragmentsAccumulator::from_inline_node(node)).to_dlist(),
|
||||
flow: flow,
|
||||
};
|
||||
opt_inline_block_splits.push_back(split);
|
||||
abs_descendants.push_descendants(kid_abs_descendants);
|
||||
ConstructionResult::Flow(mut flow, kid_abs_descendants) => {
|
||||
if !flow::base(&*flow).flags.contains(IS_ABSOLUTELY_POSITIONED) {
|
||||
// {ib} split. Flush the accumulator to our new split and make a new
|
||||
// accumulator to hold any subsequent fragments we come across.
|
||||
let split = InlineBlockSplit {
|
||||
predecessors:
|
||||
mem::replace(
|
||||
&mut fragment_accumulator,
|
||||
InlineFragmentsAccumulator::from_inline_node(
|
||||
node)).to_intermediate_inline_fragments(),
|
||||
flow: flow,
|
||||
};
|
||||
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(
|
||||
InlineFragmentsConstructionResult {
|
||||
|
@ -710,22 +794,10 @@ impl<'a> FlowConstructor<'a> {
|
|||
})) => {
|
||||
|
||||
// Bubble up {ib} splits.
|
||||
for split in splits.into_iter() {
|
||||
let InlineBlockSplit {
|
||||
predecessors,
|
||||
flow: kid_flow
|
||||
} = 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)
|
||||
}
|
||||
self.accumulate_inline_block_splits(splits,
|
||||
node,
|
||||
&mut fragment_accumulator,
|
||||
&mut opt_inline_block_splits);
|
||||
|
||||
// Push residual fragments.
|
||||
fragment_accumulator.push_all(successors);
|
||||
|
@ -743,7 +815,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
whitespace_style,
|
||||
whitespace_damage,
|
||||
fragment_info);
|
||||
fragment_accumulator.fragments.push_back(fragment)
|
||||
fragment_accumulator.fragments.fragments.push_back(fragment)
|
||||
}
|
||||
ConstructionResult::ConstructionItem(ConstructionItem::TableColumnFragment(_)) => {
|
||||
// TODO: Implement anonymous table objects for missing parents
|
||||
|
@ -753,12 +825,12 @@ impl<'a> FlowConstructor<'a> {
|
|||
}
|
||||
|
||||
// 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 {
|
||||
let construction_item = ConstructionItem::InlineFragments(
|
||||
InlineFragmentsConstructionResult {
|
||||
splits: opt_inline_block_splits,
|
||||
fragments: fragment_accumulator.to_dlist(),
|
||||
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
|
||||
abs_descendants: abs_descendants,
|
||||
});
|
||||
ConstructionResult::ConstructionItem(construction_item)
|
||||
|
@ -795,13 +867,13 @@ impl<'a> FlowConstructor<'a> {
|
|||
// 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 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()) {
|
||||
(_, Some(NodeTypeId::CharacterData(CharacterDataTypeId::Text))) => {
|
||||
self.create_fragments_for_node_text_content(&mut fragments, node, &style)
|
||||
}
|
||||
(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),
|
||||
}
|
||||
|
@ -827,13 +899,13 @@ impl<'a> FlowConstructor<'a> {
|
|||
block_flow));
|
||||
let fragment = Fragment::new(node, fragment_info);
|
||||
|
||||
let mut fragment_accumulator = InlineFragmentsAccumulator::new();
|
||||
fragment_accumulator.fragments.push_back(fragment);
|
||||
let mut fragment_accumulator = InlineFragmentsAccumulator::from_inline_node(node);
|
||||
fragment_accumulator.fragments.fragments.push_back(fragment);
|
||||
|
||||
let construction_item =
|
||||
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||
splits: LinkedList::new(),
|
||||
fragments: fragment_accumulator.to_dlist(),
|
||||
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
|
||||
abs_descendants: abs_descendants,
|
||||
});
|
||||
ConstructionResult::ConstructionItem(construction_item)
|
||||
|
@ -854,12 +926,12 @@ impl<'a> FlowConstructor<'a> {
|
|||
let fragment = Fragment::new(node, fragment_info);
|
||||
|
||||
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 =
|
||||
ConstructionItem::InlineFragments(InlineFragmentsConstructionResult {
|
||||
splits: LinkedList::new(),
|
||||
fragments: fragment_accumulator.to_dlist(),
|
||||
fragments: fragment_accumulator.to_intermediate_inline_fragments(),
|
||||
abs_descendants: abs_descendants,
|
||||
});
|
||||
ConstructionResult::ConstructionItem(construction_item)
|
||||
|
@ -973,11 +1045,11 @@ impl<'a> FlowConstructor<'a> {
|
|||
|
||||
// The flow is done.
|
||||
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_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.
|
||||
wrapper_flow.set_absolute_descendants(abs_descendants);
|
||||
|
||||
|
@ -1085,7 +1157,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
// 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
|
||||
// there.
|
||||
let mut initial_fragments = LinkedList::new();
|
||||
let mut initial_fragments = IntermediateInlineFragments::new();
|
||||
let main_fragment = self.build_fragment_for_block(node);
|
||||
let flow = match node.style().get_list().list_style_position {
|
||||
list_style_position::T::outside => {
|
||||
|
@ -1096,7 +1168,7 @@ impl<'a> FlowConstructor<'a> {
|
|||
}
|
||||
list_style_position::T::inside => {
|
||||
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,
|
||||
main_fragment,
|
||||
|
@ -1194,7 +1266,9 @@ impl<'a> FlowConstructor<'a> {
|
|||
}
|
||||
|
||||
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 {
|
||||
SpecificFragmentInfo::InlineBlock(ref mut inline_block_fragment) => {
|
||||
flow::mut_base(&mut *inline_block_fragment.flow_ref).restyle_damage
|
||||
|
|
|
@ -81,7 +81,7 @@ impl LayoutDataWrapper {
|
|||
ConstructionResult::ConstructionItem(ref construction_item) => {
|
||||
match construction_item {
|
||||
&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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1001,7 +1001,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
SpecificFragmentInfo::TableRow |
|
||||
SpecificFragmentInfo::TableWrapper |
|
||||
SpecificFragmentInfo::InlineBlock(_) |
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
||||
SpecificFragmentInfo::InlineAbsolute(_) => {
|
||||
if opts::get().show_debug_fragment_borders {
|
||||
self.build_debug_borders_around_fragment(display_list,
|
||||
stacking_relative_border_box,
|
||||
|
@ -1069,7 +1070,6 @@ impl FragmentDisplayListBuilding for Fragment {
|
|||
display_list: Box<DisplayList>,
|
||||
layer: Option<Arc<PaintLayer>>)
|
||||
-> Arc<StackingContext> {
|
||||
|
||||
let border_box = self.stacking_relative_border_box(&base_flow.stacking_relative_position,
|
||||
&base_flow.absolute_position_info
|
||||
.relative_containing_block_size,
|
||||
|
@ -1364,8 +1364,10 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
background_border_level);
|
||||
|
||||
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
|
||||
DisplayListBuildingResult::StackingContext(
|
||||
self.fragment.create_stacking_context(&self.base, display_list, None))
|
||||
DisplayListBuildingResult::StackingContext(self.fragment.create_stacking_context(
|
||||
&self.base,
|
||||
display_list,
|
||||
None))
|
||||
} else {
|
||||
match self.fragment.style.get_box().position {
|
||||
position::T::static_ => {}
|
||||
|
@ -1391,8 +1393,10 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
!self.base.flags.contains(NEEDS_LAYER) {
|
||||
// We didn't need a layer.
|
||||
self.base.display_list_building_result =
|
||||
DisplayListBuildingResult::StackingContext(
|
||||
self.fragment.create_stacking_context(&self.base, display_list, None));
|
||||
DisplayListBuildingResult::StackingContext(self.fragment.create_stacking_context(
|
||||
&self.base,
|
||||
display_list,
|
||||
None));
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -1403,7 +1407,6 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
|
|||
ScrollPolicy::Scrollable
|
||||
};
|
||||
|
||||
|
||||
let transparent = color::transparent();
|
||||
let stacking_context = self.fragment.create_stacking_context(
|
||||
&self.base,
|
||||
|
@ -1492,6 +1495,11 @@ impl InlineFlowDisplayListBuilding for InlineFlow {
|
|||
flow::mut_base(block_flow).display_list_building_result
|
||||
.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)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -324,19 +324,15 @@ pub trait Flow: fmt::Debug + Sync {
|
|||
self.positioning() == position::T::fixed
|
||||
}
|
||||
|
||||
fn is_positioned(&self) -> bool {
|
||||
self.is_relatively_positioned() || base(self).flags.contains(IS_ABSOLUTELY_POSITIONED)
|
||||
fn contains_positioned_fragments(&self) -> bool {
|
||||
self.contains_relatively_positioned_fragments() ||
|
||||
base(self).flags.contains(IS_ABSOLUTELY_POSITIONED)
|
||||
}
|
||||
|
||||
fn is_relatively_positioned(&self) -> bool {
|
||||
fn contains_relatively_positioned_fragments(&self) -> bool {
|
||||
self.positioning() == position::T::relative
|
||||
}
|
||||
|
||||
/// Return true if this is the root of an absolute flow tree.
|
||||
fn is_root_of_absolute_flow_tree(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Returns true if this is an absolute containing block.
|
||||
fn is_absolute_containing_block(&self) -> bool {
|
||||
false
|
||||
|
@ -350,14 +346,12 @@ pub trait Flow: fmt::Debug + Sync {
|
|||
/// this is only used for absolutely-positioned inline-blocks.
|
||||
fn update_late_computed_block_position_if_necessary(&mut self, block_position: Au);
|
||||
|
||||
/// Return the dimensions of the containing block generated by this flow for absolutely-
|
||||
/// positioned descendants. For block flows, this is the padding box.
|
||||
/// Return the size of the containing block generated by this flow for the absolutely-
|
||||
/// positioned descendant referenced by `for_flow`. For block flows, this is the padding box.
|
||||
///
|
||||
/// NB: Do not change this `&self` to `&mut self` under any circumstances! It has security
|
||||
/// implications because this can be called on parents concurrently from descendants!
|
||||
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
|
||||
panic!("generated_containing_block_rect not yet implemented for this flow")
|
||||
}
|
||||
fn generated_containing_block_size(&self, _: OpaqueFlow) -> LogicalSize<Au>;
|
||||
|
||||
/// Returns a layer ID for the given fragment.
|
||||
#[allow(unsafe_code)]
|
||||
|
@ -440,6 +434,9 @@ pub trait ImmutableFlowUtils {
|
|||
/// Generates missing child flow of this flow.
|
||||
fn generate_missing_child_flow(self, node: &ThreadSafeLayoutNode) -> FlowRef;
|
||||
|
||||
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
|
||||
fn contains_roots_of_absolute_flow_tree(&self) -> bool;
|
||||
|
||||
/// Returns true if this flow has no children.
|
||||
fn is_leaf(self) -> bool;
|
||||
|
||||
|
@ -471,6 +468,21 @@ pub trait MutableFlowUtils {
|
|||
/// Traverses the tree in postorder.
|
||||
fn traverse_postorder<T:PostorderFlowTraversal>(self, traversal: &T);
|
||||
|
||||
/// Traverse the Absolute flow tree in preorder.
|
||||
///
|
||||
/// Traverse all your direct absolute descendants, who will then traverse
|
||||
/// their direct absolute descendants.
|
||||
///
|
||||
/// Return true if the traversal is to continue or false to stop.
|
||||
fn traverse_preorder_absolute_flows<T>(&mut self, traversal: &mut T)
|
||||
where T: PreorderFlowTraversal;
|
||||
|
||||
/// Traverse the Absolute flow tree in postorder.
|
||||
///
|
||||
/// Return true if the traversal is to continue or false to stop.
|
||||
fn traverse_postorder_absolute_flows<T>(&mut self, traversal: &mut T)
|
||||
where T: PostorderFlowTraversal;
|
||||
|
||||
// Mutators
|
||||
|
||||
/// Calls `repair_style` and `bubble_inline_sizes`. You should use this method instead of
|
||||
|
@ -1183,6 +1195,11 @@ impl<'a> ImmutableFlowUtils for &'a (Flow + 'a) {
|
|||
FlowRef::new(flow)
|
||||
}
|
||||
|
||||
/// Returns true if this flow contains fragments that are roots of an absolute flow tree.
|
||||
fn contains_roots_of_absolute_flow_tree(&self) -> bool {
|
||||
self.contains_relatively_positioned_fragments() || self.is_root()
|
||||
}
|
||||
|
||||
/// Returns true if this flow has no children.
|
||||
fn is_leaf(self) -> bool {
|
||||
base(self).children.len() == 0
|
||||
|
@ -1276,6 +1293,34 @@ impl<'a> MutableFlowUtils for &'a mut (Flow + 'a) {
|
|||
self.repair_style(style);
|
||||
self.bubble_inline_sizes();
|
||||
}
|
||||
|
||||
/// Traverse the Absolute flow tree in preorder.
|
||||
///
|
||||
/// Traverse all your direct absolute descendants, who will then traverse
|
||||
/// their direct absolute descendants.
|
||||
///
|
||||
/// Return true if the traversal is to continue or false to stop.
|
||||
fn traverse_preorder_absolute_flows<T>(&mut self, traversal: &mut T)
|
||||
where T: PreorderFlowTraversal {
|
||||
traversal.process(*self);
|
||||
|
||||
let descendant_offset_iter = mut_base(*self).abs_descendants.iter();
|
||||
for ref mut descendant_link in descendant_offset_iter {
|
||||
descendant_link.traverse_preorder_absolute_flows(traversal)
|
||||
}
|
||||
}
|
||||
|
||||
/// Traverse the Absolute flow tree in postorder.
|
||||
///
|
||||
/// Return true if the traversal is to continue or false to stop.
|
||||
fn traverse_postorder_absolute_flows<T>(&mut self, traversal: &mut T)
|
||||
where T: PostorderFlowTraversal {
|
||||
for mut descendant_link in mut_base(*self).abs_descendants.iter() {
|
||||
descendant_link.traverse_postorder_absolute_flows(traversal);
|
||||
}
|
||||
|
||||
traversal.process(*self)
|
||||
}
|
||||
}
|
||||
|
||||
impl MutableOwnedFlowUtils for FlowRef {
|
||||
|
@ -1288,13 +1333,11 @@ impl MutableOwnedFlowUtils for FlowRef {
|
|||
/// construction is allowed to possess.
|
||||
fn set_absolute_descendants(&mut self, abs_descendants: AbsDescendants) {
|
||||
let this = self.clone();
|
||||
|
||||
let block = self.as_block();
|
||||
block.base.abs_descendants = abs_descendants;
|
||||
|
||||
for descendant_link in block.base.abs_descendants.iter() {
|
||||
let base = mut_base(descendant_link);
|
||||
base.absolute_cb.set(this.clone());
|
||||
let base = mut_base(&mut **self);
|
||||
base.abs_descendants = abs_descendants;
|
||||
for descendant_link in base.abs_descendants.iter() {
|
||||
let descendant_base = mut_base(descendant_link);
|
||||
descendant_base.absolute_cb.set(this.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1329,10 +1372,33 @@ impl ContainingBlockLink {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn generated_containing_block_rect(&mut self) -> LogicalRect<Au> {
|
||||
pub fn generated_containing_block_size(&mut self, for_flow: OpaqueFlow) -> LogicalSize<Au> {
|
||||
match self.link {
|
||||
None => panic!("haven't done it"),
|
||||
Some(ref mut link) => link.generated_containing_block_rect(),
|
||||
None => {
|
||||
panic!("Link to containing block not established; perhaps you forgot to call \
|
||||
`set_absolute_descendants`?")
|
||||
}
|
||||
Some(ref mut link) => link.generated_containing_block_size(for_flow),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A wrapper for the pointer address of a flow. These pointer addresses may only be compared for
|
||||
/// equality with other such pointer addresses, never dereferenced.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct OpaqueFlow(pub usize);
|
||||
|
||||
impl OpaqueFlow {
|
||||
#[allow(unsafe_code)]
|
||||
pub fn from_flow(flow: &Flow) -> OpaqueFlow {
|
||||
unsafe {
|
||||
let object = mem::transmute::<&Flow,raw::TraitObject>(flow);
|
||||
OpaqueFlow(object.data as usize)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_base_flow(base_flow: &BaseFlow) -> OpaqueFlow {
|
||||
OpaqueFlow(base_flow as *const BaseFlow as usize)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -149,6 +149,11 @@ pub enum SpecificFragmentInfo {
|
|||
InlineAbsoluteHypothetical(InlineAbsoluteHypotheticalFragmentInfo),
|
||||
|
||||
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>),
|
||||
Table,
|
||||
TableCell,
|
||||
|
@ -175,6 +180,7 @@ impl SpecificFragmentInfo {
|
|||
SpecificFragmentInfo::UnscannedText(_) |
|
||||
SpecificFragmentInfo::Generic => return RestyleDamage::empty(),
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref info) => &info.flow_ref,
|
||||
SpecificFragmentInfo::InlineAbsolute(ref info) => &info.flow_ref,
|
||||
SpecificFragmentInfo::InlineBlock(ref info) => &info.flow_ref,
|
||||
};
|
||||
|
||||
|
@ -188,6 +194,7 @@ impl SpecificFragmentInfo {
|
|||
SpecificFragmentInfo::GeneratedContent(_) => "SpecificFragmentInfo::GeneratedContent",
|
||||
SpecificFragmentInfo::Iframe(_) => "SpecificFragmentInfo::Iframe",
|
||||
SpecificFragmentInfo::Image(_) => "SpecificFragmentInfo::Image",
|
||||
SpecificFragmentInfo::InlineAbsolute(_) => "SpecificFragmentInfo::InlineAbsolute",
|
||||
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)]
|
||||
pub struct CanvasFragmentInfo {
|
||||
pub replaced_image_fragment_info: ReplacedImageFragmentInfo,
|
||||
|
@ -868,7 +893,8 @@ impl Fragment {
|
|||
SpecificFragmentInfo::Generic |
|
||||
SpecificFragmentInfo::GeneratedContent(_) |
|
||||
SpecificFragmentInfo::Iframe(_) |
|
||||
SpecificFragmentInfo::Image(_) => {
|
||||
SpecificFragmentInfo::Image(_) |
|
||||
SpecificFragmentInfo::InlineAbsolute(_) => {
|
||||
QuantitiesIncludedInIntrinsicInlineSizes::all()
|
||||
}
|
||||
SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => {
|
||||
|
@ -1247,6 +1273,10 @@ impl Fragment {
|
|||
let block_flow = info.flow_ref.as_block();
|
||||
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) => {
|
||||
let image_inline_size = match image_fragment_info.replaced_image_fragment_info
|
||||
.dom_inline_size {
|
||||
|
@ -1318,7 +1348,8 @@ impl Fragment {
|
|||
SpecificFragmentInfo::TableRow |
|
||||
SpecificFragmentInfo::TableWrapper |
|
||||
SpecificFragmentInfo::InlineBlock(_) |
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => Au(0),
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
||||
SpecificFragmentInfo::InlineAbsolute(_) => Au(0),
|
||||
SpecificFragmentInfo::Canvas(ref canvas_fragment_info) => {
|
||||
canvas_fragment_info.replaced_image_fragment_info.computed_inline_size()
|
||||
}
|
||||
|
@ -1608,6 +1639,7 @@ impl Fragment {
|
|||
SpecificFragmentInfo::Iframe(_) |
|
||||
SpecificFragmentInfo::InlineBlock(_) |
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
||||
SpecificFragmentInfo::InlineAbsolute(_) |
|
||||
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_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) => {
|
||||
// Scanned text fragments will have already had their content inline-sizes assigned
|
||||
// by this point.
|
||||
|
@ -1690,6 +1730,7 @@ impl Fragment {
|
|||
SpecificFragmentInfo::Image(_) |
|
||||
SpecificFragmentInfo::InlineBlock(_) |
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
||||
SpecificFragmentInfo::InlineAbsolute(_) |
|
||||
SpecificFragmentInfo::ScannedText(_) => {}
|
||||
}
|
||||
|
||||
|
@ -1735,6 +1776,12 @@ impl Fragment {
|
|||
let block_flow = info.flow_ref.as_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(_) => {
|
||||
self.border_box.size.block = IframeFragmentInfo::calculate_replaced_block_size(
|
||||
style, containing_block_block_size) +
|
||||
|
@ -1774,7 +1821,8 @@ impl Fragment {
|
|||
block_flow.fragment.margin.block_start,
|
||||
block_flow.fragment.margin.block_end)
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) => {
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
||||
SpecificFragmentInfo::InlineAbsolute(_) => {
|
||||
// Hypothetical boxes take up no space.
|
||||
InlineMetrics {
|
||||
block_size_above_baseline: Au(0),
|
||||
|
@ -1829,6 +1877,7 @@ impl Fragment {
|
|||
match self.specific {
|
||||
SpecificFragmentInfo::InlineBlock(_) |
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(_) |
|
||||
SpecificFragmentInfo::InlineAbsolute(_) |
|
||||
SpecificFragmentInfo::TableWrapper => false,
|
||||
SpecificFragmentInfo::Canvas(_) |
|
||||
SpecificFragmentInfo::Generic |
|
||||
|
|
|
@ -4,11 +4,13 @@
|
|||
|
||||
#![deny(unsafe_code)]
|
||||
|
||||
use block::{AbsoluteAssignBSizesTraversal, AbsoluteStoreOverflowTraversal};
|
||||
use css::node_style::StyledNode;
|
||||
use context::LayoutContext;
|
||||
use display_list_builder::{FragmentDisplayListBuilding, InlineFlowDisplayListBuilding};
|
||||
use floats::{FloatKind, Floats, PlacementInfo};
|
||||
use flow::{self, BaseFlow, FlowClass, Flow, ForceNonfloatedFlag, IS_ABSOLUTELY_POSITIONED};
|
||||
use flow::{MutableFlowUtils, OpaqueFlow};
|
||||
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW, RESOLVE_GENERATED_CONTENT};
|
||||
use layout_debug;
|
||||
|
@ -16,7 +18,7 @@ use model::IntrinsicISizesContribution;
|
|||
use text;
|
||||
|
||||
use collections::VecDeque;
|
||||
use geom::{Point2D, Rect};
|
||||
use geom::{Point2D, Rect, Size2D};
|
||||
use gfx::display_list::OpaqueNode;
|
||||
use gfx::font::FontMetrics;
|
||||
use gfx::font_context::FontContext;
|
||||
|
@ -27,10 +29,10 @@ use std::fmt;
|
|||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use std::u16;
|
||||
use style::computed_values::{display, overflow_x, text_align, text_justify, text_overflow};
|
||||
use style::computed_values::{vertical_align, white_space};
|
||||
use style::computed_values::{display, overflow_x, position, text_align, text_justify};
|
||||
use style::computed_values::{text_overflow, vertical_align, white_space};
|
||||
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::range::{Range, RangeIndex};
|
||||
use util;
|
||||
|
@ -1121,6 +1123,45 @@ impl InlineFlow {
|
|||
|
||||
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 {
|
||||
|
@ -1398,6 +1439,19 @@ impl Flow for InlineFlow {
|
|||
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() {
|
||||
Some(ref last_line) => last_line.bounds.start.b + last_line.bounds.size.block,
|
||||
None => Au(0),
|
||||
|
@ -1412,6 +1466,26 @@ impl Flow for InlineFlow {
|
|||
}
|
||||
|
||||
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() {
|
||||
let stacking_relative_border_box =
|
||||
fragment.stacking_relative_border_box(&self.base.stacking_relative_position,
|
||||
|
@ -1427,10 +1501,11 @@ impl Flow for InlineFlow {
|
|||
match fragment.specific {
|
||||
SpecificFragmentInfo::InlineBlock(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;
|
||||
block_flow.base.stacking_relative_position =
|
||||
stacking_relative_border_box.origin;
|
||||
stacking_relative_border_box.origin
|
||||
}
|
||||
SpecificFragmentInfo::InlineAbsoluteHypothetical(ref mut info) => {
|
||||
flow::mut_base(&mut *info.flow_ref).clip = clip;
|
||||
|
@ -1440,6 +1515,22 @@ impl Flow for InlineFlow {
|
|||
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 +1582,30 @@ impl Flow for InlineFlow {
|
|||
(*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 {
|
||||
|
|
|
@ -807,11 +807,6 @@ impl LayoutTask {
|
|||
ScrollPolicy::Scrollable));
|
||||
let origin = Rect(Point2D(Au(0), Au(0)), root_size);
|
||||
|
||||
if opts::get().dump_display_list {
|
||||
println!("#### start printing display list.");
|
||||
display_list.print_items(String::from_str("#"));
|
||||
}
|
||||
|
||||
let stacking_context = Arc::new(StackingContext::new(display_list,
|
||||
&origin,
|
||||
&origin,
|
||||
|
@ -821,6 +816,11 @@ impl LayoutTask {
|
|||
mix_blend_mode::T::normal,
|
||||
Some(paint_layer)));
|
||||
|
||||
if opts::get().dump_display_list {
|
||||
println!("#### start printing display list.");
|
||||
stacking_context.print(String::from_str("#"));
|
||||
}
|
||||
|
||||
rw_data.stacking_context = Some(stacking_context.clone());
|
||||
|
||||
debug!("Layout done!");
|
||||
|
|
|
@ -11,7 +11,7 @@ use block::BlockFlow;
|
|||
use context::LayoutContext;
|
||||
use display_list_builder::ListItemFlowDisplayListBuilding;
|
||||
use floats::FloatKind;
|
||||
use flow::{Flow, FlowClass};
|
||||
use flow::{Flow, FlowClass, OpaqueFlow};
|
||||
use fragment::{CoordinateSystem, Fragment, FragmentBorderBoxIterator, GeneratedContentInfo};
|
||||
use generated_content;
|
||||
use incremental::RESOLVE_GENERATED_CONTENT;
|
||||
|
@ -22,7 +22,7 @@ use wrapper::ThreadSafeLayoutNode;
|
|||
use geom::{Point2D, Rect};
|
||||
use gfx::display_list::DisplayList;
|
||||
use util::geometry::Au;
|
||||
use util::logical_geometry::LogicalRect;
|
||||
use util::logical_geometry::LogicalSize;
|
||||
use util::opts;
|
||||
use style::properties::ComputedValues;
|
||||
use style::computed_values::list_style_type;
|
||||
|
@ -148,8 +148,8 @@ impl Flow for ListItemFlow {
|
|||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
|
||||
self.block_flow.generated_containing_block_rect()
|
||||
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
|
||||
self.block_flow.generated_containing_block_size(flow)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
use block::BlockFlow;
|
||||
use context::LayoutContext;
|
||||
use floats::FloatKind;
|
||||
use flow::{FlowClass, Flow};
|
||||
use flow::{FlowClass, Flow, OpaqueFlow};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::{Point2D, Rect};
|
||||
use util::geometry::Au;
|
||||
use util::logical_geometry::LogicalRect;
|
||||
use util::logical_geometry::LogicalSize;
|
||||
use std::fmt;
|
||||
use style::properties::ComputedValues;
|
||||
use std::sync::Arc;
|
||||
|
@ -88,8 +88,8 @@ impl Flow for MulticolFlow {
|
|||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
|
||||
self.block_flow.generated_containing_block_rect()
|
||||
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
|
||||
self.block_flow.generated_containing_block_size(flow)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
|
|
|
@ -11,7 +11,7 @@ use block::{ISizeConstraintInput, ISizeConstraintSolution};
|
|||
use context::LayoutContext;
|
||||
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
|
||||
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 incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
|
||||
use layout_debug;
|
||||
|
@ -32,7 +32,7 @@ use style::properties::ComputedValues;
|
|||
use style::values::CSSFloat;
|
||||
use style::values::computed::LengthOrPercentageOrAuto;
|
||||
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.
|
||||
/// 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()
|
||||
}
|
||||
|
||||
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
|
||||
self.block_flow.generated_containing_block_rect()
|
||||
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
|
||||
self.block_flow.generated_containing_block_size(flow)
|
||||
}
|
||||
|
||||
fn update_late_computed_inline_position_if_necessary(&mut self, inline_position: Au) {
|
||||
|
|
|
@ -8,13 +8,13 @@
|
|||
|
||||
use block::BlockFlow;
|
||||
use context::LayoutContext;
|
||||
use flow::{FlowClass, Flow};
|
||||
use flow::{FlowClass, Flow, OpaqueFlow};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
||||
use geom::{Point2D, Rect};
|
||||
use util::geometry::Au;
|
||||
use util::logical_geometry::LogicalRect;
|
||||
use util::logical_geometry::LogicalSize;
|
||||
use std::fmt;
|
||||
use style::properties::ComputedValues;
|
||||
use std::sync::Arc;
|
||||
|
@ -89,8 +89,8 @@ impl Flow for TableCaptionFlow {
|
|||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
|
||||
self.block_flow.generated_containing_block_rect()
|
||||
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
|
||||
self.block_flow.generated_containing_block_size(flow)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
|
|
|
@ -10,7 +10,7 @@ use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
|
|||
use context::LayoutContext;
|
||||
use css::node_style::StyledNode;
|
||||
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
|
||||
use flow::{Flow, FlowClass};
|
||||
use flow::{Flow, FlowClass, OpaqueFlow};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use model::MaybeAuto;
|
||||
use layout_debug;
|
||||
|
@ -27,7 +27,7 @@ use style::computed_values::{border_collapse, border_top_style};
|
|||
use style::legacy::UnsignedIntegerAttribute;
|
||||
use style::properties::ComputedValues;
|
||||
use util::geometry::Au;
|
||||
use util::logical_geometry::{LogicalMargin, LogicalRect, WritingMode};
|
||||
use util::logical_geometry::{LogicalMargin, LogicalRect, LogicalSize, WritingMode};
|
||||
|
||||
/// A table formatting context.
|
||||
#[derive(RustcEncodable)]
|
||||
|
@ -204,8 +204,8 @@ impl Flow for TableCellFlow {
|
|||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
|
||||
self.block_flow.generated_containing_block_rect()
|
||||
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
|
||||
self.block_flow.generated_containing_block_size(flow)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
use context::LayoutContext;
|
||||
use css::node_style::StyledNode;
|
||||
use flow::{BaseFlow, FlowClass, Flow, ForceNonfloatedFlag};
|
||||
use flow::{BaseFlow, FlowClass, Flow, ForceNonfloatedFlag, OpaqueFlow};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator, SpecificFragmentInfo};
|
||||
use layout_debug;
|
||||
use wrapper::ThreadSafeLayoutNode;
|
||||
|
@ -20,6 +20,7 @@ use std::fmt;
|
|||
use style::values::computed::LengthOrPercentageOrAuto;
|
||||
use style::properties::ComputedValues;
|
||||
use std::sync::Arc;
|
||||
use util::logical_geometry::LogicalSize;
|
||||
|
||||
/// A table formatting context.
|
||||
pub struct TableColGroupFlow {
|
||||
|
@ -101,6 +102,10 @@ impl Flow for TableColGroupFlow {
|
|||
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,
|
||||
_: &mut FragmentBorderBoxIterator,
|
||||
_: &Point2D<Au>) {}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
use block::{BlockFlow, ISizeAndMarginsComputer};
|
||||
use context::LayoutContext;
|
||||
use display_list_builder::{BlockFlowDisplayListBuilding, BorderPaintingMode};
|
||||
use flow::{self, FlowClass, Flow, ImmutableFlowUtils};
|
||||
use flow::{self, FlowClass, Flow, ImmutableFlowUtils, OpaqueFlow};
|
||||
use flow_list::MutFlowListIterator;
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use layout_debug;
|
||||
|
@ -30,7 +30,7 @@ use style::computed_values::{border_collapse, border_spacing, border_top_style};
|
|||
use style::properties::ComputedValues;
|
||||
use style::values::computed::LengthOrPercentageOrAuto;
|
||||
use util::geometry::Au;
|
||||
use util::logical_geometry::{LogicalRect, PhysicalSide, WritingMode};
|
||||
use util::logical_geometry::{LogicalSize, PhysicalSide, WritingMode};
|
||||
|
||||
/// A single row of a table.
|
||||
pub struct TableRowFlow {
|
||||
|
@ -438,8 +438,8 @@ impl Flow for TableRowFlow {
|
|||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
|
||||
self.block_flow.generated_containing_block_rect()
|
||||
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
|
||||
self.block_flow.generated_containing_block_size(flow)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
use block::{BlockFlow, ISizeAndMarginsComputer};
|
||||
use context::LayoutContext;
|
||||
use flow::{FlowClass, Flow};
|
||||
use flow::{FlowClass, Flow, OpaqueFlow};
|
||||
use fragment::{Fragment, FragmentBorderBoxIterator};
|
||||
use layout_debug;
|
||||
use style::computed_values::{border_collapse, border_spacing};
|
||||
|
@ -23,7 +23,7 @@ use std::iter::{IntoIterator, Iterator, Peekable};
|
|||
use std::sync::Arc;
|
||||
use style::properties::ComputedValues;
|
||||
use util::geometry::Au;
|
||||
use util::logical_geometry::{LogicalRect, WritingMode};
|
||||
use util::logical_geometry::{LogicalSize, WritingMode};
|
||||
|
||||
/// A table formatting context.
|
||||
pub struct TableRowGroupFlow {
|
||||
|
@ -228,8 +228,8 @@ impl Flow for TableRowGroupFlow {
|
|||
self.block_flow.compute_overflow()
|
||||
}
|
||||
|
||||
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
|
||||
self.block_flow.generated_containing_block_rect()
|
||||
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
|
||||
self.block_flow.generated_containing_block_size(flow)
|
||||
}
|
||||
|
||||
fn iterate_through_fragment_border_boxes(&self,
|
||||
|
|
|
@ -18,7 +18,7 @@ use block::{ISizeConstraintSolution, MarginsMayCollapseFlag};
|
|||
use context::LayoutContext;
|
||||
use floats::FloatKind;
|
||||
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 model::MaybeAuto;
|
||||
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
|
||||
|
@ -27,7 +27,7 @@ use wrapper::ThreadSafeLayoutNode;
|
|||
|
||||
use geom::{Point2D, Rect};
|
||||
use util::geometry::Au;
|
||||
use util::logical_geometry::LogicalRect;
|
||||
use util::logical_geometry::LogicalSize;
|
||||
use std::cmp::{max, min};
|
||||
use std::fmt;
|
||||
use std::ops::Add;
|
||||
|
@ -397,8 +397,8 @@ impl Flow for TableWrapperFlow {
|
|||
self.block_flow.update_late_computed_block_position_if_necessary(block_position)
|
||||
}
|
||||
|
||||
fn generated_containing_block_rect(&self) -> LogicalRect<Au> {
|
||||
self.block_flow.generated_containing_block_rect()
|
||||
fn generated_containing_block_size(&self, flow: OpaqueFlow) -> LogicalSize<Au> {
|
||||
self.block_flow.generated_containing_block_size(flow)
|
||||
}
|
||||
|
||||
fn build_display_list(&mut self, layout_context: &LayoutContext) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче