Chromium Code Reviews| Index: cc/playback/raster_source.cc |
| diff --git a/cc/playback/raster_source.cc b/cc/playback/raster_source.cc |
| index 292d92512f134ed6054ae4d1664256b0c82f56fd..d464779c3fef57ee577b1e2c3df8783826dea5dd 100644 |
| --- a/cc/playback/raster_source.cc |
| +++ b/cc/playback/raster_source.cc |
| @@ -14,6 +14,7 @@ |
| #include "cc/playback/skip_image_canvas.h" |
| #include "skia/ext/analysis_canvas.h" |
| #include "third_party/skia/include/core/SkCanvas.h" |
| +#include "third_party/skia/include/core/SkClipStack.h" |
| #include "third_party/skia/include/core/SkPictureRecorder.h" |
| #include "ui/gfx/geometry/rect_conversions.h" |
| @@ -68,155 +69,142 @@ void RasterSource::PlaybackToCanvas(SkCanvas* raster_canvas, |
| const gfx::Rect& canvas_playback_rect, |
| float contents_scale, |
| const PlaybackSettings& settings) const { |
| - if (!settings.playback_to_shared_canvas) { |
| - PrepareForPlaybackToCanvas(raster_canvas, canvas_bitmap_rect, |
| - canvas_playback_rect, contents_scale); |
| - } |
| + SkIRect raster_bounds = gfx::RectToSkIRect(canvas_bitmap_rect); |
|
ajuma
2016/06/23 17:57:37
Is it worth intersecting this with size_?
trchen
2016/06/23 22:18:24
(I assume you meant interest_rect as in PrepareFor
|
| + if (!canvas_playback_rect.IsEmpty() && |
| + !raster_bounds.intersect(gfx::RectToSkIRect(canvas_playback_rect))) |
| + return; |
| + |
| + raster_canvas->save(); |
| + raster_canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y()); |
| + raster_canvas->clipRect(SkRect::MakeFromIRect(raster_bounds)); |
| + raster_canvas->scale(contents_scale, contents_scale); |
| + PlaybackToCanvas(raster_canvas, settings); |
| + raster_canvas->restore(); |
| +} |
| + |
| +void RasterSource::PlaybackToCanvas(SkCanvas* raster_canvas, |
| + const PlaybackSettings& settings) const { |
| + if (!settings.playback_to_shared_canvas) |
| + PrepareForPlaybackToCanvas(raster_canvas); |
| if (settings.skip_images) { |
| SkipImageCanvas canvas(raster_canvas); |
| - RasterCommon(&canvas, nullptr, canvas_bitmap_rect, canvas_playback_rect, |
| - contents_scale); |
| + RasterCommon(&canvas, nullptr); |
| } else if (settings.use_image_hijack_canvas) { |
| const SkImageInfo& info = raster_canvas->imageInfo(); |
| ImageHijackCanvas canvas(info.width(), info.height(), |
| image_decode_controller_); |
| // Before adding the canvas, make sure that the ImageHijackCanvas is aware |
| - // of the current transform, which may affect the clip bounds. Since we |
| - // query the clip bounds of the current canvas to get the list of draw |
| - // commands to process, this is important to produce correct content. |
| + // of the current transform and clip, which may affect the clip bounds. |
| + // Since we query the clip bounds of the current canvas to get the list of |
| + // draw commands to process, this is important to produce correct content. |
| + SkIRect raster_bounds; |
| + raster_canvas->getClipDeviceBounds(&raster_bounds); |
| + canvas.clipRect(SkRect::MakeFromIRect(raster_bounds)); |
| canvas.setMatrix(raster_canvas->getTotalMatrix()); |
| canvas.addCanvas(raster_canvas); |
| - RasterCommon(&canvas, nullptr, canvas_bitmap_rect, canvas_playback_rect, |
| - contents_scale); |
| + RasterCommon(&canvas, nullptr); |
| } else { |
| - RasterCommon(raster_canvas, nullptr, canvas_bitmap_rect, |
| - canvas_playback_rect, contents_scale); |
| + RasterCommon(raster_canvas, nullptr); |
| } |
| } |
| -void RasterSource::PrepareForPlaybackToCanvas( |
| - SkCanvas* canvas, |
| - const gfx::Rect& canvas_bitmap_rect, |
| - const gfx::Rect& canvas_playback_rect, |
| - float contents_scale) const { |
| +void RasterSource::PrepareForPlaybackToCanvas(SkCanvas* canvas) const { |
| // TODO(hendrikw): See if we can split this up into separate functions. |
| - bool partial_update = canvas_bitmap_rect != canvas_playback_rect; |
| - if (!partial_update) |
| + if (canvas->getClipStack()->quickContains( |
| + SkRect::MakeFromIRect(canvas->imageInfo().bounds()))) { |
| canvas->discard(); |
| - if (clear_canvas_with_debug_color_) { |
| - // Any non-painted areas in the content bounds will be left in this color. |
| - if (!partial_update) { |
| - canvas->clear(DebugColors::NonPaintedFillColor()); |
| - } else { |
| - canvas->save(); |
| - canvas->clipRect(gfx::RectToSkRect( |
| - canvas_playback_rect - canvas_bitmap_rect.OffsetFromOrigin())); |
| - canvas->drawColor(DebugColors::NonPaintedFillColor()); |
| - canvas->restore(); |
| - } |
| } |
| // If this raster source has opaque contents, it is guaranteeing that it will |
| // draw an opaque rect the size of the layer. If it is not, then we must |
| // clear this canvas ourselves. |
| if (requires_clear_) { |
| - TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD); |
| - // Clearing is about ~4x faster than drawing a rect even if the content |
| - // isn't covering a majority of the canvas. |
| - if (!partial_update) { |
| - canvas->clear(SK_ColorTRANSPARENT); |
| - } else { |
| - canvas->save(); |
| - canvas->clipRect(gfx::RectToSkRect( |
| - canvas_playback_rect - canvas_bitmap_rect.OffsetFromOrigin())); |
| - canvas->drawColor(SK_ColorTRANSPARENT, SkXfermode::kClear_Mode); |
| - canvas->restore(); |
| - } |
| - } else { |
| - // Even if completely covered, for rasterizations that touch the edge of the |
| - // layer, we also need to raster the background color underneath the last |
| - // texel (since the recording won't cover it) and outside the last texel |
| - // (due to linear filtering when using this texture). |
| - gfx::Rect content_rect = |
| - gfx::ScaleToEnclosingRect(gfx::Rect(size_), contents_scale); |
| - |
| - // The final texel of content may only be partially covered by a |
| - // rasterization; this rect represents the content rect that is fully |
| - // covered by content. |
| - gfx::Rect deflated_content_rect = content_rect; |
| - deflated_content_rect.Inset(0, 0, 1, 1); |
| - deflated_content_rect.Intersect(canvas_playback_rect); |
| - if (!deflated_content_rect.Contains(canvas_playback_rect)) { |
| - if (clear_canvas_with_debug_color_) { |
| - // Any non-painted areas outside of the content bounds are left in |
| - // this color. If this is seen then it means that cc neglected to |
| - // rerasterize a tile that used to intersect with the content rect |
| - // after the content bounds grew. |
| - canvas->save(); |
| - canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y()); |
| - canvas->clipRect(gfx::RectToSkRect(content_rect), |
| - SkRegion::kDifference_Op); |
| - canvas->drawColor(DebugColors::MissingResizeInvalidations(), |
| - SkXfermode::kSrc_Mode); |
| - canvas->restore(); |
| - } |
| - |
| - // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X |
| - // faster than clearing, so special case this. |
| - canvas->save(); |
| - canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y()); |
| - gfx::Rect inflated_content_rect = content_rect; |
| - // Only clear edges that will be inside the canvas_playback_rect, else we |
| - // clear things that are still valid from a previous raster. |
| - inflated_content_rect.Inset(0, 0, -1, -1); |
| - inflated_content_rect.Intersect(canvas_playback_rect); |
| - canvas->clipRect(gfx::RectToSkRect(inflated_content_rect), |
| - SkRegion::kReplace_Op); |
| - canvas->clipRect(gfx::RectToSkRect(deflated_content_rect), |
| - SkRegion::kDifference_Op); |
| - canvas->drawColor(background_color_, SkXfermode::kSrc_Mode); |
| - canvas->restore(); |
| - } |
| + canvas->clear(SK_ColorTRANSPARENT); |
| + return; |
| } |
| -} |
| -void RasterSource::RasterCommon(SkCanvas* canvas, |
| - SkPicture::AbortCallback* callback, |
| - const gfx::Rect& canvas_bitmap_rect, |
| - const gfx::Rect& canvas_playback_rect, |
| - float contents_scale) const { |
| - canvas->translate(-canvas_bitmap_rect.x(), -canvas_bitmap_rect.y()); |
| - gfx::Rect content_rect = |
| - gfx::ScaleToEnclosingRect(gfx::Rect(size_), contents_scale); |
| - content_rect.Intersect(canvas_playback_rect); |
| + if (clear_canvas_with_debug_color_) |
| + canvas->clear(DebugColors::NonPaintedFillColor()); |
| + |
| + // If the canvas wants us to raster with complex transform, it is hard to |
| + // determine the exact region we must clear. Just clear everything. |
| + // TODO(trchen): Optimize the common case that transformed content bounds |
| + // covers the whole clip region. |
| + if (!canvas->getTotalMatrix().rectStaysRect()) { |
| + canvas->clear(SK_ColorTRANSPARENT); |
| + return; |
| + } |
| - canvas->clipRect(gfx::RectToSkRect(content_rect), SkRegion::kIntersect_Op); |
| + SkRect content_device_rect; |
| + canvas->getTotalMatrix().mapRect( |
| + &content_device_rect, SkRect::MakeWH(size_.width(), size_.height())); |
| + // The final texel of content may only be partially covered by a |
| + // rasterization; this rect represents the content rect that is fully |
| + // covered by content. |
| + SkIRect opaque_rect; |
| + content_device_rect.roundIn(&opaque_rect); |
| + |
| + SkIRect raster_bounds; |
| + canvas->getClipDeviceBounds(&raster_bounds); |
| + |
| + if (opaque_rect.contains(raster_bounds)) |
| + return; |
| + |
| + // Even if completely covered, for rasterizations that touch the edge of the |
| + // layer, we also need to raster the background color underneath the last |
| + // texel (since the recording won't cover it) and outside the last texel |
| + // (due to linear filtering when using this texture). |
| + SkIRect interest_rect; |
| + content_device_rect.roundOut(&interest_rect); |
| + interest_rect.outset(1, 1); |
| + |
| + if (clear_canvas_with_debug_color_) { |
| + // Any non-painted areas outside of the content bounds are left in |
| + // this color. If this is seen then it means that cc neglected to |
| + // rerasterize a tile that used to intersect with the content rect |
| + // after the content bounds grew. |
| + canvas->save(); |
| + // Use clipRegion to bypass CTM because the rects are device rects. |
| + SkRegion interest_region; |
| + interest_region.setRect(interest_rect); |
| + canvas->clipRegion(interest_region, SkRegion::kDifference_Op); |
| + canvas->clear(DebugColors::MissingResizeInvalidations()); |
| + canvas->restore(); |
| + } |
| + |
| + // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X |
|
enne (OOO)
2016/08/29 20:22:52
This comment seems no longer true.
|
| + // faster than clearing, so special case this. |
| + canvas->save(); |
| + // Use clipRegion to bypass CTM because the rects are device rects. |
| + SkRegion interest_region; |
| + interest_region.setRect(interest_rect); |
| + interest_region.op(opaque_rect, SkRegion::kDifference_Op); |
| + canvas->clipRegion(interest_region); |
| + canvas->clear(background_color_); |
| + canvas->restore(); |
| +} |
| + |
| +void RasterSource::RasterCommon(SkCanvas* canvas, |
| + SkPicture::AbortCallback* callback) const { |
| DCHECK(display_list_.get()); |
| - gfx::Rect canvas_target_playback_rect = |
| - canvas_playback_rect - canvas_bitmap_rect.OffsetFromOrigin(); |
| int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); |
| - for (int i = 0; i < repeat_count; ++i) { |
| - display_list_->Raster(canvas, callback, canvas_target_playback_rect, |
| - contents_scale); |
| - } |
| + for (int i = 0; i < repeat_count; ++i) |
| + display_list_->Raster(canvas, callback); |
| } |
| sk_sp<SkPicture> RasterSource::GetFlattenedPicture() { |
| TRACE_EVENT0("cc", "RasterSource::GetFlattenedPicture"); |
| - gfx::Rect display_list_rect(size_); |
| SkPictureRecorder recorder; |
| - SkCanvas* canvas = recorder.beginRecording(display_list_rect.width(), |
| - display_list_rect.height()); |
| - if (!display_list_rect.IsEmpty()) { |
| - PrepareForPlaybackToCanvas(canvas, display_list_rect, display_list_rect, |
| - 1.f); |
| - RasterCommon(canvas, nullptr, display_list_rect, display_list_rect, 1.f); |
| + SkCanvas* canvas = recorder.beginRecording(size_.width(), size_.height()); |
| + if (!size_.IsEmpty()) { |
| + PrepareForPlaybackToCanvas(canvas); |
| + RasterCommon(canvas, nullptr); |
| } |
| return recorder.finishRecordingAsPicture(); |
| @@ -239,7 +227,8 @@ bool RasterSource::PerformSolidColorAnalysis(const gfx::Rect& content_rect, |
| layer_rect.Intersect(gfx::Rect(size_)); |
| skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height()); |
| - RasterCommon(&canvas, &canvas, layer_rect, layer_rect, 1.0f); |
| + canvas.translate(-layer_rect.x(), -layer_rect.y()); |
| + RasterCommon(&canvas, &canvas); |
| return canvas.GetColorIfSolid(color); |
| } |