Delete chrome.mediaGalleriesPrivate because the functionality unique to it has since...
[chromium-blink-merge.git] / cc / resources / picture.cc
blobb1ca99d7a0cdb81bfc1d5668f9e6760619347e1c
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/resources/picture.h"
7 #include <algorithm>
8 #include <limits>
9 #include <set>
11 #include "base/base64.h"
12 #include "base/debug/trace_event.h"
13 #include "base/debug/trace_event_argument.h"
14 #include "base/values.h"
15 #include "cc/base/math_util.h"
16 #include "cc/base/util.h"
17 #include "cc/debug/picture_debug_util.h"
18 #include "cc/debug/traced_picture.h"
19 #include "cc/debug/traced_value.h"
20 #include "cc/layers/content_layer_client.h"
21 #include "skia/ext/pixel_ref_utils.h"
22 #include "third_party/skia/include/core/SkCanvas.h"
23 #include "third_party/skia/include/core/SkDrawPictureCallback.h"
24 #include "third_party/skia/include/core/SkPaint.h"
25 #include "third_party/skia/include/core/SkPictureRecorder.h"
26 #include "third_party/skia/include/core/SkStream.h"
27 #include "third_party/skia/include/utils/SkNullCanvas.h"
28 #include "third_party/skia/include/utils/SkPictureUtils.h"
29 #include "ui/gfx/codec/jpeg_codec.h"
30 #include "ui/gfx/codec/png_codec.h"
31 #include "ui/gfx/geometry/rect_conversions.h"
32 #include "ui/gfx/skia_util.h"
34 namespace cc {
36 namespace {
38 bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
39 const unsigned char* data = static_cast<const unsigned char *>(buffer);
41 // Try PNG first.
42 if (gfx::PNGCodec::Decode(data, size, bm))
43 return true;
45 // Try JPEG.
46 scoped_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodec::Decode(data, size));
47 if (decoded_jpeg) {
48 *bm = *decoded_jpeg;
49 return true;
51 return false;
54 } // namespace
56 scoped_refptr<Picture> Picture::Create(const gfx::Rect& layer_rect,
57 ContentLayerClient* client,
58 const gfx::Size& tile_grid_size,
59 bool gather_pixel_refs,
60 RecordingMode recording_mode) {
61 scoped_refptr<Picture> picture = make_scoped_refptr(new Picture(layer_rect));
63 picture->Record(client, tile_grid_size, recording_mode);
64 if (gather_pixel_refs)
65 picture->GatherPixelRefs(tile_grid_size);
67 return picture;
70 Picture::Picture(const gfx::Rect& layer_rect)
71 : layer_rect_(layer_rect),
72 cell_size_(layer_rect.size()) {
73 // Instead of recording a trace event for object creation here, we wait for
74 // the picture to be recorded in Picture::Record.
77 scoped_refptr<Picture> Picture::CreateFromSkpValue(const base::Value* value) {
78 // Decode the picture from base64.
79 std::string encoded;
80 if (!value->GetAsString(&encoded))
81 return NULL;
83 std::string decoded;
84 base::Base64Decode(encoded, &decoded);
85 SkMemoryStream stream(decoded.data(), decoded.size());
87 // Read the picture. This creates an empty picture on failure.
88 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
89 if (skpicture == NULL)
90 return NULL;
92 gfx::Rect layer_rect(gfx::SkIRectToRect(skpicture->cullRect().roundOut()));
93 return make_scoped_refptr(new Picture(skpicture, layer_rect));
96 scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
97 const base::DictionaryValue* value = NULL;
98 if (!raw_value->GetAsDictionary(&value))
99 return NULL;
101 // Decode the picture from base64.
102 std::string encoded;
103 if (!value->GetString("skp64", &encoded))
104 return NULL;
106 std::string decoded;
107 base::Base64Decode(encoded, &decoded);
108 SkMemoryStream stream(decoded.data(), decoded.size());
110 const base::Value* layer_rect_value = NULL;
111 if (!value->Get("params.layer_rect", &layer_rect_value))
112 return NULL;
114 gfx::Rect layer_rect;
115 if (!MathUtil::FromValue(layer_rect_value, &layer_rect))
116 return NULL;
118 // Read the picture. This creates an empty picture on failure.
119 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
120 if (skpicture == NULL)
121 return NULL;
123 return make_scoped_refptr(new Picture(skpicture, layer_rect));
126 Picture::Picture(SkPicture* picture, const gfx::Rect& layer_rect)
127 : layer_rect_(layer_rect),
128 picture_(skia::AdoptRef(picture)),
129 cell_size_(layer_rect.size()) {
132 Picture::Picture(const skia::RefPtr<SkPicture>& picture,
133 const gfx::Rect& layer_rect,
134 const PixelRefMap& pixel_refs) :
135 layer_rect_(layer_rect),
136 picture_(picture),
137 pixel_refs_(pixel_refs),
138 cell_size_(layer_rect.size()) {
141 Picture::~Picture() {
142 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
143 TRACE_DISABLED_BY_DEFAULT("cc.debug.picture"), "cc::Picture", this);
146 bool Picture::IsSuitableForGpuRasterization(const char** reason) const {
147 DCHECK(picture_);
149 // TODO(hendrikw): SkPicture::suitableForGpuRasterization takes a GrContext.
150 // Currently the GrContext isn't used, and should probably be removed from
151 // skia.
152 return picture_->suitableForGpuRasterization(nullptr, reason);
155 int Picture::ApproximateOpCount() const {
156 DCHECK(picture_);
157 return picture_->approximateOpCount();
160 size_t Picture::ApproximateMemoryUsage() const {
161 DCHECK(picture_);
162 return SkPictureUtils::ApproximateBytesUsed(picture_.get());
165 bool Picture::HasText() const {
166 DCHECK(picture_);
167 return picture_->hasText();
170 void Picture::Record(ContentLayerClient* painter,
171 const gfx::Size& tile_grid_size,
172 RecordingMode recording_mode) {
173 TRACE_EVENT2("cc",
174 "Picture::Record",
175 "data",
176 AsTraceableRecordData(),
177 "recording_mode",
178 recording_mode);
180 DCHECK(!picture_);
181 DCHECK(!tile_grid_size.IsEmpty());
183 // TODO(mtklein): If SkRTree sticks, clean up tile_grid_info. skbug.com/3085
184 SkRTreeFactory factory;
185 SkPictureRecorder recorder;
187 skia::RefPtr<SkCanvas> canvas;
188 canvas = skia::SharePtr(recorder.beginRecording(
189 layer_rect_.width(), layer_rect_.height(), &factory,
190 SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag));
192 ContentLayerClient::GraphicsContextStatus graphics_context_status =
193 ContentLayerClient::GRAPHICS_CONTEXT_ENABLED;
195 switch (recording_mode) {
196 case RECORD_NORMALLY:
197 // Already setup for normal recording.
198 break;
199 case RECORD_WITH_SK_NULL_CANVAS:
200 canvas = skia::AdoptRef(SkCreateNullCanvas());
201 break;
202 case RECORD_WITH_PAINTING_DISABLED:
203 // We pass a disable flag through the paint calls when perfromance
204 // testing (the only time this case should ever arise) when we want to
205 // prevent the Blink GraphicsContext object from consuming any compute
206 // time.
207 canvas = skia::AdoptRef(SkCreateNullCanvas());
208 graphics_context_status = ContentLayerClient::GRAPHICS_CONTEXT_DISABLED;
209 break;
210 default:
211 NOTREACHED();
214 canvas->save();
215 canvas->translate(SkFloatToScalar(-layer_rect_.x()),
216 SkFloatToScalar(-layer_rect_.y()));
218 SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
219 layer_rect_.y(),
220 layer_rect_.width(),
221 layer_rect_.height());
222 canvas->clipRect(layer_skrect);
224 painter->PaintContents(canvas.get(), layer_rect_, graphics_context_status);
226 canvas->restore();
227 picture_ = skia::AdoptRef(recorder.endRecording());
228 DCHECK(picture_);
230 EmitTraceSnapshot();
233 void Picture::GatherPixelRefs(const gfx::Size& tile_grid_size) {
234 TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
235 "width", layer_rect_.width(),
236 "height", layer_rect_.height());
238 DCHECK(picture_);
239 DCHECK(pixel_refs_.empty());
240 if (!WillPlayBackBitmaps())
241 return;
242 cell_size_ = tile_grid_size;
243 DCHECK_GT(cell_size_.width(), 0);
244 DCHECK_GT(cell_size_.height(), 0);
246 int min_x = std::numeric_limits<int>::max();
247 int min_y = std::numeric_limits<int>::max();
248 int max_x = 0;
249 int max_y = 0;
251 skia::DiscardablePixelRefList pixel_refs;
252 skia::PixelRefUtils::GatherDiscardablePixelRefs(picture_.get(), &pixel_refs);
253 for (skia::DiscardablePixelRefList::const_iterator it = pixel_refs.begin();
254 it != pixel_refs.end();
255 ++it) {
256 gfx::Point min(
257 RoundDown(static_cast<int>(it->pixel_ref_rect.x()),
258 cell_size_.width()),
259 RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
260 cell_size_.height()));
261 gfx::Point max(
262 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
263 cell_size_.width()),
264 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
265 cell_size_.height()));
267 for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
268 for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
269 PixelRefMapKey key(x, y);
270 pixel_refs_[key].push_back(it->pixel_ref);
274 min_x = std::min(min_x, min.x());
275 min_y = std::min(min_y, min.y());
276 max_x = std::max(max_x, max.x());
277 max_y = std::max(max_y, max.y());
280 min_pixel_cell_ = gfx::Point(min_x, min_y);
281 max_pixel_cell_ = gfx::Point(max_x, max_y);
284 int Picture::Raster(SkCanvas* canvas,
285 SkDrawPictureCallback* callback,
286 const Region& negated_content_region,
287 float contents_scale) const {
288 TRACE_EVENT_BEGIN1(
289 "cc",
290 "Picture::Raster",
291 "data",
292 AsTraceableRasterData(contents_scale));
294 DCHECK(picture_);
296 canvas->save();
298 for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
299 canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
301 canvas->scale(contents_scale, contents_scale);
302 canvas->translate(layer_rect_.x(), layer_rect_.y());
303 if (callback) {
304 // If we have a callback, we need to call |draw()|, |drawPicture()| doesn't
305 // take a callback. This is used by |AnalysisCanvas| to early out.
306 picture_->playback(canvas, callback);
307 } else {
308 // Prefer to call |drawPicture()| on the canvas since it could place the
309 // entire picture on the canvas instead of parsing the skia operations.
310 canvas->drawPicture(picture_.get());
312 SkIRect bounds;
313 canvas->getClipDeviceBounds(&bounds);
314 canvas->restore();
315 TRACE_EVENT_END1(
316 "cc", "Picture::Raster",
317 "num_pixels_rasterized", bounds.width() * bounds.height());
318 return bounds.width() * bounds.height();
321 void Picture::Replay(SkCanvas* canvas) {
322 TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
323 DCHECK(picture_);
324 picture_->playback(canvas);
325 SkIRect bounds;
326 canvas->getClipDeviceBounds(&bounds);
327 TRACE_EVENT_END1("cc", "Picture::Replay",
328 "num_pixels_replayed", bounds.width() * bounds.height());
331 scoped_ptr<base::Value> Picture::AsValue() const {
332 // Encode the picture as base64.
333 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
334 res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
335 std::string b64_picture;
336 PictureDebugUtil::SerializeAsBase64(picture_.get(), &b64_picture);
337 res->SetString("skp64", b64_picture);
338 return res.Pass();
341 void Picture::EmitTraceSnapshot() const {
342 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
343 TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") ","
344 TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"),
345 "cc::Picture",
346 this,
347 TracedPicture::AsTraceablePicture(this));
350 void Picture::EmitTraceSnapshotAlias(Picture* original) const {
351 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
352 TRACE_DISABLED_BY_DEFAULT("cc.debug.picture") ","
353 TRACE_DISABLED_BY_DEFAULT("devtools.timeline.picture"),
354 "cc::Picture",
355 this,
356 TracedPicture::AsTraceablePictureAlias(original));
359 base::LazyInstance<Picture::PixelRefs>
360 Picture::PixelRefIterator::empty_pixel_refs_;
362 Picture::PixelRefIterator::PixelRefIterator()
363 : picture_(NULL),
364 current_pixel_refs_(empty_pixel_refs_.Pointer()),
365 current_index_(0),
366 min_point_(-1, -1),
367 max_point_(-1, -1),
368 current_x_(0),
369 current_y_(0) {
372 Picture::PixelRefIterator::PixelRefIterator(
373 const gfx::Rect& rect,
374 const Picture* picture)
375 : picture_(picture),
376 current_pixel_refs_(empty_pixel_refs_.Pointer()),
377 current_index_(0) {
378 gfx::Rect layer_rect = picture->layer_rect_;
379 gfx::Size cell_size = picture->cell_size_;
380 DCHECK(!cell_size.IsEmpty());
382 gfx::Rect query_rect(rect);
383 // Early out if the query rect doesn't intersect this picture.
384 if (!query_rect.Intersects(layer_rect)) {
385 min_point_ = gfx::Point(0, 0);
386 max_point_ = gfx::Point(0, 0);
387 current_x_ = 1;
388 current_y_ = 1;
389 return;
392 // First, subtract the layer origin as cells are stored in layer space.
393 query_rect.Offset(-layer_rect.OffsetFromOrigin());
395 // We have to find a cell_size aligned point that corresponds to
396 // query_rect. Point is a multiple of cell_size.
397 min_point_ = gfx::Point(
398 RoundDown(query_rect.x(), cell_size.width()),
399 RoundDown(query_rect.y(), cell_size.height()));
400 max_point_ = gfx::Point(
401 RoundDown(query_rect.right() - 1, cell_size.width()),
402 RoundDown(query_rect.bottom() - 1, cell_size.height()));
404 // Limit the points to known pixel ref boundaries.
405 min_point_ = gfx::Point(
406 std::max(min_point_.x(), picture->min_pixel_cell_.x()),
407 std::max(min_point_.y(), picture->min_pixel_cell_.y()));
408 max_point_ = gfx::Point(
409 std::min(max_point_.x(), picture->max_pixel_cell_.x()),
410 std::min(max_point_.y(), picture->max_pixel_cell_.y()));
412 // Make the current x be cell_size.width() less than min point, so that
413 // the first increment will point at min_point_.
414 current_x_ = min_point_.x() - cell_size.width();
415 current_y_ = min_point_.y();
416 if (current_y_ <= max_point_.y())
417 ++(*this);
420 Picture::PixelRefIterator::~PixelRefIterator() {
423 Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() {
424 ++current_index_;
425 // If we're not at the end of the list, then we have the next item.
426 if (current_index_ < current_pixel_refs_->size())
427 return *this;
429 DCHECK(current_y_ <= max_point_.y());
430 while (true) {
431 gfx::Size cell_size = picture_->cell_size_;
433 // Advance the current grid cell.
434 current_x_ += cell_size.width();
435 if (current_x_ > max_point_.x()) {
436 current_y_ += cell_size.height();
437 current_x_ = min_point_.x();
438 if (current_y_ > max_point_.y()) {
439 current_pixel_refs_ = empty_pixel_refs_.Pointer();
440 current_index_ = 0;
441 break;
445 // If there are no pixel refs at this grid cell, keep incrementing.
446 PixelRefMapKey key(current_x_, current_y_);
447 PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key);
448 if (iter == picture_->pixel_refs_.end())
449 continue;
451 // We found a non-empty list: store it and get the first pixel ref.
452 current_pixel_refs_ = &iter->second;
453 current_index_ = 0;
454 break;
456 return *this;
459 scoped_refptr<base::debug::ConvertableToTraceFormat>
460 Picture::AsTraceableRasterData(float scale) const {
461 scoped_refptr<base::debug::TracedValue> raster_data =
462 new base::debug::TracedValue();
463 TracedValue::SetIDRef(this, raster_data.get(), "picture_id");
464 raster_data->SetDouble("scale", scale);
465 return raster_data;
468 scoped_refptr<base::debug::ConvertableToTraceFormat>
469 Picture::AsTraceableRecordData() const {
470 scoped_refptr<base::debug::TracedValue> record_data =
471 new base::debug::TracedValue();
472 TracedValue::SetIDRef(this, record_data.get(), "picture_id");
473 MathUtil::AddToTracedValue("layer_rect", layer_rect_, record_data.get());
474 return record_data;
477 } // namespace cc