Temporarily re-enabling SizeAfterPrefChange test with traces.
[chromium-blink-merge.git] / cc / resources / picture.cc
blob7147a156b0e28afa0b2b5151c85e9a57d916a3fd
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/values.h"
14 #include "cc/base/math_util.h"
15 #include "cc/base/util.h"
16 #include "cc/debug/traced_picture.h"
17 #include "cc/debug/traced_value.h"
18 #include "cc/layers/content_layer_client.h"
19 #include "skia/ext/pixel_ref_utils.h"
20 #include "third_party/skia/include/core/SkCanvas.h"
21 #include "third_party/skia/include/core/SkData.h"
22 #include "third_party/skia/include/core/SkDrawFilter.h"
23 #include "third_party/skia/include/core/SkPaint.h"
24 #include "third_party/skia/include/core/SkPictureRecorder.h"
25 #include "third_party/skia/include/core/SkStream.h"
26 #include "third_party/skia/include/utils/SkNullCanvas.h"
27 #include "third_party/skia/include/utils/SkPictureUtils.h"
28 #include "ui/gfx/codec/jpeg_codec.h"
29 #include "ui/gfx/codec/png_codec.h"
30 #include "ui/gfx/rect_conversions.h"
31 #include "ui/gfx/skia_util.h"
33 namespace cc {
35 namespace {
37 SkData* EncodeBitmap(size_t* offset, const SkBitmap& bm) {
38 const int kJpegQuality = 80;
39 std::vector<unsigned char> data;
41 // If bitmap is opaque, encode as JPEG.
42 // Otherwise encode as PNG.
43 bool encoding_succeeded = false;
44 if (bm.isOpaque()) {
45 SkAutoLockPixels lock_bitmap(bm);
46 if (bm.empty())
47 return NULL;
49 encoding_succeeded = gfx::JPEGCodec::Encode(
50 reinterpret_cast<unsigned char*>(bm.getAddr32(0, 0)),
51 gfx::JPEGCodec::FORMAT_SkBitmap,
52 bm.width(),
53 bm.height(),
54 bm.rowBytes(),
55 kJpegQuality,
56 &data);
57 } else {
58 encoding_succeeded = gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &data);
61 if (encoding_succeeded) {
62 *offset = 0;
63 return SkData::NewWithCopy(&data.front(), data.size());
65 return NULL;
68 bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
69 const unsigned char* data = static_cast<const unsigned char *>(buffer);
71 // Try PNG first.
72 if (gfx::PNGCodec::Decode(data, size, bm))
73 return true;
75 // Try JPEG.
76 scoped_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodec::Decode(data, size));
77 if (decoded_jpeg) {
78 *bm = *decoded_jpeg;
79 return true;
81 return false;
84 } // namespace
86 scoped_refptr<Picture> Picture::Create(
87 const gfx::Rect& layer_rect,
88 ContentLayerClient* client,
89 const SkTileGridFactory::TileGridInfo& tile_grid_info,
90 bool gather_pixel_refs,
91 int num_raster_threads,
92 RecordingMode recording_mode) {
93 scoped_refptr<Picture> picture = make_scoped_refptr(new Picture(layer_rect));
95 picture->Record(client, tile_grid_info, recording_mode);
96 if (gather_pixel_refs)
97 picture->GatherPixelRefs(tile_grid_info);
98 picture->CloneForDrawing(num_raster_threads);
100 return picture;
103 Picture::Picture(const gfx::Rect& layer_rect)
104 : layer_rect_(layer_rect),
105 cell_size_(layer_rect.size()) {
106 // Instead of recording a trace event for object creation here, we wait for
107 // the picture to be recorded in Picture::Record.
110 scoped_refptr<Picture> Picture::CreateFromSkpValue(const base::Value* value) {
111 // Decode the picture from base64.
112 std::string encoded;
113 if (!value->GetAsString(&encoded))
114 return NULL;
116 std::string decoded;
117 base::Base64Decode(encoded, &decoded);
118 SkMemoryStream stream(decoded.data(), decoded.size());
120 // Read the picture. This creates an empty picture on failure.
121 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
122 if (skpicture == NULL)
123 return NULL;
125 gfx::Rect layer_rect(skpicture->width(), skpicture->height());
126 gfx::Rect opaque_rect(skpicture->width(), skpicture->height());
128 return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
131 scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
132 const base::DictionaryValue* value = NULL;
133 if (!raw_value->GetAsDictionary(&value))
134 return NULL;
136 // Decode the picture from base64.
137 std::string encoded;
138 if (!value->GetString("skp64", &encoded))
139 return NULL;
141 std::string decoded;
142 base::Base64Decode(encoded, &decoded);
143 SkMemoryStream stream(decoded.data(), decoded.size());
145 const base::Value* layer_rect_value = NULL;
146 if (!value->Get("params.layer_rect", &layer_rect_value))
147 return NULL;
149 gfx::Rect layer_rect;
150 if (!MathUtil::FromValue(layer_rect_value, &layer_rect))
151 return NULL;
153 const base::Value* opaque_rect_value = NULL;
154 if (!value->Get("params.opaque_rect", &opaque_rect_value))
155 return NULL;
157 gfx::Rect opaque_rect;
158 if (!MathUtil::FromValue(opaque_rect_value, &opaque_rect))
159 return NULL;
161 // Read the picture. This creates an empty picture on failure.
162 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
163 if (skpicture == NULL)
164 return NULL;
166 return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
169 Picture::Picture(SkPicture* picture,
170 const gfx::Rect& layer_rect,
171 const gfx::Rect& opaque_rect) :
172 layer_rect_(layer_rect),
173 opaque_rect_(opaque_rect),
174 picture_(skia::AdoptRef(picture)),
175 cell_size_(layer_rect.size()) {
178 Picture::Picture(const skia::RefPtr<SkPicture>& picture,
179 const gfx::Rect& layer_rect,
180 const gfx::Rect& opaque_rect,
181 const PixelRefMap& pixel_refs) :
182 layer_rect_(layer_rect),
183 opaque_rect_(opaque_rect),
184 picture_(picture),
185 pixel_refs_(pixel_refs),
186 cell_size_(layer_rect.size()) {
189 Picture::~Picture() {
190 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
191 TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
194 Picture* Picture::GetCloneForDrawingOnThread(unsigned thread_index) {
195 // We don't need clones to draw from multiple threads with SkRecord.
196 if (playback_) {
197 return this;
200 // SkPicture is not thread-safe to rasterize with, this returns a clone
201 // to rasterize with on a specific thread.
202 CHECK_GE(clones_.size(), thread_index);
203 return thread_index == clones_.size() ? this : clones_[thread_index].get();
206 bool Picture::IsSuitableForGpuRasterization() const {
207 DCHECK(picture_);
209 // TODO(alokp): SkPicture::suitableForGpuRasterization needs a GrContext.
210 // Ideally this GrContext should be the same as that for rasterizing this
211 // picture. But we are on the main thread while the rasterization context
212 // may be on the compositor or raster thread.
213 // SkPicture::suitableForGpuRasterization is not implemented yet.
214 // Pass a NULL context for now and discuss with skia folks if the context
215 // is really needed.
216 return picture_->suitableForGpuRasterization(NULL);
219 void Picture::CloneForDrawing(int num_threads) {
220 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads);
222 // We don't need clones to draw from multiple threads with SkRecord.
223 if (playback_) {
224 return;
227 DCHECK(picture_);
228 DCHECK(clones_.empty());
230 // We can re-use this picture for one raster worker thread.
231 raster_thread_checker_.DetachFromThread();
233 if (num_threads > 1) {
234 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads - 1]);
235 picture_->clone(&clones[0], num_threads - 1);
237 for (int i = 0; i < num_threads - 1; i++) {
238 scoped_refptr<Picture> clone = make_scoped_refptr(
239 new Picture(skia::AdoptRef(new SkPicture(clones[i])),
240 layer_rect_,
241 opaque_rect_,
242 pixel_refs_));
243 clones_.push_back(clone);
245 clone->EmitTraceSnapshotAlias(this);
246 clone->raster_thread_checker_.DetachFromThread();
251 void Picture::Record(ContentLayerClient* painter,
252 const SkTileGridFactory::TileGridInfo& tile_grid_info,
253 RecordingMode recording_mode) {
254 TRACE_EVENT2("cc",
255 "Picture::Record",
256 "data",
257 AsTraceableRecordData(),
258 "recording_mode",
259 recording_mode);
261 DCHECK(!picture_);
262 DCHECK(!tile_grid_info.fTileInterval.isEmpty());
264 SkTileGridFactory factory(tile_grid_info);
265 SkPictureRecorder recorder;
267 scoped_ptr<EXPERIMENTAL::SkRecording> recording;
269 skia::RefPtr<SkCanvas> canvas;
270 canvas = skia::SharePtr(
271 recorder.beginRecording(layer_rect_.width(),
272 layer_rect_.height(),
273 &factory,
274 SkPicture::kUsePathBoundsForClip_RecordingFlag));
276 ContentLayerClient::GraphicsContextStatus graphics_context_status =
277 ContentLayerClient::GRAPHICS_CONTEXT_ENABLED;
279 switch (recording_mode) {
280 case RECORD_NORMALLY:
281 // Already setup for normal recording.
282 break;
283 case RECORD_WITH_SK_NULL_CANVAS:
284 canvas = skia::AdoptRef(SkCreateNullCanvas());
285 break;
286 case RECORD_WITH_PAINTING_DISABLED:
287 // We pass a disable flag through the paint calls when perfromance
288 // testing (the only time this case should ever arise) when we want to
289 // prevent the Blink GraphicsContext object from consuming any compute
290 // time.
291 canvas = skia::AdoptRef(SkCreateNullCanvas());
292 graphics_context_status = ContentLayerClient::GRAPHICS_CONTEXT_DISABLED;
293 break;
294 case RECORD_WITH_SKRECORD:
295 recording.reset(new EXPERIMENTAL::SkRecording(layer_rect_.width(),
296 layer_rect_.height()));
297 canvas = skia::SharePtr(recording->canvas());
298 break;
299 default:
300 NOTREACHED();
303 canvas->save();
304 canvas->translate(SkFloatToScalar(-layer_rect_.x()),
305 SkFloatToScalar(-layer_rect_.y()));
307 SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
308 layer_rect_.y(),
309 layer_rect_.width(),
310 layer_rect_.height());
311 canvas->clipRect(layer_skrect);
313 gfx::RectF opaque_layer_rect;
314 painter->PaintContents(
315 canvas.get(), layer_rect_, &opaque_layer_rect, graphics_context_status);
317 canvas->restore();
318 picture_ = skia::AdoptRef(recorder.endRecording());
319 DCHECK(picture_);
321 if (recording) {
322 // SkRecording requires it's the only one holding onto canvas before we
323 // may call releasePlayback(). (This helps enforce thread-safety.)
324 canvas.clear();
325 playback_.reset(recording->releasePlayback());
328 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
330 EmitTraceSnapshot();
333 void Picture::GatherPixelRefs(
334 const SkTileGridFactory::TileGridInfo& tile_grid_info) {
335 TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
336 "width", layer_rect_.width(),
337 "height", layer_rect_.height());
339 DCHECK(picture_);
340 DCHECK(pixel_refs_.empty());
341 if (!WillPlayBackBitmaps())
342 return;
343 cell_size_ = gfx::Size(
344 tile_grid_info.fTileInterval.width() +
345 2 * tile_grid_info.fMargin.width(),
346 tile_grid_info.fTileInterval.height() +
347 2 * tile_grid_info.fMargin.height());
348 DCHECK_GT(cell_size_.width(), 0);
349 DCHECK_GT(cell_size_.height(), 0);
351 int min_x = std::numeric_limits<int>::max();
352 int min_y = std::numeric_limits<int>::max();
353 int max_x = 0;
354 int max_y = 0;
356 skia::DiscardablePixelRefList pixel_refs;
357 skia::PixelRefUtils::GatherDiscardablePixelRefs(picture_.get(), &pixel_refs);
358 for (skia::DiscardablePixelRefList::const_iterator it = pixel_refs.begin();
359 it != pixel_refs.end();
360 ++it) {
361 gfx::Point min(
362 RoundDown(static_cast<int>(it->pixel_ref_rect.x()),
363 cell_size_.width()),
364 RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
365 cell_size_.height()));
366 gfx::Point max(
367 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
368 cell_size_.width()),
369 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
370 cell_size_.height()));
372 for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
373 for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
374 PixelRefMapKey key(x, y);
375 pixel_refs_[key].push_back(it->pixel_ref);
379 min_x = std::min(min_x, min.x());
380 min_y = std::min(min_y, min.y());
381 max_x = std::max(max_x, max.x());
382 max_y = std::max(max_y, max.y());
385 min_pixel_cell_ = gfx::Point(min_x, min_y);
386 max_pixel_cell_ = gfx::Point(max_x, max_y);
389 int Picture::Raster(
390 SkCanvas* canvas,
391 SkDrawPictureCallback* callback,
392 const Region& negated_content_region,
393 float contents_scale) {
394 if (!playback_)
395 DCHECK(raster_thread_checker_.CalledOnValidThread());
396 TRACE_EVENT_BEGIN1(
397 "cc",
398 "Picture::Raster",
399 "data",
400 AsTraceableRasterData(contents_scale));
402 DCHECK(picture_);
404 canvas->save();
406 for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
407 canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
409 canvas->scale(contents_scale, contents_scale);
410 canvas->translate(layer_rect_.x(), layer_rect_.y());
411 if (playback_) {
412 playback_->draw(canvas);
413 } else {
414 picture_->draw(canvas, callback);
416 SkIRect bounds;
417 canvas->getClipDeviceBounds(&bounds);
418 canvas->restore();
419 TRACE_EVENT_END1(
420 "cc", "Picture::Raster",
421 "num_pixels_rasterized", bounds.width() * bounds.height());
422 return bounds.width() * bounds.height();
425 void Picture::Replay(SkCanvas* canvas) {
426 if (!playback_)
427 DCHECK(raster_thread_checker_.CalledOnValidThread());
428 TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
429 DCHECK(picture_);
431 if (playback_) {
432 playback_->draw(canvas);
433 } else {
434 picture_->draw(canvas);
436 SkIRect bounds;
437 canvas->getClipDeviceBounds(&bounds);
438 TRACE_EVENT_END1("cc", "Picture::Replay",
439 "num_pixels_replayed", bounds.width() * bounds.height());
442 scoped_ptr<base::Value> Picture::AsValue() const {
443 SkDynamicMemoryWStream stream;
445 if (playback_) {
446 // SkPlayback can't serialize itself, so re-record into an SkPicture.
447 SkPictureRecorder recorder;
448 skia::RefPtr<SkCanvas> canvas(skia::SharePtr(recorder.beginRecording(
449 layer_rect_.width(),
450 layer_rect_.height(),
451 NULL, // Default (no) bounding-box hierarchy is fastest.
452 SkPicture::kUsePathBoundsForClip_RecordingFlag)));
453 playback_->draw(canvas.get());
454 skia::RefPtr<SkPicture> picture(skia::AdoptRef(recorder.endRecording()));
455 picture->serialize(&stream, &EncodeBitmap);
456 } else {
457 // Serialize the picture.
458 picture_->serialize(&stream, &EncodeBitmap);
461 // Encode the picture as base64.
462 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
463 res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
464 res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release());
466 size_t serialized_size = stream.bytesWritten();
467 scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
468 stream.copyTo(serialized_picture.get());
469 std::string b64_picture;
470 base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
471 &b64_picture);
472 res->SetString("skp64", b64_picture);
473 return res.PassAs<base::Value>();
476 void Picture::EmitTraceSnapshot() const {
477 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
478 "cc::Picture", this, TracedPicture::AsTraceablePicture(this));
481 void Picture::EmitTraceSnapshotAlias(Picture* original) const {
482 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
483 TRACE_DISABLED_BY_DEFAULT("cc.debug"),
484 "cc::Picture",
485 this,
486 TracedPicture::AsTraceablePictureAlias(original));
489 base::LazyInstance<Picture::PixelRefs>
490 Picture::PixelRefIterator::empty_pixel_refs_;
492 Picture::PixelRefIterator::PixelRefIterator()
493 : picture_(NULL),
494 current_pixel_refs_(empty_pixel_refs_.Pointer()),
495 current_index_(0),
496 min_point_(-1, -1),
497 max_point_(-1, -1),
498 current_x_(0),
499 current_y_(0) {
502 Picture::PixelRefIterator::PixelRefIterator(
503 const gfx::Rect& rect,
504 const Picture* picture)
505 : picture_(picture),
506 current_pixel_refs_(empty_pixel_refs_.Pointer()),
507 current_index_(0) {
508 gfx::Rect layer_rect = picture->layer_rect_;
509 gfx::Size cell_size = picture->cell_size_;
510 DCHECK(!cell_size.IsEmpty());
512 gfx::Rect query_rect(rect);
513 // Early out if the query rect doesn't intersect this picture.
514 if (!query_rect.Intersects(layer_rect)) {
515 min_point_ = gfx::Point(0, 0);
516 max_point_ = gfx::Point(0, 0);
517 current_x_ = 1;
518 current_y_ = 1;
519 return;
522 // First, subtract the layer origin as cells are stored in layer space.
523 query_rect.Offset(-layer_rect.OffsetFromOrigin());
525 // We have to find a cell_size aligned point that corresponds to
526 // query_rect. Point is a multiple of cell_size.
527 min_point_ = gfx::Point(
528 RoundDown(query_rect.x(), cell_size.width()),
529 RoundDown(query_rect.y(), cell_size.height()));
530 max_point_ = gfx::Point(
531 RoundDown(query_rect.right() - 1, cell_size.width()),
532 RoundDown(query_rect.bottom() - 1, cell_size.height()));
534 // Limit the points to known pixel ref boundaries.
535 min_point_ = gfx::Point(
536 std::max(min_point_.x(), picture->min_pixel_cell_.x()),
537 std::max(min_point_.y(), picture->min_pixel_cell_.y()));
538 max_point_ = gfx::Point(
539 std::min(max_point_.x(), picture->max_pixel_cell_.x()),
540 std::min(max_point_.y(), picture->max_pixel_cell_.y()));
542 // Make the current x be cell_size.width() less than min point, so that
543 // the first increment will point at min_point_.
544 current_x_ = min_point_.x() - cell_size.width();
545 current_y_ = min_point_.y();
546 if (current_y_ <= max_point_.y())
547 ++(*this);
550 Picture::PixelRefIterator::~PixelRefIterator() {
553 Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() {
554 ++current_index_;
555 // If we're not at the end of the list, then we have the next item.
556 if (current_index_ < current_pixel_refs_->size())
557 return *this;
559 DCHECK(current_y_ <= max_point_.y());
560 while (true) {
561 gfx::Size cell_size = picture_->cell_size_;
563 // Advance the current grid cell.
564 current_x_ += cell_size.width();
565 if (current_x_ > max_point_.x()) {
566 current_y_ += cell_size.height();
567 current_x_ = min_point_.x();
568 if (current_y_ > max_point_.y()) {
569 current_pixel_refs_ = empty_pixel_refs_.Pointer();
570 current_index_ = 0;
571 break;
575 // If there are no pixel refs at this grid cell, keep incrementing.
576 PixelRefMapKey key(current_x_, current_y_);
577 PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key);
578 if (iter == picture_->pixel_refs_.end())
579 continue;
581 // We found a non-empty list: store it and get the first pixel ref.
582 current_pixel_refs_ = &iter->second;
583 current_index_ = 0;
584 break;
586 return *this;
589 scoped_refptr<base::debug::ConvertableToTraceFormat>
590 Picture::AsTraceableRasterData(float scale) const {
591 scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue());
592 raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
593 raster_data->SetDouble("scale", scale);
594 return TracedValue::FromValue(raster_data.release());
597 scoped_refptr<base::debug::ConvertableToTraceFormat>
598 Picture::AsTraceableRecordData() const {
599 scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
600 record_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
601 record_data->Set("layer_rect", MathUtil::AsValue(layer_rect_).release());
602 return TracedValue::FromValue(record_data.release());
605 } // namespace cc