gfx: Update Azure and Skia, and rewrite broken clipping logic.

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.
This commit is contained in:
Patrick Walton 2014-12-05 03:55:39 -08:00
parent 368d6dc6bf
commit 1d845ee4f2
7 changed files with 71 additions and 61 deletions

View file

@ -176,8 +176,8 @@ impl StackingContext {
pub fn optimize_and_draw_into_context(&self,
paint_context: &mut PaintContext,
tile_bounds: &Rect<AzFloat>,
current_transform: &Matrix2D<AzFloat>,
current_clip_stack: &mut Vec<Rect<Au>>) {
transform: &Matrix2D<AzFloat>,
clip_rect: Option<&Rect<Au>>) {
let temporary_draw_target =
paint_context.get_or_create_temporary_draw_target(self.opacity);
{
@ -186,7 +186,7 @@ impl StackingContext {
font_ctx: &mut *paint_context.font_ctx,
page_rect: paint_context.page_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.
@ -201,11 +201,17 @@ impl StackingContext {
positioned_children.as_slice_mut()
.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.
for display_item in display_list.background_and_borders.iter() {
display_item.draw_into_context(&mut paint_subcontext,
current_transform,
current_clip_stack)
display_item.draw_into_context(&mut paint_subcontext)
}
// Step 3: Positioned descendants with negative z-indices.
@ -215,41 +221,39 @@ impl StackingContext {
}
if positioned_kid.layer.is_none() {
let new_transform =
current_transform.translate(positioned_kid.bounds.origin.x.to_nearest_px()
as AzFloat,
positioned_kid.bounds.origin.y.to_nearest_px()
as AzFloat);
transform.translate(positioned_kid.bounds
.origin
.x
.to_nearest_px() as AzFloat,
positioned_kid.bounds
.origin
.y
.to_nearest_px() as AzFloat);
let new_tile_rect =
self.compute_tile_rect_for_child_stacking_context(tile_bounds,
&**positioned_kid);
positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext,
&new_tile_rect,
&new_transform,
current_clip_stack);
Some(&positioned_kid.clip_rect))
}
}
// Step 4: Block backgrounds and borders.
for display_item in display_list.block_backgrounds_and_borders.iter() {
display_item.draw_into_context(&mut paint_subcontext,
current_transform,
current_clip_stack)
display_item.draw_into_context(&mut paint_subcontext)
}
// Step 5: Floats.
for display_item in display_list.floats.iter() {
display_item.draw_into_context(&mut paint_subcontext,
current_transform,
current_clip_stack)
display_item.draw_into_context(&mut paint_subcontext)
}
// TODO(pcwalton): Step 6: Inlines that generate stacking contexts.
// Step 7: Content.
for display_item in display_list.content.iter() {
display_item.draw_into_context(&mut paint_subcontext,
current_transform,
current_clip_stack)
display_item.draw_into_context(&mut paint_subcontext)
}
// Steps 8 and 9: Positioned descendants with nonnegative z-indices.
@ -260,25 +264,38 @@ impl StackingContext {
if positioned_kid.layer.is_none() {
let new_transform =
current_transform.translate(positioned_kid.bounds.origin.x.to_nearest_px()
as AzFloat,
positioned_kid.bounds.origin.y.to_nearest_px()
as AzFloat);
transform.translate(positioned_kid.bounds
.origin
.x
.to_nearest_px() as AzFloat,
positioned_kid.bounds
.origin
.y
.to_nearest_px() as AzFloat);
let new_tile_rect =
self.compute_tile_rect_for_child_stacking_context(tile_bounds,
&**positioned_kid);
positioned_kid.optimize_and_draw_into_context(&mut paint_subcontext,
&new_tile_rect,
&new_transform,
current_clip_stack);
Some(&positioned_kid.clip_rect))
}
}
// 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,
self.opacity)
paint_context.draw_temporary_draw_target_if_necessary(&temporary_draw_target, self.opacity)
}
/// 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 {
/// Paints this display item into the given paint context.
fn draw_into_context(&self,
paint_context: &mut PaintContext,
current_transform: &Matrix2D<AzFloat>,
current_clip_stack: &mut Vec<Rect<Au>>) {
// 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 {
/// Paints this display item into the given painting context.
fn draw_into_context(&self, paint_context: &mut PaintContext) {
let this_clip_rect = self.base().clip_rect;
if paint_context.transient_clip_rect != Some(this_clip_rect) {
if paint_context.transient_clip_rect.is_some() {
paint_context.draw_pop_clip();
drop(current_clip_stack.pop());
}
paint_context.draw_push_clip(clip_rect);
current_clip_stack.push(*clip_rect);
paint_context.draw_push_clip(&this_clip_rect);
paint_context.transient_clip_rect = Some(this_clip_rect)
}
paint_context.draw_target.set_transform(current_transform);
match *self {
SolidColorDisplayItemClass(ref solid_color) => {
paint_context.draw_solid_color(&solid_color.base.bounds, solid_color.color)
@ -585,7 +595,7 @@ impl DisplayItem {
TextDisplayItemClass(ref text) => {
debug!("Drawing text at {}.", text.base.bounds);
paint_context.draw_text(&**text, current_transform);
paint_context.draw_text(&**text);
}
ImageDisplayItemClass(ref image_item) => {

View file

@ -40,6 +40,10 @@ pub struct PaintContext<'a> {
pub page_rect: Rect<f32>,
/// The rectangle that this context encompasses in screen coordinates (pixels).
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 {
@ -130,11 +134,11 @@ impl<'a> PaintContext<'a> {
size,
stride as i32,
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));
let dest_rect = bounds.to_azure_rect();
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,
dest_rect,
source_rect,
@ -628,9 +632,9 @@ impl<'a> PaintContext<'a> {
self.draw_border_path(&original_bounds, direction, border, radius, scaled_color);
}
pub fn draw_text(&mut self,
text: &TextDisplayItem,
current_transform: &Matrix2D<AzFloat>) {
pub fn draw_text(&mut self, text: &TextDisplayItem) {
let current_transform = self.draw_target.get_transform();
// Optimization: Dont set a transform matrix for upright text, and pass a start point to
// `draw_text_into_context`.
//
@ -669,7 +673,7 @@ impl<'a> PaintContext<'a> {
// Undo the transform, only when we did one.
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,
page_rect: tile.page_rect,
screen_rect: tile.screen_rect,
transient_clip_rect: None,
};
// 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,
-tile_bounds.origin.y as AzFloat);
paint_context.draw_target.set_transform(&matrix);
// Clear the buffer.
paint_context.clear();
// Draw the display list.
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,
&tile.page_rect,
&matrix,
&mut clip_stack);
None);
paint_context.draw_target.flush();
});
}

View file

@ -25,7 +25,7 @@ dependencies = [
[[package]]
name = "azure"
version = "0.1.0"
source = "git+https://github.com/servo/rust-azure#d323c3c7c248d3d5a2d46a6a5ee61c6e92aec0b0"
source = "git+https://github.com/servo/rust-azure#452939480f5ef7640714f16c6a9e5d02e0e2d147"
dependencies = [
"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)",
@ -34,7 +34,7 @@ dependencies = [
"freetype 0.1.0 (git+https://github.com/servo/rust-freetype)",
"geom 0.1.0 (git+https://github.com/servo/rust-geom)",
"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)",
]
@ -600,7 +600,7 @@ source = "git+https://github.com/rust-lang/semver#7dca047a9cd40e929a4545b37a1917
[[package]]
name = "skia-sys"
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 = [
"expat-sys 2.1.0 (git+https://github.com/servo/libexpat)",
"freetype-sys 2.4.11 (git+https://github.com/servo/libfreetype2)",