layout: Rewrite clipping to be per-display-item instead of having

a separate `ClipDisplayItem`.

We push down clipping areas during absolute position calculation. This
makes display items into a flat list, improving cache locality. It
dramatically simplifies the code all around.

Because we need to push down clip rects even for absolutely-positioned
children of non-absolutely-positioned flows, this patch alters the
parallel traversal to compute absolute positions for
absolutely-positioned children at the same time it computes absolute
positions for other children. This doesn't seem to break anything either
in theory (since the overall order remains correct) or in practice. It
simplifies the parallel traversal code quite a bit.

See the relevant Gecko bug:
https://bugzilla.mozilla.org/show_bug.cgi?id=615734
This commit is contained in:
Patrick Walton 2014-10-10 15:13:12 -07:00
parent f350879574
commit bffaad118e
12 changed files with 312 additions and 487 deletions

View file

@ -9,8 +9,8 @@ use context::LayoutContext;
use floats::{FloatLeft, Floats, PlacementInfo};
use flow::{BaseFlow, FlowClass, Flow, InlineFlowClass, MutableFlowUtils};
use flow;
use fragment::{Fragment, InlineBlockFragment, ScannedTextFragment, ScannedTextFragmentInfo};
use fragment::{SplitInfo};
use fragment::{Fragment, InlineAbsoluteHypotheticalFragment, InlineBlockFragment};
use fragment::{ScannedTextFragment, ScannedTextFragmentInfo, SplitInfo};
use layout_debug;
use model::IntrinsicISizes;
use text;
@ -18,7 +18,7 @@ use wrapper::ThreadSafeLayoutNode;
use collections::{Deque, RingBuf};
use geom::Rect;
use gfx::display_list::ContentLevel;
use gfx::display_list::{ContentLevel, DisplayList};
use gfx::font::FontMetrics;
use gfx::font_context::FontContext;
use geom::Size2D;
@ -704,19 +704,20 @@ impl InlineFlow {
let fragment_position = self.base
.abs_position
.add_size(&rel_offset.to_physical(self.base.writing_mode));
let mut accumulator = fragment.build_display_list(&mut self.base.display_list,
layout_context,
fragment_position,
ContentLevel);
fragment.build_display_list(&mut self.base.display_list,
layout_context,
fragment_position,
ContentLevel,
&self.base.clip_rect);
match fragment.specific {
InlineBlockFragment(ref mut block_flow) => {
let block_flow = block_flow.flow_ref.get_mut();
accumulator.push_child(&mut self.base.display_list, block_flow);
self.base.display_list.push_all_move(
mem::replace(&mut flow::mut_base(block_flow).display_list,
DisplayList::new()));
}
_ => {}
}
accumulator.finish(&mut self.base.display_list);
}
}
@ -1124,16 +1125,40 @@ impl Flow for InlineFlow {
fn compute_absolute_position(&mut self) {
for fragment in self.fragments.fragments.iter_mut() {
match fragment.specific {
let absolute_position = match fragment.specific {
InlineBlockFragment(ref mut info) => {
let block_flow = info.flow_ref.get_mut().as_block();
// FIXME(#2795): Get the real container size
let container_size = Size2D::zero();
block_flow.base.abs_position =
self.base.abs_position +
fragment.border_box.start.to_physical(self.base.writing_mode,
container_size);
block_flow.base.abs_position
}
InlineAbsoluteHypotheticalFragment(ref mut info) => {
let block_flow = info.flow_ref.get_mut().as_block();
// FIXME(#2795): Get the real container size
let container_size = Size2D::zero();
block_flow.base.abs_position =
self.base.abs_position +
fragment.border_box.start.to_physical(self.base.writing_mode,
container_size);
block_flow.base.abs_position
}
_ => continue,
};
let clip_rect = fragment.clip_rect_for_children(self.base.clip_rect,
absolute_position);
match fragment.specific {
InlineBlockFragment(ref mut info) => {
flow::mut_base(info.flow_ref.get_mut()).clip_rect = clip_rect
}
InlineAbsoluteHypotheticalFragment(ref mut info) => {
flow::mut_base(info.flow_ref.get_mut()).clip_rect = clip_rect
}
_ => {}
}