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

@ -283,8 +283,7 @@ impl CompositorLayer for Layer<CompositorData> {
self.clamp_scroll_offset_and_scroll_layer(scroll_offset + delta) self.clamp_scroll_offset_and_scroll_layer(scroll_offset + delta)
} }
fn clamp_scroll_offset_and_scroll_layer(&self, fn clamp_scroll_offset_and_scroll_layer(&self, new_offset: TypedPoint2D<LayerPixel, f32>)
new_offset: TypedPoint2D<LayerPixel, f32>)
-> ScrollEventResult { -> ScrollEventResult {
let layer_size = self.bounds.borrow().size; let layer_size = self.bounds.borrow().size;
let content_size = calculate_content_size_for_layer(self); let content_size = calculate_content_size_for_layer(self);
@ -339,17 +338,14 @@ impl CompositorLayer for Layer<CompositorData> {
let _ = chan.send_opt(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message)); let _ = chan.send_opt(ConstellationControlMsg::SendEvent(pipeline.id.clone(), message));
} }
fn scroll_layer_and_all_child_layers(&self, fn scroll_layer_and_all_child_layers(&self, new_offset: TypedPoint2D<LayerPixel, f32>)
new_offset: TypedPoint2D<LayerPixel, f32>)
-> bool { -> bool {
let mut result = false; let mut result = false;
// Only scroll this layer if it's not fixed-positioned. // Only scroll this layer if it's not fixed-positioned.
if self.extra_data.borrow().scroll_policy != FixedPosition { if self.extra_data.borrow().scroll_policy != FixedPosition {
let new_offset = new_offset.to_untyped(); let new_offset = new_offset.to_untyped();
*self.transform.borrow_mut() = identity().translate(new_offset.x, *self.transform.borrow_mut() = identity().translate(new_offset.x, new_offset.y, 0.0);
new_offset.y,
0.0);
*self.content_offset.borrow_mut() = Point2D::from_untyped(&new_offset); *self.content_offset.borrow_mut() = Point2D::from_untyped(&new_offset);
result = true result = true
} }

View file

@ -34,7 +34,7 @@ use servo_msg::compositor_msg::LayerId;
use servo_net::image::base::Image; use servo_net::image::base::Image;
use servo_util::cursor::Cursor; use servo_util::cursor::Cursor;
use servo_util::dlist as servo_dlist; use servo_util::dlist as servo_dlist;
use servo_util::geometry::{mod, Au, MAX_RECT, ZERO_POINT, ZERO_RECT}; use servo_util::geometry::{mod, Au, MAX_RECT, ZERO_RECT};
use servo_util::range::Range; use servo_util::range::Range;
use servo_util::smallvec::{SmallVec, SmallVec8}; use servo_util::smallvec::{SmallVec, SmallVec8};
use std::fmt; use std::fmt;
@ -160,9 +160,8 @@ pub struct StackingContext {
pub layer: Option<Arc<PaintLayer>>, pub layer: Option<Arc<PaintLayer>>,
/// The position and size of this stacking context. /// The position and size of this stacking context.
pub bounds: Rect<Au>, pub bounds: Rect<Au>,
/// The clipping rect for this stacking context, in the coordinate system of the *parent* /// The overflow rect for this stacking context in its coordinate system.
/// stacking context. pub overflow: Rect<Au>,
pub clip_rect: Rect<Au>,
/// The `z-index` for this stacking context. /// The `z-index` for this stacking context.
pub z_index: i32, pub z_index: i32,
/// The opacity of this stacking context. /// The opacity of this stacking context.
@ -171,12 +170,10 @@ pub struct StackingContext {
impl StackingContext { impl StackingContext {
/// Creates a new stacking context. /// Creates a new stacking context.
///
/// TODO(pcwalton): Stacking contexts should not always be clipped to their bounds, to handle
/// overflow properly.
#[inline] #[inline]
pub fn new(display_list: Box<DisplayList>, pub fn new(display_list: Box<DisplayList>,
bounds: Rect<Au>, bounds: &Rect<Au>,
overflow: &Rect<Au>,
z_index: i32, z_index: i32,
opacity: AzFloat, opacity: AzFloat,
layer: Option<Arc<PaintLayer>>) layer: Option<Arc<PaintLayer>>)
@ -184,8 +181,8 @@ impl StackingContext {
StackingContext { StackingContext {
display_list: display_list, display_list: display_list,
layer: layer, layer: layer,
bounds: bounds, bounds: *bounds,
clip_rect: Rect(ZERO_POINT, bounds.size), overflow: *overflow,
z_index: z_index, z_index: z_index,
opacity: opacity, opacity: opacity,
} }
@ -196,7 +193,7 @@ impl StackingContext {
paint_context: &mut PaintContext, paint_context: &mut PaintContext,
tile_bounds: &Rect<AzFloat>, tile_bounds: &Rect<AzFloat>,
transform: &Matrix2D<AzFloat>, transform: &Matrix2D<AzFloat>,
clip_rect: Option<Rect<Au>>) { clip_rect: Option<&Rect<Au>>) {
let temporary_draw_target = let temporary_draw_target =
paint_context.get_or_create_temporary_draw_target(self.opacity); paint_context.get_or_create_temporary_draw_target(self.opacity);
{ {
@ -205,7 +202,7 @@ impl StackingContext {
font_ctx: &mut *paint_context.font_ctx, font_ctx: &mut *paint_context.font_ctx,
page_rect: paint_context.page_rect, page_rect: paint_context.page_rect,
screen_rect: paint_context.screen_rect, screen_rect: paint_context.screen_rect,
clip_rect: clip_rect, clip_rect: clip_rect.map(|clip_rect| *clip_rect),
transient_clip: None, transient_clip: None,
}; };
@ -252,7 +249,7 @@ impl StackingContext {
positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext, positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext,
&new_tile_rect, &new_tile_rect,
&new_transform, &new_transform,
Some(positioned_kid.clip_rect)) Some(&positioned_kid.overflow))
} }
} }
@ -295,7 +292,7 @@ impl StackingContext {
positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext, positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext,
&new_tile_rect, &new_tile_rect,
&new_transform, &new_transform,
Some(positioned_kid.clip_rect)) Some(&positioned_kid.overflow))
} }
} }
@ -329,11 +326,18 @@ impl StackingContext {
} }
}; };
let child_stacking_context_bounds = child_stacking_context.bounds.to_azure_rect(); // Translate the child's overflow region into our coordinate system.
let tile_subrect = tile_bounds.intersection(&child_stacking_context_bounds) let child_stacking_context_overflow =
child_stacking_context.overflow.translate(&child_stacking_context.bounds.origin)
.to_azure_rect();
// Intersect that with the current tile boundaries to find the tile boundaries that the
// child covers.
let tile_subrect = tile_bounds.intersection(&child_stacking_context_overflow)
.unwrap_or(ZERO_AZURE_RECT); .unwrap_or(ZERO_AZURE_RECT);
let offset = tile_subrect.origin - child_stacking_context_bounds.origin;
Rect(offset, tile_subrect.size) // Translate the resulting rect into the child's coordinate system.
tile_subrect.translate(&-child_stacking_context.bounds.to_azure_rect().origin)
} }
/// Places all nodes containing the point of interest into `result`, topmost first. If /// Places all nodes containing the point of interest into `result`, topmost first. If

