mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
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:
parent
ba8cf6b0e6
commit
5ea2c6dcfd
30 changed files with 357 additions and 179 deletions
|
@ -34,7 +34,7 @@ use servo_msg::compositor_msg::LayerId;
|
|||
use servo_net::image::base::Image;
|
||||
use servo_util::cursor::Cursor;
|
||||
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::smallvec::{SmallVec, SmallVec8};
|
||||
use std::fmt;
|
||||
|
@ -160,9 +160,8 @@ pub struct StackingContext {
|
|||
pub layer: Option<Arc<PaintLayer>>,
|
||||
/// The position and size of this stacking context.
|
||||
pub bounds: Rect<Au>,
|
||||
/// The clipping rect for this stacking context, in the coordinate system of the *parent*
|
||||
/// stacking context.
|
||||
pub clip_rect: Rect<Au>,
|
||||
/// The overflow rect for this stacking context in its coordinate system.
|
||||
pub overflow: Rect<Au>,
|
||||
/// The `z-index` for this stacking context.
|
||||
pub z_index: i32,
|
||||
/// The opacity of this stacking context.
|
||||
|
@ -171,12 +170,10 @@ pub struct StackingContext {
|
|||
|
||||
impl StackingContext {
|
||||
/// Creates a new stacking context.
|
||||
///
|
||||
/// TODO(pcwalton): Stacking contexts should not always be clipped to their bounds, to handle
|
||||
/// overflow properly.
|
||||
#[inline]
|
||||
pub fn new(display_list: Box<DisplayList>,
|
||||
bounds: Rect<Au>,
|
||||
bounds: &Rect<Au>,
|
||||
overflow: &Rect<Au>,
|
||||
z_index: i32,
|
||||
opacity: AzFloat,
|
||||
layer: Option<Arc<PaintLayer>>)
|
||||
|
@ -184,8 +181,8 @@ impl StackingContext {
|
|||
StackingContext {
|
||||
display_list: display_list,
|
||||
layer: layer,
|
||||
bounds: bounds,
|
||||
clip_rect: Rect(ZERO_POINT, bounds.size),
|
||||
bounds: *bounds,
|
||||
overflow: *overflow,
|
||||
z_index: z_index,
|
||||
opacity: opacity,
|
||||
}
|
||||
|
@ -196,7 +193,7 @@ impl StackingContext {
|
|||
paint_context: &mut PaintContext,
|
||||
tile_bounds: &Rect<AzFloat>,
|
||||
transform: &Matrix2D<AzFloat>,
|
||||
clip_rect: Option<Rect<Au>>) {
|
||||
clip_rect: Option<&Rect<Au>>) {
|
||||
let temporary_draw_target =
|
||||
paint_context.get_or_create_temporary_draw_target(self.opacity);
|
||||
{
|
||||
|
@ -205,7 +202,7 @@ impl StackingContext {
|
|||
font_ctx: &mut *paint_context.font_ctx,
|
||||
page_rect: paint_context.page_rect,
|
||||
screen_rect: paint_context.screen_rect,
|
||||
clip_rect: clip_rect,
|
||||
clip_rect: clip_rect.map(|clip_rect| *clip_rect),
|
||||
transient_clip: None,
|
||||
};
|
||||
|
||||
|
@ -252,7 +249,7 @@ impl StackingContext {
|
|||
positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext,
|
||||
&new_tile_rect,
|
||||
&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,
|
||||
&new_tile_rect,
|
||||
&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();
|
||||
let tile_subrect = tile_bounds.intersection(&child_stacking_context_bounds)
|
||||
// Translate the child's overflow region into our coordinate system.
|
||||
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);
|
||||
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
|
||||
|
|
|
@ -59,7 +59,8 @@ impl DisplayListOptimizer {
|
|||
mut stacking_contexts: I)
|
||||
where I: Iterator<&'a Arc<StackingContext>> {
|
||||
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())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,20 +148,21 @@ fn initialize_layers<C>(compositor: &mut C,
|
|||
stacking_context: &StackingContext,
|
||||
page_position: &Point2D<Au>) {
|
||||
let page_position = stacking_context.bounds.origin + *page_position;
|
||||
match stacking_context.layer {
|
||||
None => {}
|
||||
Some(ref paint_layer) => {
|
||||
metadata.push(LayerMetadata {
|
||||
id: paint_layer.id,
|
||||
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,
|
||||
scroll_policy: paint_layer.scroll_policy,
|
||||
})
|
||||
}
|
||||
if let Some(ref paint_layer) = stacking_context.layer {
|
||||
// Layers start at the top left of their overflow rect, as far as the info we give to
|
||||
// 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 {
|
||||
id: paint_layer.id,
|
||||
position: layer_position,
|
||||
background_color: paint_layer.background_color,
|
||||
scroll_policy: paint_layer.scroll_policy,
|
||||
})
|
||||
}
|
||||
|
||||
for kid in stacking_context.display_list.children.iter() {
|
||||
|
@ -384,15 +385,14 @@ impl<C> PaintTask<C> where C: PaintListener + Send {
|
|||
layer_id: LayerId) {
|
||||
profile(TimeProfilerCategory::Painting, None, self.time_profiler_chan.clone(), || {
|
||||
// Bail out if there is no appropriate stacking context.
|
||||
let stacking_context = match self.root_stacking_context {
|
||||
Some(ref stacking_context) => {
|
||||
match display_list::find_stacking_context_with_layer_id(stacking_context,
|
||||
layer_id) {
|
||||
Some(stacking_context) => stacking_context,
|
||||
None => return,
|
||||
}
|
||||
let stacking_context = if let Some(ref stacking_context) = self.root_stacking_context {
|
||||
match display_list::find_stacking_context_with_layer_id(stacking_context,
|
||||
layer_id) {
|
||||
Some(stacking_context) => stacking_context,
|
||||
None => return,
|
||||
}
|
||||
None => return,
|
||||
} else {
|
||||
return
|
||||
};
|
||||
|
||||
// Divide up the layer into tiles and distribute them to workers via a simple round-
|
||||
|
@ -547,8 +547,13 @@ impl WorkerThread {
|
|||
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.
|
||||
let tile_bounds = tile.page_rect;
|
||||
let matrix: Matrix2D<AzFloat> = Matrix2D::identity();
|
||||
let matrix = matrix.scale(scale as AzFloat, scale as AzFloat);
|
||||
let matrix = matrix.translate(-tile_bounds.origin.x as AzFloat,
|
||||
|
@ -561,7 +566,7 @@ impl WorkerThread {
|
|||
profile(TimeProfilerCategory::PaintingPerTile, None,
|
||||
self.time_profiler_sender.clone(), || {
|
||||
stacking_context.optimize_and_draw_into_context(&mut paint_context,
|
||||
&tile.page_rect,
|
||||
&tile_bounds,
|
||||
&matrix,
|
||||
None);
|
||||
paint_context.draw_target.flush();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue