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:
Patrick Walton 2015-05-13 14:27:21 -05:00
Родитель 30d6380a36
Коммит c918f5d92e
18 изменённых файлов: 574 добавлений и 265 удалений

Просмотреть файл

@ -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) {