View file

@ -59,7 +59,8 @@ impl DisplayListOptimizer {
mut stacking_contexts: I) mut stacking_contexts: I)
where I: Iterator<&'a Arc<StackingContext>> { where I: Iterator<&'a Arc<StackingContext>> {
for stacking_context in stacking_contexts { for stacking_context in stacking_contexts {
if self.visible_rect.intersects(&stacking_context.bounds) { let overflow = stacking_context.overflow.translate(&stacking_context.bounds.origin);
if self.visible_rect.intersects(&overflow) {
result_list.push_back((*stacking_context).clone()) result_list.push_back((*stacking_context).clone())
} }
} }

View file

@ -148,21 +148,22 @@ fn initialize_layers<C>(compositor: &mut C,
stacking_context: &StackingContext, stacking_context: &StackingContext,
page_position: &Point2D<Au>) { page_position: &Point2D<Au>) {
let page_position = stacking_context.bounds.origin + *page_position; let page_position = stacking_context.bounds.origin + *page_position;
match stacking_context.layer { if let Some(ref paint_layer) = stacking_context.layer {
None => {} // Layers start at the top left of their overflow rect, as far as the info we give to
Some(ref paint_layer) => { // the compositor is concerned.
let overflow_relative_page_position = page_position + stacking_context.overflow.origin;
let layer_position =
Rect(Point2D(overflow_relative_page_position.x.to_nearest_px() as i32,
overflow_relative_page_position.y.to_nearest_px() as i32),
Size2D(stacking_context.overflow.size.width.to_nearest_px() as i32,
stacking_context.overflow.size.height.to_nearest_px() as i32));
metadata.push(LayerMetadata { metadata.push(LayerMetadata {
id: paint_layer.id, id: paint_layer.id,
position: position: layer_position,
Rect(Point2D(page_position.x.to_nearest_px() as uint,
page_position.y.to_nearest_px() as uint),
Size2D(stacking_context.bounds.size.width.to_nearest_px() as uint,
stacking_context.bounds.size.height.to_nearest_px() as uint)),
background_color: paint_layer.background_color, background_color: paint_layer.background_color,
scroll_policy: paint_layer.scroll_policy, scroll_policy: paint_layer.scroll_policy,
}) })
} }
}
for kid in stacking_context.display_list.children.iter() { for kid in stacking_context.display_list.children.iter() {
build(metadata, &**kid, &page_position) build(metadata, &**kid, &page_position)
@ -384,15 +385,14 @@ impl<C> PaintTask<C> where C: PaintListener + Send {
layer_id: LayerId) { layer_id: LayerId) {
profile(TimeProfilerCategory::Painting, None, self.time_profiler_chan.clone(), || { profile(TimeProfilerCategory::Painting, None, self.time_profiler_chan.clone(), || {
// Bail out if there is no appropriate stacking context. // Bail out if there is no appropriate stacking context.
let stacking_context = match self.root_stacking_context { let stacking_context = if let Some(ref stacking_context) = self.root_stacking_context {
Some(ref stacking_context) => {
match display_list::find_stacking_context_with_layer_id(stacking_context, match display_list::find_stacking_context_with_layer_id(stacking_context,
layer_id) { layer_id) {
Some(stacking_context) => stacking_context, Some(stacking_context) => stacking_context,
None => return, None => return,
} }
} } else {
None => return, return
}; };
// Divide up the layer into tiles and distribute them to workers via a simple round- // Divide up the layer into tiles and distribute them to workers via a simple round-
@ -547,8 +547,13 @@ impl WorkerThread {
transient_clip: None, transient_clip: None,
}; };
// Apply a translation to start at the boundaries of the stacking context, since the
// layer's origin starts at its overflow rect's origin.
let tile_bounds = tile.page_rect.translate(
&Point2D(stacking_context.overflow.origin.x.to_subpx() as AzFloat,
stacking_context.overflow.origin.y.to_subpx() as AzFloat));
// Apply the translation to paint the tile we want. // Apply the translation to paint the tile we want.
let tile_bounds = tile.page_rect;
let matrix: Matrix2D<AzFloat> = Matrix2D::identity(); let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
let matrix = matrix.scale(scale as AzFloat, scale as AzFloat); let matrix = matrix.scale(scale as AzFloat, scale as AzFloat);
let matrix = matrix.translate(-tile_bounds.origin.x as AzFloat, let matrix = matrix.translate(-tile_bounds.origin.x as AzFloat,
@ -561,7 +566,7 @@ impl WorkerThread {
profile(TimeProfilerCategory::PaintingPerTile, None, profile(TimeProfilerCategory::PaintingPerTile, None,
self.time_profiler_sender.clone(), || { self.time_profiler_sender.clone(), || {
stacking_context.optimize_and_draw_into_context(&mut paint_context, stacking_context.optimize_and_draw_into_context(&mut paint_context,
&tile.page_rect, &tile_bounds,
&matrix, &matrix,
None); None);
paint_context.draw_target.flush(); paint_context.draw_target.flush();

View file

@ -41,7 +41,7 @@ use flow::{LAYERS_NEEDED_FOR_DESCENDANTS, NEEDS_LAYER};
use flow::{IS_ABSOLUTELY_POSITIONED}; use flow::{IS_ABSOLUTELY_POSITIONED};
use flow::{CLEARS_LEFT, CLEARS_RIGHT}; use flow::{CLEARS_LEFT, CLEARS_RIGHT};
use flow; use flow;
use fragment::{Fragment, FragmentBoundsIterator, SpecificFragmentInfo}; use fragment::{Fragment, FragmentOverflowIterator, SpecificFragmentInfo};
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW}; use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
use layout_debug; use layout_debug;
use model::{IntrinsicISizes, MarginCollapseInfo}; use model::{IntrinsicISizes, MarginCollapseInfo};
@ -49,7 +49,7 @@ use model::{MaybeAuto, CollapsibleMargins, specified, specified_or_none};
use table::ColumnComputedInlineSize; use table::ColumnComputedInlineSize;
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use geom::Size2D; use geom::{Rect, Size2D};
use gfx::display_list::{ClippingRegion, DisplayList}; use gfx::display_list::{ClippingRegion, DisplayList};
use serialize::{Encoder, Encodable}; use serialize::{Encoder, Encodable};
use servo_msg::compositor_msg::LayerId; use servo_msg::compositor_msg::LayerId;
@ -1797,13 +1797,6 @@ impl Flow for BlockFlow {
self.flags.insert(IS_ROOT) self.flags.insert(IS_ROOT)
} }
/// Return true if store overflow is delayed for this flow.
///
/// Currently happens only for absolutely positioned flows.
fn is_store_overflow_delayed(&mut self) -> bool {
self.base.flags.contains(IS_ABSOLUTELY_POSITIONED)
}
fn is_root(&self) -> bool { fn is_root(&self) -> bool {
self.flags.contains(IS_ROOT) self.flags.contains(IS_ROOT)
} }
@ -1864,12 +1857,13 @@ impl Flow for BlockFlow {
self.fragment.repair_style(new_style) self.fragment.repair_style(new_style)
} }
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { fn compute_overflow(&self) -> Rect<Au> {
self.fragment.compute_overflow()
}
fn iterate_through_fragment_overflow(&self, iterator: &mut FragmentOverflowIterator) {
if iterator.should_process(&self.fragment) { if iterator.should_process(&self.fragment) {
let fragment_origin = iterator.process(&self.fragment, self.fragment.compute_overflow());
self.base.stacking_relative_position_of_child_fragment(&self.fragment);
iterator.process(&self.fragment,
self.fragment.stacking_relative_bounds(&fragment_origin));
} }
} }
} }
@ -2455,11 +2449,14 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
MaybeAuto::Specified(fragment.content_inline_size()) MaybeAuto::Specified(fragment.content_inline_size())
} }
fn containing_block_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &LayoutContext) -> Au { fn containing_block_inline_size(&self, block: &mut BlockFlow, _: Au, ctx: &LayoutContext)
-> Au {
block.containing_block_size(ctx.shared.screen_size).inline block.containing_block_size(ctx.shared.screen_size).inline
} }
fn set_flow_x_coord_if_necessary(&self, block: &mut BlockFlow, solution: ISizeConstraintSolution) { fn set_flow_x_coord_if_necessary(&self,
block: &mut BlockFlow,
solution: ISizeConstraintSolution) {
// Set the x-coordinate of the absolute flow wrt to its containing block. // Set the x-coordinate of the absolute flow wrt to its containing block.
block.base.position.start.i = solution.inline_start; block.base.position.start.i = solution.inline_start;
} }

View file

@ -1103,7 +1103,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
background_border_level); background_border_level);
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() { self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, None)) DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list,
None))
} else { } else {
DisplayListBuildingResult::Normal(display_list) DisplayListBuildingResult::Normal(display_list)
} }
@ -1120,7 +1121,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
!self.base.flags.contains(NEEDS_LAYER) { !self.base.flags.contains(NEEDS_LAYER) {
// We didn't need a layer. // We didn't need a layer.
self.base.display_list_building_result = self.base.display_list_building_result =
DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, None)); DisplayListBuildingResult::StackingContext(self.create_stacking_context(
display_list,
None));
return return
} }
@ -1137,7 +1140,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
Some(Arc::new(PaintLayer::new(self.layer_id(0), Some(Arc::new(PaintLayer::new(self.layer_id(0),
transparent, transparent,
scroll_policy)))); scroll_policy))));
self.base.display_list_building_result = DisplayListBuildingResult::StackingContext(stacking_context) self.base.display_list_building_result =
DisplayListBuildingResult::StackingContext(stacking_context)
} }
fn build_display_list_for_floating_block(&mut self, fn build_display_list_for_floating_block(&mut self,
@ -1149,7 +1153,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
display_list.form_float_pseudo_stacking_context(); display_list.form_float_pseudo_stacking_context();
self.base.display_list_building_result = if self.fragment.establishes_stacking_context() { self.base.display_list_building_result = if self.fragment.establishes_stacking_context() {
DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list, None)) DisplayListBuildingResult::StackingContext(self.create_stacking_context(display_list,
None))
} else { } else {
DisplayListBuildingResult::Normal(display_list) DisplayListBuildingResult::Normal(display_list)
} }
@ -1165,7 +1170,9 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
} else if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) { } else if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
self.build_display_list_for_absolutely_positioned_block(display_list, layout_context) self.build_display_list_for_absolutely_positioned_block(display_list, layout_context)
} else { } else {
self.build_display_list_for_static_block(display_list, layout_context, BackgroundAndBorderLevel::Block) self.build_display_list_for_static_block(display_list,
layout_context,
BackgroundAndBorderLevel::Block)
} }
} }
@ -1173,11 +1180,16 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
display_list: Box<DisplayList>, display_list: Box<DisplayList>,
layer: Option<Arc<PaintLayer>>) layer: Option<Arc<PaintLayer>>)
-> Arc<StackingContext> { -> Arc<StackingContext> {
let bounds = Rect(self.base.stacking_relative_position, let size = self.base.position.size.to_physical(self.base.writing_mode);
self.base.overflow.size.to_physical(self.base.writing_mode)); let bounds = Rect(self.base.stacking_relative_position, size);
let z_index = self.fragment.style().get_box().z_index.number_or_zero(); let z_index = self.fragment.style().get_box().z_index.number_or_zero();
let opacity = self.fragment.style().get_effects().opacity as f32; let opacity = self.fragment.style().get_effects().opacity as f32;
Arc::new(StackingContext::new(display_list, bounds, z_index, opacity, layer)) Arc::new(StackingContext::new(display_list,
&bounds,
&self.base.overflow,
z_index,
opacity,
layer))
} }
} }

