1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Copyright 2012 The Chromium Authors. All rights reserved. 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// Use of this source code is governed by a BSD-style license that can be 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com// found in the LICENSE file. 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include <algorithm> 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com#include <limits> 76806fe87e0b39e283291c1a1c7d1d864230aa2aatfarina@chromium.org 88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "base/debug/trace_event.h" 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "cc/base/region.h" 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "cc/debug/debug_colors.h" 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "cc/resources/picture_pile_impl.h" 125da3f220034f89f3234b16b98bd86e7246941ffecommit-bot@chromium.org#include "skia/ext/analysis_canvas.h" 135da3f220034f89f3234b16b98bd86e7246941ffecommit-bot@chromium.org#include "third_party/skia/include/core/SkCanvas.h" 140716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com#include "third_party/skia/include/core/SkPictureRecorder.h" 158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "third_party/skia/include/core/SkSize.h" 168c3ff17e2cab6f7c798b9f8ff4515c4a3d3fd9d1bsalomon@google.com#include "ui/gfx/rect_conversions.h" 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "ui/gfx/size_conversions.h" 180456e0b7b85060e9b9597ce414c4c2b19aff4f58robertphillips@google.com#include "ui/gfx/skia_util.h" 190456e0b7b85060e9b9597ce414c4c2b19aff4f58robertphillips@google.com 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comnamespace cc { 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 220e2810be95d3f1aa95c341521d3f514eb9e9ebdemike@reedtribe.orgscoped_refptr<PicturePileImpl> PicturePileImpl::Create() { 230716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com return make_scoped_refptr(new PicturePileImpl); 240716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com} 250716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com 260716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.comscoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther( 278426058dee0faf75a18b81cfcde47ee8ab8c31d9reed@google.com const PicturePileBase* other) { 288426058dee0faf75a18b81cfcde47ee8ab8c31d9reed@google.com return make_scoped_refptr(new PicturePileImpl(other)); 290716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com} 300e2810be95d3f1aa95c341521d3f514eb9e9ebdemike@reedtribe.org 310716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.comPicturePileImpl::PicturePileImpl() { 320716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com} 330716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com 340716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.comPicturePileImpl::PicturePileImpl(const PicturePileBase* other) 350716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com : PicturePileBase(other) { 360716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com} 370716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com 38fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.comPicturePileImpl::~PicturePileImpl() { 398426058dee0faf75a18b81cfcde47ee8ab8c31d9reed@google.com} 408426058dee0faf75a18b81cfcde47ee8ab8c31d9reed@google.com 418426058dee0faf75a18b81cfcde47ee8ab8c31d9reed@google.comvoid PicturePileImpl::RasterDirect( 428426058dee0faf75a18b81cfcde47ee8ab8c31d9reed@google.com SkCanvas* canvas, 438426058dee0faf75a18b81cfcde47ee8ab8c31d9reed@google.com const gfx::Rect& canvas_rect, 448426058dee0faf75a18b81cfcde47ee8ab8c31d9reed@google.com float contents_scale, 458426058dee0faf75a18b81cfcde47ee8ab8c31d9reed@google.com RenderingStatsInstrumentation* rendering_stats_instrumentation) { 461f90287df3129cb267422e482c52ebeca6a8990ftomhudson@google.com RasterCommon(canvas, 47fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com NULL, 480e2810be95d3f1aa95c341521d3f514eb9e9ebdemike@reedtribe.org canvas_rect, 490e2810be95d3f1aa95c341521d3f514eb9e9ebdemike@reedtribe.org contents_scale, 500716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com rendering_stats_instrumentation, 510716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com false); 520716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com} 530716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com 54a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.orgvoid PicturePileImpl::RasterForAnalysis( 55a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org skia::AnalysisCanvas* canvas, 56a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org const gfx::Rect& canvas_rect, 57a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org float contents_scale, 58a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org RenderingStatsInstrumentation* stats_instrumentation) const { 59a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org RasterCommon( 600716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com canvas, canvas, canvas_rect, contents_scale, stats_instrumentation, true); 610716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com} 620716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com 630716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.comvoid PicturePileImpl::RasterToBitmap( 640716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com SkCanvas* canvas, 650716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com const gfx::Rect& canvas_rect, 660716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com float contents_scale, 670716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com RenderingStatsInstrumentation* rendering_stats_instrumentation) const { 688c3ff17e2cab6f7c798b9f8ff4515c4a3d3fd9d1bsalomon@google.com canvas->discard(); 69a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org if (clear_canvas_with_debug_color_) { 700716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com // Any non-painted areas in the content bounds will be left in this color. 710716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com canvas->clear(DebugColors::NonPaintedFillColor()); 720716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com } 730716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com 740716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com // If this picture has opaque contents, it is guaranteeing that it will 750716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com // draw an opaque rect the size of the layer. If it is not, then we must 760716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com // clear this canvas ourselves. 770716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com if (contents_opaque_ || contents_fill_bounds_completely_) { 780716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com // Even if completely covered, for rasterizations that touch the edge of the 790716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com // layer, we also need to raster the background color underneath the last 800716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com // texel (since the recording won't cover it) and outside the last texel 810716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com // (due to linear filtering when using this texture). 820716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com gfx::Rect content_tiling_rect = gfx::ToEnclosingRect( 830716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale)); 840716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com 850e2810be95d3f1aa95c341521d3f514eb9e9ebdemike@reedtribe.org // The final texel of content may only be partially covered by a 860e2810be95d3f1aa95c341521d3f514eb9e9ebdemike@reedtribe.org // rasterization; this rect represents the content rect that is fully 870e2810be95d3f1aa95c341521d3f514eb9e9ebdemike@reedtribe.org // covered by content. 88a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org gfx::Rect deflated_content_tiling_rect = content_tiling_rect; 890716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com deflated_content_tiling_rect.Inset(0, 0, 1, 1); 900716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com if (!deflated_content_tiling_rect.Contains(canvas_rect)) { 910716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com if (clear_canvas_with_debug_color_) { 920716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com // Any non-painted areas outside of the content bounds are left in 934991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com // this color. If this is seen then it means that cc neglected to 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // rerasterize a tile that used to intersect with the content rect 95a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org // after the content bounds grew. 96fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com canvas->save(); 970e2810be95d3f1aa95c341521d3f514eb9e9ebdemike@reedtribe.org canvas->translate(-canvas_rect.x(), -canvas_rect.y()); 98a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org canvas->clipRect(gfx::RectToSkRect(content_tiling_rect), 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkRegion::kDifference_Op); 100a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org canvas->drawColor(DebugColors::MissingResizeInvalidations(), 101fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com SkXfermode::kSrc_Mode); 1028f838259ab65e44562902679fa88cb00575b99cecommit-bot@chromium.org canvas->restore(); 1038f838259ab65e44562902679fa88cb00575b99cecommit-bot@chromium.org } 1048f838259ab65e44562902679fa88cb00575b99cecommit-bot@chromium.org 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X 1064e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com // faster than clearing, so special case this. 1074e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com canvas->save(); 1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com canvas->translate(-canvas_rect.x(), -canvas_rect.y()); 1094991b8f23482afc1494fd17647421ce68de53331robertphillips@google.com gfx::Rect inflated_content_tiling_rect = content_tiling_rect; 11074ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org inflated_content_tiling_rect.Inset(0, 0, -1, -1); 11174ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org canvas->clipRect(gfx::RectToSkRect(inflated_content_tiling_rect), 11274ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org SkRegion::kReplace_Op); 11374ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org canvas->clipRect(gfx::RectToSkRect(deflated_content_tiling_rect), 114fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com SkRegion::kDifference_Op); 1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com canvas->drawColor(background_color_, SkXfermode::kSrc_Mode); 1168b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org canvas->restore(); 117fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com } 1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } else { 1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD); 1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Clearing is about ~4x faster than drawing a rect even if the content 1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // isn't covering a majority of the canvas. 1220716c63332a64c3cc77a9afb87ae2fd9614f0c4freed@google.com canvas->clear(SK_ColorTRANSPARENT); 1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1258f838259ab65e44562902679fa88cb00575b99cecommit-bot@chromium.org RasterCommon(canvas, 1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com NULL, 1274e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com canvas_rect, 1284e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com contents_scale, 1294e2b3d3fb1288c6dc0f3ea1c0aa4a0d7c603bd7breed@google.com rendering_stats_instrumentation, 1300e2810be95d3f1aa95c341521d3f514eb9e9ebdemike@reedtribe.org false); 131a8282ef8f9e63e60c5665af0cdfc8fdd11c089f6mike@reedtribe.org} 1320e2810be95d3f1aa95c341521d3f514eb9e9ebdemike@reedtribe.org 1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect, 1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const gfx::Rect& content_rect, 1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com float contents_scale, 1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com PictureRegionMap* results) const { 137fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com DCHECK(results); 1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // Rasterize the collection of relevant picture piles. 13974ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( 14074ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org content_rect, 1.f / contents_scale); 14174ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org 14274ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // Make sure pictures don't overlap by keeping track of previous right/bottom. 14374ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org int min_content_left = -1; 14474ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org int min_content_top = -1; 14574ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org int last_row_index = -1; 14674ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org int last_col_index = -1; 14774ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org gfx::Rect last_content_rect; 14874ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org 14974ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // Coalesce rasters of the same picture into different rects: 15074ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // - Compute the clip of each of the pile chunks, 15174ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // - Subtract it from the canvas rect to get difference region 15274ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // - Later, use the difference region to subtract each of the comprising 15374ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // rects from the canvas. 15474ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // Note that in essence, we're trying to mimic clipRegion with intersect op 15574ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // that also respects the current canvas transform and clip. In order to use 15674ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // the canvas transform, we must stick to clipRect operations (clipRegion 15774ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // ignores the transform). Intersect then can be written as subtracting the 15874ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // negation of the region we're trying to intersect. Luckily, we know that all 15974ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // of the rects will have to fit into |content_rect|, so we can start with 16074ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // that and subtract chunk rects to get the region that we need to subtract 16174ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // from the canvas. Then, we can use clipRect with difference op to subtract 16274ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // each rect in the region. 16374ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org bool include_borders = true; 16474ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); 16574ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org tile_iter; 16674ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org ++tile_iter) { 16774ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); 16874ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org if (map_iter == picture_map_.end()) 16974ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org continue; 17074ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org const PictureInfo& info = map_iter->second; 17174ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org const Picture* picture = info.GetPicture(); 17274ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org if (!picture) 17374ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org continue; 17474ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org 17574ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // This is intentionally *enclosed* rect, so that the clip is aligned on 17674ba2f62dce1998bd6555291ab0a5330c276301dcommit-bot@chromium.org // integral post-scale content pixels and does not extend past the edges 1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // of the picture chunk's layer rect. The min_contents_scale enforces that 1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // enough buffer pixels have been added such that the enclosed rect 1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com // encompasses all invalidated pixels at any larger scale level. 180 gfx::Rect chunk_rect = PaddedRect(tile_iter.index()); 181 gfx::Rect content_clip = 182 gfx::ScaleToEnclosedRect(chunk_rect, contents_scale); 183 DCHECK(!content_clip.IsEmpty()) << "Layer rect: " 184 << picture->LayerRect().ToString() 185 << "Contents scale: " << contents_scale; 186 content_clip.Intersect(canvas_rect); 187 188 // Make sure iterator goes top->bottom. 189 DCHECK_GE(tile_iter.index_y(), last_row_index); 190 if (tile_iter.index_y() > last_row_index) { 191 // First tile in a new row. 192 min_content_left = content_clip.x(); 193 min_content_top = last_content_rect.bottom(); 194 } else { 195 // Make sure iterator goes left->right. 196 DCHECK_GT(tile_iter.index_x(), last_col_index); 197 min_content_left = last_content_rect.right(); 198 min_content_top = last_content_rect.y(); 199 } 200 201 last_col_index = tile_iter.index_x(); 202 last_row_index = tile_iter.index_y(); 203 204 // Only inset if the content_clip is less than then previous min. 205 int inset_left = std::max(0, min_content_left - content_clip.x()); 206 int inset_top = std::max(0, min_content_top - content_clip.y()); 207 content_clip.Inset(inset_left, inset_top, 0, 0); 208 209 PictureRegionMap::iterator it = results->find(picture); 210 Region* clip_region; 211 if (it == results->end()) { 212 // The clip for a set of coalesced pictures starts out clipping the entire 213 // canvas. Each picture added to the set must subtract its own bounds 214 // from the clip region, poking a hole so that the picture is unclipped. 215 clip_region = &(*results)[picture]; 216 *clip_region = canvas_rect; 217 } else { 218 clip_region = &it->second; 219 } 220 221 DCHECK(clip_region->Contains(content_clip)) 222 << "Content clips should not overlap."; 223 clip_region->Subtract(content_clip); 224 last_content_rect = content_clip; 225 } 226} 227 228void PicturePileImpl::RasterCommon( 229 SkCanvas* canvas, 230 SkDrawPictureCallback* callback, 231 const gfx::Rect& canvas_rect, 232 float contents_scale, 233 RenderingStatsInstrumentation* rendering_stats_instrumentation, 234 bool is_analysis) const { 235 DCHECK(contents_scale >= min_contents_scale_); 236 237 canvas->translate(-canvas_rect.x(), -canvas_rect.y()); 238 gfx::Rect content_tiling_rect = gfx::ToEnclosingRect( 239 gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale)); 240 content_tiling_rect.Intersect(canvas_rect); 241 242 canvas->clipRect(gfx::RectToSkRect(content_tiling_rect), 243 SkRegion::kIntersect_Op); 244 245 PictureRegionMap picture_region_map; 246 CoalesceRasters( 247 canvas_rect, content_tiling_rect, contents_scale, &picture_region_map); 248 249#ifndef NDEBUG 250 Region total_clip; 251#endif // NDEBUG 252 253 // Iterate the coalesced map and use each picture's region 254 // to clip the canvas. 255 for (PictureRegionMap::iterator it = picture_region_map.begin(); 256 it != picture_region_map.end(); 257 ++it) { 258 const Picture* picture = it->first; 259 Region negated_clip_region = it->second; 260 261#ifndef NDEBUG 262 Region positive_clip = content_tiling_rect; 263 positive_clip.Subtract(negated_clip_region); 264 // Make sure we never rasterize the same region twice. 265 DCHECK(!total_clip.Intersects(positive_clip)); 266 total_clip.Union(positive_clip); 267#endif // NDEBUG 268 269 base::TimeDelta best_duration = base::TimeDelta::Max(); 270 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); 271 int rasterized_pixel_count = 0; 272 273 for (int j = 0; j < repeat_count; ++j) { 274 base::TimeTicks start_time; 275 if (rendering_stats_instrumentation) 276 start_time = rendering_stats_instrumentation->StartRecording(); 277 278 rasterized_pixel_count = picture->Raster( 279 canvas, callback, negated_clip_region, contents_scale); 280 281 if (rendering_stats_instrumentation) { 282 base::TimeDelta duration = 283 rendering_stats_instrumentation->EndRecording(start_time); 284 best_duration = std::min(best_duration, duration); 285 } 286 } 287 288 if (rendering_stats_instrumentation) { 289 if (is_analysis) { 290 rendering_stats_instrumentation->AddAnalysis(best_duration, 291 rasterized_pixel_count); 292 } else { 293 rendering_stats_instrumentation->AddRaster(best_duration, 294 rasterized_pixel_count); 295 } 296 } 297 } 298 299#ifndef NDEBUG 300 // Fill the clip with debug color. This allows us to 301 // distinguish between non painted areas and problems with missing 302 // pictures. 303 SkPaint paint; 304 for (Region::Iterator it(total_clip); it.has_rect(); it.next()) 305 canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op); 306 paint.setColor(DebugColors::MissingPictureFillColor()); 307 paint.setXfermodeMode(SkXfermode::kSrc_Mode); 308 canvas->drawPaint(paint); 309#endif // NDEBUG 310} 311 312skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() { 313 TRACE_EVENT0("cc", "PicturePileImpl::GetFlattenedPicture"); 314 315 gfx::Rect tiling_rect(tiling_.tiling_size()); 316 SkPictureRecorder recorder; 317 SkCanvas* canvas = 318 recorder.beginRecording(tiling_rect.width(), tiling_rect.height()); 319 if (!tiling_rect.IsEmpty()) 320 RasterToBitmap(canvas, tiling_rect, 1.0, NULL); 321 skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording()); 322 323 return picture; 324} 325 326void PicturePileImpl::AnalyzeInRect(const gfx::Rect& content_rect, 327 float contents_scale, 328 PicturePileImpl::Analysis* analysis) const { 329 AnalyzeInRect(content_rect, contents_scale, analysis, NULL); 330} 331 332void PicturePileImpl::AnalyzeInRect( 333 const gfx::Rect& content_rect, 334 float contents_scale, 335 PicturePileImpl::Analysis* analysis, 336 RenderingStatsInstrumentation* stats_instrumentation) const { 337 DCHECK(analysis); 338 TRACE_EVENT0("cc", "PicturePileImpl::AnalyzeInRect"); 339 340 gfx::Rect layer_rect = gfx::ScaleToEnclosingRect( 341 content_rect, 1.0f / contents_scale); 342 343 layer_rect.Intersect(gfx::Rect(tiling_.tiling_size())); 344 345 skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height()); 346 347 RasterForAnalysis(&canvas, layer_rect, 1.0f, stats_instrumentation); 348 349 analysis->is_solid_color = canvas.GetColorIfSolid(&analysis->solid_color); 350} 351 352// Since there are situations when we can skip analysis, the variables have to 353// be set to their safest values. That is, we have to assume that the tile is 354// not solid color. As well, we have to assume that the tile has text so we 355// don't early out incorrectly. 356PicturePileImpl::Analysis::Analysis() : is_solid_color(false) { 357} 358 359PicturePileImpl::Analysis::~Analysis() { 360} 361 362PicturePileImpl::PixelRefIterator::PixelRefIterator( 363 const gfx::Rect& content_rect, 364 float contents_scale, 365 const PicturePileImpl* picture_pile) 366 : picture_pile_(picture_pile), 367 layer_rect_( 368 gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale)), 369 tile_iterator_(&picture_pile_->tiling_, 370 layer_rect_, 371 false /* include_borders */) { 372 // Early out if there isn't a single tile. 373 if (!tile_iterator_) 374 return; 375 376 AdvanceToTilePictureWithPixelRefs(); 377} 378 379PicturePileImpl::PixelRefIterator::~PixelRefIterator() { 380} 381 382PicturePileImpl::PixelRefIterator& 383 PicturePileImpl::PixelRefIterator::operator++() { 384 ++pixel_ref_iterator_; 385 if (pixel_ref_iterator_) 386 return *this; 387 388 ++tile_iterator_; 389 AdvanceToTilePictureWithPixelRefs(); 390 return *this; 391} 392 393void PicturePileImpl::PixelRefIterator::AdvanceToTilePictureWithPixelRefs() { 394 for (; tile_iterator_; ++tile_iterator_) { 395 PictureMap::const_iterator it = 396 picture_pile_->picture_map_.find(tile_iterator_.index()); 397 if (it == picture_pile_->picture_map_.end()) 398 continue; 399 400 const Picture* picture = it->second.GetPicture(); 401 if (!picture || (processed_pictures_.count(picture) != 0) || 402 !picture->WillPlayBackBitmaps()) 403 continue; 404 405 processed_pictures_.insert(picture); 406 pixel_ref_iterator_ = Picture::PixelRefIterator(layer_rect_, picture); 407 if (pixel_ref_iterator_) 408 break; 409 } 410} 411 412void PicturePileImpl::DidBeginTracing() { 413 std::set<const void*> processed_pictures; 414 for (PictureMap::iterator it = picture_map_.begin(); 415 it != picture_map_.end(); 416 ++it) { 417 const Picture* picture = it->second.GetPicture(); 418 if (picture && (processed_pictures.count(picture) == 0)) { 419 picture->EmitTraceSnapshot(); 420 processed_pictures.insert(picture); 421 } 422 } 423} 424 425} // namespace cc 426