layout: Paint stacking contexts' overflow areas properly.

This was making `box-shadow` not show up in many cases, in particular,
but the effects were not limited to that.
This commit is contained in:
Patrick Walton 2014-12-18 18:59:42 -08:00
parent ba8cf6b0e6
commit 5ea2c6dcfd
30 changed files with 357 additions and 179 deletions

View file

@ -32,7 +32,7 @@ use display_list_builder::DisplayListBuildingResult;
use floats::Floats;
use flow_list::{FlowList, FlowListIterator, MutFlowListIterator};
use flow_ref::FlowRef;
use fragment::{Fragment, FragmentBoundsIterator, SpecificFragmentInfo};
use fragment::{Fragment, FragmentOverflowIterator, SpecificFragmentInfo};
use incremental::{RECONSTRUCT_FLOW, REFLOW, REFLOW_OUT_OF_FLOW, RestyleDamage};
use inline::InlineFlow;
use model::{CollapsibleMargins, IntrinsicISizes, MarginCollapseInfo};
@ -50,7 +50,7 @@ use geom::{Point2D, Rect, Size2D};
use gfx::display_list::ClippingRegion;
use serialize::{Encoder, Encodable};
use servo_msg::compositor_msg::LayerId;
use servo_util::geometry::Au;
use servo_util::geometry::{Au, ZERO_RECT};
use servo_util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
use std::mem;
use std::fmt;
@ -220,8 +220,11 @@ pub trait Flow: fmt::Show + ToString + Sync {
/// Phase 5 of reflow: builds display lists.
fn build_display_list(&mut self, layout_context: &LayoutContext);
/// Perform an iteration of fragment bounds on this flow.
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator);
/// Returns the union of all overflow rects of all of this flow's fragments.
fn compute_overflow(&self) -> Rect<Au>;
/// Iterates through overflow rects of all of this flow's fragments.
fn iterate_through_fragment_overflow(&self, iterator: &mut FragmentOverflowIterator);
fn compute_collapsible_block_start_margin(&mut self,
_layout_context: &mut LayoutContext,
@ -718,7 +721,7 @@ pub struct BaseFlow {
/// The amount of overflow of this flow, relative to the containing block. Must include all the
/// pixels of all the display list items for correct invalidation.
pub overflow: LogicalRect<Au>,
pub overflow: Rect<Au>,
/// Data used during parallel traversals.
///
@ -894,7 +897,7 @@ impl BaseFlow {
children: FlowList::new(),
intrinsic_inline_sizes: IntrinsicISizes::new(),
position: LogicalRect::zero(writing_mode),
overflow: LogicalRect::zero(writing_mode),
overflow: ZERO_RECT,
parallel: FlowParallelInfo::new(),
floats: Floats::new(writing_mode),
collapsible_margins: CollapsibleMargins::new(),
@ -929,10 +932,12 @@ impl BaseFlow {
/// Ensures that all display list items generated by this flow are within the flow's overflow
/// rect. This should only be used for debugging.
pub fn validate_display_list_geometry(&self) {
let position_with_overflow = self.position.union(&self.overflow);
let bounds = Rect(self.stacking_relative_position,
Size2D(position_with_overflow.size.inline,
position_with_overflow.size.block));
// FIXME(pcwalton, #2795): Get the real container size.
let container_size = Size2D::zero();
let position_with_overflow = self.position
.to_physical(self.writing_mode, container_size)
.union(&self.overflow);
let bounds = Rect(self.stacking_relative_position, position_with_overflow.size);
let all_items = match self.display_list_building_result {
DisplayListBuildingResult::None => Vec::new(),
@ -1175,40 +1180,29 @@ impl<'a> MutableFlowUtils for &'a mut Flow + 'a {
/// already been set.
/// Assumption: Absolute descendants have had their overflow calculated.
fn store_overflow(self, _: &LayoutContext) {
let my_position = mut_base(self).position;
// FIXME(pcwalton): We should calculate overflow on a per-fragment basis, because their
// styles can affect overflow regions. Consider `box-shadow`, `outline`, etc.--anything
// that can draw outside the border box. For now we assume overflow is the border box, but
// that is wrong.
let mut overflow = my_position;
// Calculate overflow on a per-fragment basis.
let mut overflow = self.compute_overflow();
if self.is_block_container() {
let writing_mode = base(self).writing_mode;
// FIXME(#2795): Get the real container size
// FIXME(#2795): Get the real container size.
let container_size = Size2D::zero();
for kid in child_iter(self) {
if kid.is_store_overflow_delayed() {
// Absolute flows will be handled by their CB. If we are
// their CB, they will show up in `abs_descendants`.
continue;
if base(kid).flags.contains(IS_ABSOLUTELY_POSITIONED) {
continue
}
let kid_base = base(kid);
let mut kid_overflow = kid_base.overflow.convert(
kid_base.writing_mode, writing_mode, container_size);
kid_overflow = kid_overflow.translate(&my_position.start);
overflow = overflow.union(&kid_overflow)
let kid_overflow = base(kid).overflow;
let kid_position = base(kid).position.to_physical(base(kid).writing_mode,
container_size);
overflow = overflow.union(&kid_overflow.translate(&kid_position.origin))
}
// FIXME(#2004, pcwalton): This is wrong for `position: fixed`.
for descendant_link in mut_base(self).abs_descendants.iter() {
let kid_base = base(descendant_link);
let mut kid_overflow = kid_base.overflow.convert(
kid_base.writing_mode, writing_mode, container_size);
kid_overflow = kid_overflow.translate(&my_position.start);
overflow = overflow.union(&kid_overflow)
for kid in mut_base(self).abs_descendants.iter() {
let kid_overflow = base(kid).overflow;
let kid_position = base(kid).position.to_physical(base(kid).writing_mode,
container_size);
overflow = overflow.union(&kid_overflow.translate(&kid_position.origin))
}
}
mut_base(self).overflow = overflow;
}