View file

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

View file

@ -23,7 +23,7 @@ use util::OpaqueNodeMethods;
use wrapper::{TLayoutNode, ThreadSafeLayoutNode}; use wrapper::{TLayoutNode, ThreadSafeLayoutNode};
use geom::{Point2D, Rect, Size2D}; use geom::{Point2D, Rect, Size2D};
use gfx::display_list::OpaqueNode; use gfx::display_list::{BOX_SHADOW_INFLATION_FACTOR, OpaqueNode};
use gfx::text::glyph::CharIndex; use gfx::text::glyph::CharIndex;
use gfx::text::text_run::{TextRun, TextRunSlice}; use gfx::text::text_run::{TextRun, TextRunSlice};
use script_traits::UntrustedNodeAddress; use script_traits::UntrustedNodeAddress;
@ -531,8 +531,9 @@ impl Fragment {
// Foo // Foo
// </div> // </div>
// //
// Anonymous table fragments, SpecificFragmentInfo::TableRow and SpecificFragmentInfo::TableCell, are generated around // Anonymous table fragments, SpecificFragmentInfo::TableRow and
// `Foo`, but they shouldn't inherit the border. // SpecificFragmentInfo::TableCell, are generated around `Foo`, but they shouldn't inherit
// the border.
let node_style = cascade_anonymous(&**node.style()); let node_style = cascade_anonymous(&**node.style());
let writing_mode = node_style.writing_mode; let writing_mode = node_style.writing_mode;
@ -647,7 +648,10 @@ impl Fragment {
fn quantities_included_in_intrinsic_inline_size(&self) fn quantities_included_in_intrinsic_inline_size(&self)
-> QuantitiesIncludedInIntrinsicInlineSizes { -> QuantitiesIncludedInIntrinsicInlineSizes {
match self.specific { match self.specific {
SpecificFragmentInfo::Generic | SpecificFragmentInfo::Iframe(_) | SpecificFragmentInfo::Image(_) | SpecificFragmentInfo::InlineBlock(_) => { SpecificFragmentInfo::Generic |
SpecificFragmentInfo::Iframe(_) |
SpecificFragmentInfo::Image(_) |
SpecificFragmentInfo::InlineBlock(_) => {
QuantitiesIncludedInIntrinsicInlineSizes::all() QuantitiesIncludedInIntrinsicInlineSizes::all()
} }
SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => { SpecificFragmentInfo::Table | SpecificFragmentInfo::TableCell => {
@ -836,9 +840,7 @@ impl Fragment {
} }
// Return offset from original position because of `position: relative`. // Return offset from original position because of `position: relative`.
pub fn relative_position(&self, pub fn relative_position(&self, containing_block_size: &LogicalSize<Au>) -> LogicalSize<Au> {
containing_block_size: &LogicalSize<Au>)
-> LogicalSize<Au> {
fn from_style(style: &ComputedValues, container_size: &LogicalSize<Au>) fn from_style(style: &ComputedValues, container_size: &LogicalSize<Au>)
-> LogicalSize<Au> { -> LogicalSize<Au> {
let offsets = style.logical_position(); let offsets = style.logical_position();
@ -1567,6 +1569,41 @@ impl Fragment {
} }
} }
} }
/// Computes the overflow rect of this fragment relative to the start of the flow.
pub fn compute_overflow(&self) -> Rect<Au> {
// FIXME(pcwalton, #2795): Get the real container size.
let container_size = Size2D::zero();
let mut border_box = self.border_box.to_physical(self.style.writing_mode, container_size);
// Relative position can cause us to draw outside our border box.
//
// FIXME(pcwalton): I'm not a fan of the way this makes us crawl though so many styles all
// the time. Can't we handle relative positioning by just adjusting `border_box`?
let relative_position =
self.relative_position(&LogicalSize::zero(self.style.writing_mode));
border_box =
border_box.translate_by_size(&relative_position.to_physical(self.style.writing_mode));
let mut overflow = border_box;
// Box shadows cause us to draw outside our border box.
for box_shadow in self.style().get_effects().box_shadow.iter() {
let offset = Point2D(box_shadow.offset_x, box_shadow.offset_y);
let inflation = box_shadow.spread_radius +
box_shadow.blur_radius * BOX_SHADOW_INFLATION_FACTOR;
overflow = overflow.union(&border_box.translate(&offset).inflate(inflation, inflation))
}
// Outlines cause us to draw outside our border box.
let outline_width = self.style.get_outline().outline_width;
if outline_width != Au(0) {
overflow = overflow.union(&border_box.inflate(outline_width, outline_width))
}
// FIXME(pcwalton): Sometimes excessively fancy glyphs can make us draw outside our border
// box too.
overflow
}
} }
impl fmt::Show for Fragment { impl fmt::Show for Fragment {
@ -1600,10 +1637,10 @@ bitflags! {
} }
} }
/// A top-down fragment bounds iteration handler. /// A top-down fragment overflow region iteration handler.
pub trait FragmentBoundsIterator { pub trait FragmentOverflowIterator {
/// The operation to perform. /// The operation to perform.
fn process(&mut self, fragment: &Fragment, bounds: Rect<Au>); fn process(&mut self, fragment: &Fragment, overflow: Rect<Au>);
/// Returns true if this fragment must be processed in-order. If this returns false, /// Returns true if this fragment must be processed in-order. If this returns false,
/// we skip the operation for this fragment, but continue processing siblings. /// we skip the operation for this fragment, but continue processing siblings.

View file

@ -12,7 +12,7 @@ use flow::{BaseFlow, FlowClass, Flow, MutableFlowUtils, ForceNonfloatedFlag};
use flow::{IS_ABSOLUTELY_POSITIONED}; use flow::{IS_ABSOLUTELY_POSITIONED};
use flow; use flow;
use fragment::{Fragment, SpecificFragmentInfo}; use fragment::{Fragment, SpecificFragmentInfo};
use fragment::{FragmentBoundsIterator, ScannedTextFragmentInfo}; use fragment::{FragmentOverflowIterator, ScannedTextFragmentInfo};
use fragment::SplitInfo; use fragment::SplitInfo;
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW}; use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
use layout_debug; use layout_debug;
@ -20,12 +20,12 @@ use model::IntrinsicISizesContribution;
use text; use text;
use collections::{RingBuf}; use collections::{RingBuf};
use geom::Size2D; use geom::{Rect, Size2D};
use gfx::display_list::DisplayList; use gfx::display_list::DisplayList;
use gfx::font::FontMetrics; use gfx::font::FontMetrics;
use gfx::font_context::FontContext; use gfx::font_context::FontContext;
use gfx::text::glyph::CharIndex; use gfx::text::glyph::CharIndex;
use servo_util::geometry::Au; use servo_util::geometry::{Au, ZERO_RECT};
use servo_util::logical_geometry::{LogicalRect, LogicalSize, WritingMode}; use servo_util::logical_geometry::{LogicalRect, LogicalSize, WritingMode};
use servo_util::opts; use servo_util::opts;
use servo_util::range::{Range, RangeIndex}; use servo_util::range::{Range, RangeIndex};
@ -1271,7 +1271,15 @@ impl Flow for InlineFlow {
fn repair_style(&mut self, _: &Arc<ComputedValues>) {} fn repair_style(&mut self, _: &Arc<ComputedValues>) {}
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { fn compute_overflow(&self) -> Rect<Au> {
let mut overflow = ZERO_RECT;
for fragment in self.fragments.fragments.iter() {
overflow = overflow.union(&fragment.compute_overflow())
}
overflow
}
fn iterate_through_fragment_overflow(&self, iterator: &mut FragmentOverflowIterator) {
for fragment in self.fragments.fragments.iter() { for fragment in self.fragments.fragments.iter() {
if iterator.should_process(fragment) { if iterator.should_process(fragment) {
let fragment_origin = let fragment_origin =

View file

@ -10,7 +10,7 @@ use construct::ConstructionResult;
use context::SharedLayoutContext; use context::SharedLayoutContext;
use flow::{mod, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils}; use flow::{mod, Flow, ImmutableFlowUtils, MutableFlowUtils, MutableOwnedFlowUtils};
use flow_ref::FlowRef; use flow_ref::FlowRef;
use fragment::{Fragment, FragmentBoundsIterator}; use fragment::{Fragment, FragmentOverflowIterator};
use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT}; use incremental::{LayoutDamageComputation, REFLOW, REFLOW_ENTIRE_DOCUMENT, REPAINT};
use layout_debug; use layout_debug;
use parallel::{mod, UnsafeFlow}; use parallel::{mod, UnsafeFlow};
@ -604,7 +604,7 @@ impl LayoutTask {
// FIXME(pcwalton): This has not been updated to handle the stacking context relative // FIXME(pcwalton): This has not been updated to handle the stacking context relative
// stuff. So the position is wrong in most cases. // stuff. So the position is wrong in most cases.
let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node); let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node);
let mut iterator = UnioningFragmentBoundsIterator::new(requested_node); let mut iterator = UnioningFragmentOverflowIterator::new(requested_node);
sequential::iterate_through_flow_tree_fragment_bounds(layout_root, &mut iterator); sequential::iterate_through_flow_tree_fragment_bounds(layout_root, &mut iterator);
rw_data.content_box_response = iterator.rect; rw_data.content_box_response = iterator.rect;
} }
@ -616,7 +616,7 @@ impl LayoutTask {
// FIXME(pcwalton): This has not been updated to handle the stacking context relative // FIXME(pcwalton): This has not been updated to handle the stacking context relative
// stuff. So the position is wrong in most cases. // stuff. So the position is wrong in most cases.
let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node); let requested_node: OpaqueNode = OpaqueNodeMethods::from_script_node(requested_node);
let mut iterator = CollectingFragmentBoundsIterator::new(requested_node); let mut iterator = CollectingFragmentOverflowIterator::new(requested_node);
sequential::iterate_through_flow_tree_fragment_bounds(layout_root, &mut iterator); sequential::iterate_through_flow_tree_fragment_bounds(layout_root, &mut iterator);
rw_data.content_boxes_response = iterator.rects; rw_data.content_boxes_response = iterator.rects;
} }
@ -693,7 +693,8 @@ impl LayoutTask {
Scrollable)); Scrollable));
let origin = Rect(Point2D(Au(0), Au(0)), root_size); let origin = Rect(Point2D(Au(0), Au(0)), root_size);
let stacking_context = Arc::new(StackingContext::new(display_list, let stacking_context = Arc::new(StackingContext::new(display_list,
origin, &origin,
&origin,
0, 0,
1.0, 1.0,
Some(paint_layer))); Some(paint_layer)));
@ -1016,21 +1017,21 @@ impl LayoutRPC for LayoutRPCImpl {
} }
} }
struct UnioningFragmentBoundsIterator { struct UnioningFragmentOverflowIterator {
node_address: OpaqueNode, node_address: OpaqueNode,
rect: Rect<Au>, rect: Rect<Au>,
} }
impl UnioningFragmentBoundsIterator { impl UnioningFragmentOverflowIterator {
fn new(node_address: OpaqueNode) -> UnioningFragmentBoundsIterator { fn new(node_address: OpaqueNode) -> UnioningFragmentOverflowIterator {
UnioningFragmentBoundsIterator { UnioningFragmentOverflowIterator {
node_address: node_address, node_address: node_address,
rect: Rect::zero(), rect: Rect::zero(),
} }
} }
} }
impl FragmentBoundsIterator for UnioningFragmentBoundsIterator { impl FragmentOverflowIterator for UnioningFragmentOverflowIterator {
fn process(&mut self, _: &Fragment, bounds: Rect<Au>) { fn process(&mut self, _: &Fragment, bounds: Rect<Au>) {
if self.rect.is_empty() { if self.rect.is_empty() {
self.rect = bounds; self.rect = bounds;
@ -1044,21 +1045,21 @@ impl FragmentBoundsIterator for UnioningFragmentBoundsIterator {
} }
} }
struct CollectingFragmentBoundsIterator { struct CollectingFragmentOverflowIterator {
node_address: OpaqueNode, node_address: OpaqueNode,
rects: Vec<Rect<Au>>, rects: Vec<Rect<Au>>,
} }
impl CollectingFragmentBoundsIterator { impl CollectingFragmentOverflowIterator {
fn new(node_address: OpaqueNode) -> CollectingFragmentBoundsIterator { fn new(node_address: OpaqueNode) -> CollectingFragmentOverflowIterator {
CollectingFragmentBoundsIterator { CollectingFragmentOverflowIterator {
node_address: node_address, node_address: node_address,
rects: Vec::new(), rects: Vec::new(),
} }
} }
} }
impl FragmentBoundsIterator for CollectingFragmentBoundsIterator { impl FragmentOverflowIterator for CollectingFragmentOverflowIterator {
fn process(&mut self, _: &Fragment, bounds: Rect<Au>) { fn process(&mut self, _: &Fragment, bounds: Rect<Au>) {
self.rects.push(bounds); self.rects.push(bounds);
} }

View file

@ -12,9 +12,10 @@ use construct::FlowConstructor;
use context::LayoutContext; use context::LayoutContext;
use display_list_builder::ListItemFlowDisplayListBuilding; use display_list_builder::ListItemFlowDisplayListBuilding;
use flow::{Flow, FlowClass}; use flow::{Flow, FlowClass};
use fragment::{Fragment, FragmentBoundsIterator}; use fragment::{Fragment, FragmentOverflowIterator};
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use geom::Rect;
use gfx::display_list::DisplayList; use gfx::display_list::DisplayList;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::opts; use servo_util::opts;
@ -111,8 +112,12 @@ impl Flow for ListItemFlow {
self.block_flow.repair_style(new_style) self.block_flow.repair_style(new_style)
} }
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { fn compute_overflow(&self) -> Rect<Au> {
self.block_flow.iterate_through_fragment_bounds(iterator); self.block_flow.compute_overflow()
}
fn iterate_through_fragment_overflow(&self, iterator: &mut FragmentOverflowIterator) {
self.block_flow.iterate_through_fragment_overflow(iterator);
} }
} }

View file

@ -8,7 +8,7 @@ use context::{LayoutContext, SharedLayoutContext};
use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal}; use flow::{Flow, MutableFlowUtils, PreorderFlowTraversal, PostorderFlowTraversal};
use flow; use flow;
use flow_ref::FlowRef; use flow_ref::FlowRef;
use fragment::FragmentBoundsIterator; use fragment::FragmentOverflowIterator;
use servo_util::opts; use servo_util::opts;
use traversal::{BubbleISizes, RecalcStyleForNode, ConstructFlows}; use traversal::{BubbleISizes, RecalcStyleForNode, ConstructFlows};
use traversal::{AssignBSizesAndStoreOverflow, AssignISizes}; use traversal::{AssignBSizesAndStoreOverflow, AssignISizes};
@ -95,9 +95,9 @@ pub fn build_display_list_for_subtree(root: &mut FlowRef,
} }
pub fn iterate_through_flow_tree_fragment_bounds(root: &mut FlowRef, pub fn iterate_through_flow_tree_fragment_bounds(root: &mut FlowRef,
iterator: &mut FragmentBoundsIterator) { iterator: &mut FragmentOverflowIterator) {
fn doit(flow: &mut Flow, iterator: &mut FragmentBoundsIterator) { fn doit(flow: &mut Flow, iterator: &mut FragmentOverflowIterator) {
flow.iterate_through_fragment_bounds(iterator); flow.iterate_through_fragment_overflow(iterator);
for kid in flow::mut_base(flow).child_iter() { for kid in flow::mut_base(flow).child_iter() {
doit(kid, iterator); doit(kid, iterator);

View file

@ -13,13 +13,14 @@ use context::LayoutContext;
use floats::FloatKind; use floats::FloatKind;
use flow::{mod, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; use flow::{mod, Flow, FlowClass, IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
use flow::ImmutableFlowUtils; use flow::ImmutableFlowUtils;
use fragment::{Fragment, FragmentBoundsIterator}; use fragment::{Fragment, FragmentOverflowIterator};
use layout_debug; use layout_debug;
use model::{IntrinsicISizes, IntrinsicISizesContribution}; use model::{IntrinsicISizes, IntrinsicISizesContribution};
use table_row::CellIntrinsicInlineSize; use table_row::CellIntrinsicInlineSize;
use table_wrapper::TableLayout; use table_wrapper::TableLayout;
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use geom::Rect;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use servo_util::logical_geometry::LogicalRect; use servo_util::logical_geometry::LogicalRect;
use std::cmp::max; use std::cmp::max;
@ -384,8 +385,12 @@ impl Flow for TableFlow {
self.block_flow.repair_style(new_style) self.block_flow.repair_style(new_style)
} }
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { fn compute_overflow(&self) -> Rect<Au> {
self.block_flow.iterate_through_fragment_bounds(iterator); self.block_flow.compute_overflow()
}
fn iterate_through_fragment_overflow(&self, iterator: &mut FragmentOverflowIterator) {
self.block_flow.iterate_through_fragment_overflow(iterator);
} }
} }

View file

@ -10,9 +10,10 @@ use block::BlockFlow;
use construct::FlowConstructor; use construct::FlowConstructor;
use context::LayoutContext; use context::LayoutContext;
use flow::{FlowClass, Flow}; use flow::{FlowClass, Flow};
use fragment::FragmentBoundsIterator; use fragment::FragmentOverflowIterator;
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use geom::Rect;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use std::fmt; use std::fmt;
use style::ComputedValues; use style::ComputedValues;
@ -81,8 +82,12 @@ impl Flow for TableCaptionFlow {
self.block_flow.repair_style(new_style) self.block_flow.repair_style(new_style)
} }
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { fn compute_overflow(&self) -> Rect<Au> {
self.block_flow.iterate_through_fragment_bounds(iterator); self.block_flow.compute_overflow()
}
fn iterate_through_fragment_overflow(&self, iterator: &mut FragmentOverflowIterator) {
self.block_flow.iterate_through_fragment_overflow(iterator);
} }
} }

View file

@ -9,12 +9,13 @@
use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag}; use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
use context::LayoutContext; use context::LayoutContext;
use flow::{Flow, FlowClass}; use flow::{Flow, FlowClass};
use fragment::{Fragment, FragmentBoundsIterator}; use fragment::{Fragment, FragmentOverflowIterator};
use model::{MaybeAuto}; use model::{MaybeAuto};
use layout_debug; use layout_debug;
use table::InternalTable; use table::InternalTable;
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use geom::Rect;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use std::fmt; use std::fmt;
use style::{UnsignedIntegerAttribute, ComputedValues}; use style::{UnsignedIntegerAttribute, ComputedValues};
@ -162,8 +163,12 @@ impl Flow for TableCellFlow {
self.block_flow.repair_style(new_style) self.block_flow.repair_style(new_style)
} }
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { fn compute_overflow(&self) -> Rect<Au> {
self.block_flow.iterate_through_fragment_bounds(iterator); self.block_flow.compute_overflow()
}
fn iterate_through_fragment_overflow(&self, iterator: &mut FragmentOverflowIterator) {
self.block_flow.iterate_through_fragment_overflow(iterator);
} }
} }

