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