Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layout: Paint stacking contexts' overflow areas properly. #4460

Closed
wants to merge 2 commits into from
Closed
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Next

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.
  • Loading branch information
pcwalton committed Jan 5, 2015
commit 5ea2c6dcfdfc24ce3730f736fcd045a13bcdc5b6
@@ -283,8 +283,7 @@ impl CompositorLayer for Layer<CompositorData> {
self.clamp_scroll_offset_and_scroll_layer(scroll_offset + delta)
}

fn clamp_scroll_offset_and_scroll_layer(&self,
new_offset: TypedPoint2D<LayerPixel, f32>)
fn clamp_scroll_offset_and_scroll_layer(&self, new_offset: TypedPoint2D<LayerPixel, f32>)
-> ScrollEventResult {
let layer_size = self.bounds.borrow().size;
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));
}

fn scroll_layer_and_all_child_layers(&self,
new_offset: TypedPoint2D<LayerPixel, f32>)
fn scroll_layer_and_all_child_layers(&self, new_offset: TypedPoint2D<LayerPixel, f32>)
-> bool {
let mut result = false;

// Only scroll this layer if it's not fixed-positioned.
if self.extra_data.borrow().scroll_policy != FixedPosition {
let new_offset = new_offset.to_untyped();
*self.transform.borrow_mut() = identity().translate(new_offset.x,
new_offset.y,
0.0);
*self.transform.borrow_mut() = identity().translate(new_offset.x, new_offset.y, 0.0);
*self.content_offset.borrow_mut() = Point2D::from_untyped(&new_offset);
result = true
}
@@ -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,21 +170,19 @@ 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>>)
-> 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();
@@ -41,15 +41,15 @@ use flow::{LAYERS_NEEDED_FOR_DESCENDANTS, NEEDS_LAYER};
use flow::{IS_ABSOLUTELY_POSITIONED};
use flow::{CLEARS_LEFT, CLEARS_RIGHT};
use flow;
use fragment::{Fragment, FragmentBoundsIterator, SpecificFragmentInfo};
use fragment::{Fragment, FragmentOverflowIterator, SpecificFragmentInfo};
use incremental::{REFLOW, REFLOW_OUT_OF_FLOW};
use layout_debug;
use model::{IntrinsicISizes, MarginCollapseInfo};
use model::{MaybeAuto, CollapsibleMargins, specified, specified_or_none};
use table::ColumnComputedInlineSize;
use wrapper::ThreadSafeLayoutNode;

use geom::Size2D;
use geom::{Rect, Size2D};
use gfx::display_list::{ClippingRegion, DisplayList};
use serialize::{Encoder, Encodable};
use servo_msg::compositor_msg::LayerId;
@@ -1797,13 +1797,6 @@ impl Flow for BlockFlow {
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 {
self.flags.contains(IS_ROOT)
}
@@ -1864,12 +1857,13 @@ impl Flow for BlockFlow {
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) {
let fragment_origin =
self.base.stacking_relative_position_of_child_fragment(&self.fragment);
iterator.process(&self.fragment,
self.fragment.stacking_relative_bounds(&fragment_origin));
iterator.process(&self.fragment, self.fragment.compute_overflow());
}
}
}
@@ -2455,11 +2449,14 @@ impl ISizeAndMarginsComputer for AbsoluteReplaced {
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
}

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.
block.base.position.start.i = solution.inline_start;
}
@@ -1103,7 +1103,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
background_border_level);

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 {
DisplayListBuildingResult::Normal(display_list)
}
@@ -1120,7 +1121,9 @@ 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.create_stacking_context(display_list, None));
DisplayListBuildingResult::StackingContext(self.create_stacking_context(
display_list,
None));
return
}

@@ -1137,7 +1140,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
Some(Arc::new(PaintLayer::new(self.layer_id(0),
transparent,
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,
@@ -1149,7 +1153,8 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
display_list.form_float_pseudo_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 {
DisplayListBuildingResult::Normal(display_list)
}
@@ -1165,19 +1170,26 @@ impl BlockFlowDisplayListBuilding for BlockFlow {
} else if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
self.build_display_list_for_absolutely_positioned_block(display_list, layout_context)
} 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)
}
}

fn create_stacking_context(&self,
display_list: Box<DisplayList>,
layer: Option<Arc<PaintLayer>>)
-> Arc<StackingContext> {
let bounds = Rect(self.base.stacking_relative_position,
self.base.overflow.size.to_physical(self.base.writing_mode));
let size = self.base.position.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 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))
}
}

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.