View file

@ -9,11 +9,12 @@
use context::LayoutContext; use context::LayoutContext;
use css::node_style::StyledNode; use css::node_style::StyledNode;
use flow::{BaseFlow, FlowClass, Flow, ForceNonfloatedFlag}; use flow::{BaseFlow, FlowClass, Flow, ForceNonfloatedFlag};
use fragment::{Fragment, FragmentBoundsIterator, SpecificFragmentInfo}; use fragment::{Fragment, FragmentOverflowIterator, SpecificFragmentInfo};
use layout_debug; use layout_debug;
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use servo_util::geometry::Au; use geom::Rect;
use servo_util::geometry::{Au, ZERO_RECT};
use std::cmp::max; use std::cmp::max;
use std::fmt; use std::fmt;
use style::computed_values::LengthOrPercentageOrAuto; use style::computed_values::LengthOrPercentageOrAuto;
@ -96,7 +97,11 @@ impl Flow for TableColGroupFlow {
fn repair_style(&mut self, _: &Arc<ComputedValues>) {} fn repair_style(&mut self, _: &Arc<ComputedValues>) {}
fn iterate_through_fragment_bounds(&self, _: &mut FragmentBoundsIterator) { fn compute_overflow(&self) -> Rect<Au> {
ZERO_RECT
}
fn iterate_through_fragment_overflow(&self, _: &mut FragmentOverflowIterator) {
} }
} }

