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); |
} |