servo: Merge #4272 - gfx: Update Azure and Skia, and rewrite broken clipping logic (from pcwalton:upgrade-azure); r=mrobinson

This exposed some problems in our clipping logic, which was never
properly rewritten for the stacking context reform. The clipping code
worked in terms of a stack of clips, but the new stacking context code
has no concept of a stack of clip regions. Fixing that in turn exposed
some flaky/incorrect tests:

* `borders` had an incorrect reference image, as far as I can tell.

* `negative_margins` had some stray pixels, fixed by changing the text.

r? @mrobinson

Source-Repo: https://github.com/servo/servo
Source-Revision: 40c706b42d9d29ef58913f22da49159796e1b81b
This commit is contained in:
Patrick Walton 2014-12-08 14:52:02 -07:00
parent 40deabd7f7
commit c02b013483
4 changed files with 67 additions and 55 deletions

View File

@ -176,8 +176,8 @@ impl StackingContext {
pub fn optimize_and_draw_into_context(&self, pub fn optimize_and_draw_into_context(&self,
paint_context: &mut PaintContext, paint_context: &mut PaintContext,
tile_bounds: &Rect<AzFloat>, tile_bounds: &Rect<AzFloat>,
current_transform: &Matrix2D<AzFloat>, transform: &Matrix2D<AzFloat>,
current_clip_stack: &mut Vec<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);
{ {
@ -186,7 +186,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,
..*paint_context transient_clip_rect: None,
}; };
// Optimize the display list to throw out out-of-bounds display items and so forth. // Optimize the display list to throw out out-of-bounds display items and so forth.
@ -201,11 +201,17 @@ impl StackingContext {
positioned_children.as_slice_mut() positioned_children.as_slice_mut()
.sort_by(|this, other| this.z_index.cmp(&other.z_index)); .sort_by(|this, other| this.z_index.cmp(&other.z_index));
// Set up our clip rect and transform.
match clip_rect {
None => {}
Some(clip_rect) => paint_subcontext.draw_push_clip(clip_rect),
}
let old_transform = paint_subcontext.draw_target.get_transform();
paint_subcontext.draw_target.set_transform(transform);
// Steps 1 and 2: Borders and background for the root. // Steps 1 and 2: Borders and background for the root.
for display_item in display_list.background_and_borders.iter() { for display_item in display_list.background_and_borders.iter() {
display_item.draw_into_context(&mut paint_subcontext, display_item.draw_into_context(&mut paint_subcontext)
current_transform,
current_clip_stack)
} }
// Step 3: Positioned descendants with negative z-indices. // Step 3: Positioned descendants with negative z-indices.
@ -215,41 +221,39 @@ impl StackingContext {
} }
if positioned_kid.layer.is_none() { if positioned_kid.layer.is_none() {
let new_transform = let new_transform =
current_transform.translate(positioned_kid.bounds.origin.x.to_nearest_px() transform.translate(positioned_kid.bounds
as AzFloat, .origin
positioned_kid.bounds.origin.y.to_nearest_px() .x
as AzFloat); .to_nearest_px() as AzFloat,
positioned_kid.bounds
.origin
.y
.to_nearest_px() as AzFloat);
let new_tile_rect = let new_tile_rect =
self.compute_tile_rect_for_child_stacking_context(tile_bounds, self.compute_tile_rect_for_child_stacking_context(tile_bounds,
&**positioned_kid); &**positioned_kid);
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,
current_clip_stack); Some(&positioned_kid.clip_rect))
} }
} }
// Step 4: Block backgrounds and borders. // Step 4: Block backgrounds and borders.
for display_item in display_list.block_backgrounds_and_borders.iter() { for display_item in display_list.block_backgrounds_and_borders.iter() {
display_item.draw_into_context(&mut paint_subcontext, display_item.draw_into_context(&mut paint_subcontext)
current_transform,
current_clip_stack)
} }
// Step 5: Floats. // Step 5: Floats.
for display_item in display_list.floats.iter() { for display_item in display_list.floats.iter() {
display_item.draw_into_context(&mut paint_subcontext, display_item.draw_into_context(&mut paint_subcontext)
current_transform,
current_clip_stack)
} }
// TODO(pcwalton): Step 6: Inlines that generate stacking contexts. // TODO(pcwalton): Step 6: Inlines that generate stacking contexts.
// Step 7: Content. // Step 7: Content.
for display_item in display_list.content.iter() { for display_item in display_list.content.iter() {
display_item.draw_into_context(&mut paint_subcontext, display_item.draw_into_context(&mut paint_subcontext)
current_transform,
current_clip_stack)
} }
// Steps 8 and 9: Positioned descendants with nonnegative z-indices. // Steps 8 and 9: Positioned descendants with nonnegative z-indices.
@ -260,25 +264,38 @@ impl StackingContext {
if positioned_kid.layer.is_none() { if positioned_kid.layer.is_none() {
let new_transform = let new_transform =
current_transform.translate(positioned_kid.bounds.origin.x.to_nearest_px() transform.translate(positioned_kid.bounds
as AzFloat, .origin
positioned_kid.bounds.origin.y.to_nearest_px() .x
as AzFloat); .to_nearest_px() as AzFloat,
positioned_kid.bounds
.origin
.y
.to_nearest_px() as AzFloat);
let new_tile_rect = let new_tile_rect =
self.compute_tile_rect_for_child_stacking_context(tile_bounds, self.compute_tile_rect_for_child_stacking_context(tile_bounds,
&**positioned_kid); &**positioned_kid);
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,
current_clip_stack); Some(&positioned_kid.clip_rect))
} }
} }
// TODO(pcwalton): Step 10: Outlines. // TODO(pcwalton): Step 10: Outlines.
// Undo our clipping and transform.
if paint_subcontext.transient_clip_rect.is_some() {
paint_subcontext.draw_pop_clip();
paint_subcontext.transient_clip_rect = None
}
paint_subcontext.draw_target.set_transform(&old_transform);
if clip_rect.is_some() {
paint_subcontext.draw_pop_clip()
}
} }
paint_context.draw_temporary_draw_target_if_necessary(&temporary_draw_target, paint_context.draw_temporary_draw_target_if_necessary(&temporary_draw_target, self.opacity)
self.opacity)
} }
/// Translate the given tile rect into the coordinate system of a child stacking context. /// Translate the given tile rect into the coordinate system of a child stacking context.
@ -560,24 +577,17 @@ impl<'a> Iterator<&'a DisplayItem> for DisplayItemIterator<'a> {
} }
impl DisplayItem { impl DisplayItem {
/// Paints this display item into the given paint context. /// Paints this display item into the given painting context.
fn draw_into_context(&self, fn draw_into_context(&self, paint_context: &mut PaintContext) {
paint_context: &mut PaintContext, let this_clip_rect = self.base().clip_rect;
current_transform: &Matrix2D<AzFloat>, if paint_context.transient_clip_rect != Some(this_clip_rect) {
current_clip_stack: &mut Vec<Rect<Au>>) { if paint_context.transient_clip_rect.is_some() {
// TODO(pcwalton): This will need some tweaking to deal with more complex clipping regions.
let clip_rect = &self.base().clip_rect;
if current_clip_stack.len() == 0 || current_clip_stack.last().unwrap() != clip_rect {
while current_clip_stack.len() != 0 {
paint_context.draw_pop_clip(); paint_context.draw_pop_clip();
drop(current_clip_stack.pop());
} }
paint_context.draw_push_clip(clip_rect); paint_context.draw_push_clip(&this_clip_rect);
current_clip_stack.push(*clip_rect); paint_context.transient_clip_rect = Some(this_clip_rect)
} }
paint_context.draw_target.set_transform(current_transform);
match *self { match *self {
SolidColorDisplayItemClass(ref solid_color) => { SolidColorDisplayItemClass(ref solid_color) => {
paint_context.draw_solid_color(&solid_color.base.bounds, solid_color.color) paint_context.draw_solid_color(&solid_color.base.bounds, solid_color.color)
@ -585,7 +595,7 @@ impl DisplayItem {
TextDisplayItemClass(ref text) => { TextDisplayItemClass(ref text) => {
debug!("Drawing text at {}.", text.base.bounds); debug!("Drawing text at {}.", text.base.bounds);
paint_context.draw_text(&**text, current_transform); paint_context.draw_text(&**text);
} }
ImageDisplayItemClass(ref image_item) => { ImageDisplayItemClass(ref image_item) => {

View File

@ -40,6 +40,10 @@ pub struct PaintContext<'a> {
pub page_rect: Rect<f32>, pub page_rect: Rect<f32>,
/// The rectangle that this context encompasses in screen coordinates (pixels). /// The rectangle that this context encompasses in screen coordinates (pixels).
pub screen_rect: Rect<uint>, pub screen_rect: Rect<uint>,
/// The current transient clipping rect, if any. A "transient clipping rect" is the clipping
/// rect used by the last display item. We cache the last value so that we avoid pushing and
/// popping clip rects unnecessarily.
pub transient_clip_rect: Option<Rect<Au>>,
} }
enum Direction { enum Direction {
@ -130,11 +134,11 @@ impl<'a> PaintContext<'a> {
size, size,
stride as i32, stride as i32,
source_format); source_format);
let source_rect = Rect(Point2D(0u as AzFloat, 0u as AzFloat), let source_rect = Rect(Point2D(0.0, 0.0),
Size2D(image.width as AzFloat, image.height as AzFloat)); Size2D(image.width as AzFloat, image.height as AzFloat));
let dest_rect = bounds.to_azure_rect(); let dest_rect = bounds.to_azure_rect();
let draw_surface_options = DrawSurfaceOptions::new(Linear, true); let draw_surface_options = DrawSurfaceOptions::new(Linear, true);
let draw_options = DrawOptions::new(1.0f64 as AzFloat, 0); let draw_options = DrawOptions::new(1.0, 0);
draw_target_ref.draw_surface(azure_surface, draw_target_ref.draw_surface(azure_surface,
dest_rect, dest_rect,
source_rect, source_rect,
@ -628,9 +632,9 @@ impl<'a> PaintContext<'a> {
self.draw_border_path(&original_bounds, direction, border, radius, scaled_color); self.draw_border_path(&original_bounds, direction, border, radius, scaled_color);
} }
pub fn draw_text(&mut self, pub fn draw_text(&mut self, text: &TextDisplayItem) {
text: &TextDisplayItem, let current_transform = self.draw_target.get_transform();
current_transform: &Matrix2D<AzFloat>) {
// Optimization: Dont set a transform matrix for upright text, and pass a start point to // Optimization: Dont set a transform matrix for upright text, and pass a start point to
// `draw_text_into_context`. // `draw_text_into_context`.
// //
@ -669,7 +673,7 @@ impl<'a> PaintContext<'a> {
// Undo the transform, only when we did one. // Undo the transform, only when we did one.
if text.orientation != Upright { if text.orientation != Upright {
self.draw_target.set_transform(current_transform) self.draw_target.set_transform(&current_transform)
} }
} }

View File

@ -509,6 +509,7 @@ impl WorkerThread {
font_ctx: &mut self.font_context, font_ctx: &mut self.font_context,
page_rect: tile.page_rect, page_rect: tile.page_rect,
screen_rect: tile.screen_rect, screen_rect: tile.screen_rect,
transient_clip_rect: None,
}; };
// Apply the translation to paint the tile we want. // Apply the translation to paint the tile we want.
@ -518,18 +519,15 @@ impl WorkerThread {
let matrix = matrix.translate(-tile_bounds.origin.x as AzFloat, let matrix = matrix.translate(-tile_bounds.origin.x as AzFloat,
-tile_bounds.origin.y as AzFloat); -tile_bounds.origin.y as AzFloat);
paint_context.draw_target.set_transform(&matrix);
// Clear the buffer. // Clear the buffer.
paint_context.clear(); paint_context.clear();
// Draw the display list. // Draw the display list.
profile(time::PaintingPerTileCategory, None, self.time_profiler_sender.clone(), || { profile(time::PaintingPerTileCategory, None, self.time_profiler_sender.clone(), || {
let mut clip_stack = Vec::new();
stacking_context.optimize_and_draw_into_context(&mut paint_context, stacking_context.optimize_and_draw_into_context(&mut paint_context,
&tile.page_rect, &tile.page_rect,
&matrix, &matrix,
&mut clip_stack); None);
paint_context.draw_target.flush(); paint_context.draw_target.flush();
}); });
} }

View File

@ -25,7 +25,7 @@ dependencies = [
[[package]] [[package]]
name = "azure" name = "azure"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/servo/rust-azure#d323c3c7c248d3d5a2d46a6a5ee61c6e92aec0b0" source = "git+https://github.com/servo/rust-azure#452939480f5ef7640714f16c6a9e5d02e0e2d147"
dependencies = [ dependencies = [
"core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)", "core_foundation 0.1.0 (git+https://github.com/servo/rust-core-foundation)",
"core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)", "core_graphics 0.1.0 (git+https://github.com/servo/rust-core-graphics)",
@ -34,7 +34,7 @@ dependencies = [
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)", "freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
"geom 0.1.0 (git+https://github.com/servo/rust-geom)", "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
"layers 0.1.0 (git+https://github.com/servo/rust-layers)", "layers 0.1.0 (git+https://github.com/servo/rust-layers)",
"skia-sys 0.0.20130412 (git+https://github.com/servo/skia)", "skia-sys 0.0.20130412 (git+https://github.com/servo/skia?ref=upstream-2014-06-16)",
"xlib 0.1.0 (git+https://github.com/servo/rust-xlib)", "xlib 0.1.0 (git+https://github.com/servo/rust-xlib)",
] ]
@ -600,7 +600,7 @@ source = "git+https://github.com/rust-lang/semver#7dca047a9cd40e929a4545b37a1917
[[package]] [[package]]
name = "skia-sys" name = "skia-sys"
version = "0.0.20130412" version = "0.0.20130412"
source = "git+https://github.com/servo/skia#79aa9354837bc195b83fa041b9632ea628e6f7d0" source = "git+https://github.com/servo/skia?ref=upstream-2014-06-16#c3dd8cacbddbfc20b0dae9b456ac1545b0402cff"
dependencies = [ dependencies = [
"expat-sys 2.1.0 (git+https://github.com/servo/libexpat)", "expat-sys 2.1.0 (git+https://github.com/servo/libexpat)",
"freetype-sys 2.4.11 (git+https://github.com/servo/libfreetype2)", "freetype-sys 2.4.11 (git+https://github.com/servo/libfreetype2)",