View file

@ -12,12 +12,13 @@ use construct::FlowConstructor;
use context::LayoutContext; use context::LayoutContext;
use flow::{FlowClass, Flow, ImmutableFlowUtils}; use flow::{FlowClass, Flow, ImmutableFlowUtils};
use flow; use flow;
use fragment::{Fragment, FragmentBoundsIterator}; use fragment::{Fragment, FragmentOverflowIterator};
use layout_debug; use layout_debug;
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable}; use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable};
use model::MaybeAuto; use model::MaybeAuto;
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use geom::Rect;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use std::cmp::max; use std::cmp::max;
use std::fmt; use std::fmt;
@ -315,8 +316,12 @@ impl Flow for TableRowFlow {
self.block_flow.repair_style(new_style) self.block_flow.repair_style(new_style)
} }
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { fn compute_overflow(&self) -> Rect<Au> {
self.block_flow.iterate_through_fragment_bounds(iterator); self.block_flow.compute_overflow()
}
fn iterate_through_fragment_overflow(&self, iterator: &mut FragmentOverflowIterator) {
self.block_flow.iterate_through_fragment_overflow(iterator);
} }
} }

View file

@ -10,11 +10,12 @@ use block::{BlockFlow, ISizeAndMarginsComputer, MarginsMayCollapseFlag};
use construct::FlowConstructor; use construct::FlowConstructor;
use context::LayoutContext; use context::LayoutContext;
use flow::{FlowClass, Flow}; use flow::{FlowClass, Flow};
use fragment::{Fragment, FragmentBoundsIterator}; use fragment::{Fragment, FragmentOverflowIterator};
use layout_debug; use layout_debug;
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable}; use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize, InternalTable};
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use geom::Rect;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use std::fmt; use std::fmt;
use style::ComputedValues; use style::ComputedValues;
@ -150,8 +151,12 @@ impl Flow for TableRowGroupFlow {
self.block_flow.repair_style(new_style) self.block_flow.repair_style(new_style)
} }
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { fn compute_overflow(&self) -> Rect<Au> {
self.block_flow.iterate_through_fragment_bounds(iterator); self.block_flow.compute_overflow()
}
fn iterate_through_fragment_overflow(&self, iterator: &mut FragmentOverflowIterator) {
self.block_flow.iterate_through_fragment_overflow(iterator);
} }
} }

View file

@ -19,10 +19,11 @@ use context::LayoutContext;
use floats::FloatKind; use floats::FloatKind;
use flow::{FlowClass, Flow, ImmutableFlowUtils}; use flow::{FlowClass, Flow, ImmutableFlowUtils};
use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS}; use flow::{IMPACTED_BY_LEFT_FLOATS, IMPACTED_BY_RIGHT_FLOATS};
use fragment::{Fragment, FragmentBoundsIterator}; use fragment::{Fragment, FragmentOverflowIterator};
use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize}; use table::{ColumnComputedInlineSize, ColumnIntrinsicInlineSize};
use wrapper::ThreadSafeLayoutNode; use wrapper::ThreadSafeLayoutNode;
use geom::Rect;
use servo_util::geometry::Au; use servo_util::geometry::Au;
use std::cmp::{max, min}; use std::cmp::{max, min};
use std::fmt; use std::fmt;
@ -358,8 +359,12 @@ impl Flow for TableWrapperFlow {
self.block_flow.repair_style(new_style) self.block_flow.repair_style(new_style)
} }
fn iterate_through_fragment_bounds(&self, iterator: &mut FragmentBoundsIterator) { fn compute_overflow(&self) -> Rect<Au> {
self.block_flow.iterate_through_fragment_bounds(iterator); self.block_flow.compute_overflow()
}
fn iterate_through_fragment_overflow(&self, iterator: &mut FragmentOverflowIterator) {
self.block_flow.iterate_through_fragment_overflow(iterator);
} }
} }

View file

@ -332,13 +332,8 @@ impl<'a> PostorderFlowTraversal for AssignBSizesAndStoreOverflow<'a> {
} }
flow.assign_block_size(self.layout_context); flow.assign_block_size(self.layout_context);
// Skip store-overflow for absolutely positioned flows. That will be
// done in a separate traversal.
if !flow.is_store_overflow_delayed() {
flow.store_overflow(self.layout_context); flow.store_overflow(self.layout_context);
} }
}
#[inline] #[inline]
fn should_process(&self, flow: &mut Flow) -> bool { fn should_process(&self, flow: &mut Flow) -> bool {

View file

@ -75,7 +75,7 @@ pub struct LayerMetadata {
/// An opaque ID. This is usually the address of the flow and index of the box within it. /// An opaque ID. This is usually the address of the flow and index of the box within it.
pub id: LayerId, pub id: LayerId,
/// The position and size of the layer in pixels. /// The position and size of the layer in pixels.
pub position: Rect<uint>, pub position: Rect<i32>,
/// The background color of the layer. /// The background color of the layer.
pub background_color: Color, pub background_color: Color,
/// The scrolling policy of this layer. /// The scrolling policy of this layer.

View file

@ -248,7 +248,7 @@ source = "git+https://github.com/alexcrichton/gcc-rs#903e8f8a2e3766ad3d514404d45
[[package]] [[package]]
name = "geom" name = "geom"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/servo/rust-geom#da6b4a36a5549cf78bf702f0b9387b5c8cf61498" source = "git+https://github.com/servo/rust-geom#0f77c6ad116748b7e6bedbf2414d4ceea17debc2"
[[package]] [[package]]
name = "gfx" name = "gfx"

2
ports/cef/Cargo.lock generated
View file

@ -244,7 +244,7 @@ source = "git+https://github.com/alexcrichton/gcc-rs#903e8f8a2e3766ad3d514404d45
[[package]] [[package]]
name = "geom" name = "geom"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/servo/rust-geom#da6b4a36a5549cf78bf702f0b9387b5c8cf61498" source = "git+https://github.com/servo/rust-geom#0f77c6ad116748b7e6bedbf2414d4ceea17debc2"
[[package]] [[package]]
name = "gfx" name = "gfx"

2
ports/gonk/Cargo.lock generated
View file

@ -227,7 +227,7 @@ source = "git+https://github.com/alexcrichton/gcc-rs#903e8f8a2e3766ad3d514404d45
[[package]] [[package]]
name = "geom" name = "geom"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/servo/rust-geom#da6b4a36a5549cf78bf702f0b9387b5c8cf61498" source = "git+https://github.com/servo/rust-geom#0f77c6ad116748b7e6bedbf2414d4ceea17debc2"
[[package]] [[package]]
name = "gfx" name = "gfx"

View file

@ -222,3 +222,5 @@ fragment=top != ../html/acid2.html acid2_ref.html
!= inset_blackborder.html blackborder_ref.html != inset_blackborder.html blackborder_ref.html
!= outset_blackborder.html blackborder_ref.html != outset_blackborder.html blackborder_ref.html
== border_radius_clip_a.html border_radius_clip_ref.html == border_radius_clip_a.html border_radius_clip_ref.html
== stacking_context_overflow_a.html stacking_context_overflow_ref.html
== stacking_context_overflow_relative_outline_a.html stacking_context_overflow_relative_outline_ref.html

View file

@ -1,7 +1,7 @@
<html> <html>
<body> <body>
<div style="position: absolute; top: 0px; left: 0px;"> <div style="position: absolute; top: 0px; left: 0px;">
<div style="position: absolute; background: green; margin-left: 512px; width: 20px; height: 20px;"></div> <div style="position: absolute; background: green; top: 0; margin-left: 512px; width: 20px; height: 20px;"></div>
<!-- This position:fixed sibling should force its sibling to be layerized. --> <!-- This position:fixed sibling should force its sibling to be layerized. -->
<div style="position: fixed;"></div> <div style="position: fixed;"></div>

View file

@ -0,0 +1,22 @@
<html>
<head>
<!-- Tests that stacking contexts display overflow. -->
<style>
body {
margin: 0;
}
section {
position: absolute;
z-index: 1;
width: 72px;
height: 72px;
border: solid black 2px;
font: 24px Arial;
}
</style>
</head>
<body>
<section>CSS IS AWESOME</section>
</body>
</html>

View file

@ -0,0 +1,21 @@
<html>
<head>
<!-- Tests that stacking contexts display overflow. -->
<style>
body {
margin: 0;
}
section {
width: 72px;
height: 72px;
border: solid black 2px;
font: 24px Arial;
}
</style>
</head>
<body>
<section>CSS IS AWESOME</section>
</body>
</html>

View file

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html>
<style>
section {
position: absolute;
top: 100px;
left: 100px;
width: 10px;
height: 10px;
}
h1 {
position: relative;
top: -50px;
left: -50px;
width: 200px;
height: 200px;
margin: 0;
outline: solid 10px green;
}
</style>
<body>
<section><h1></h1></section>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<style>
section {
position: absolute;
top: 40px;
left: 40px;
width: 200px;
height: 200px;
border: solid 10px green;
}
</style>
<body>
<section></section>
</body>
</html>