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"
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/SkStream.h"
25 #include "third_party/skia/include/utils/SkPictureUtils.h"
26 #include "ui/gfx/codec/jpeg_codec.h"
27 #include "ui/gfx/codec/png_codec.h"
28 #include "ui/gfx/rect_conversions.h"
29 #include "ui/gfx/skia_util.h"
35 SkData* EncodeBitmap(size_t* offset, const SkBitmap& bm) {
36 const int kJpegQuality = 80;
37 std::vector<unsigned char> data;
39 // If bitmap is opaque, encode as JPEG.
40 // Otherwise encode as PNG.
41 bool encoding_succeeded = false;
43 SkAutoLockPixels lock_bitmap(bm);
47 encoding_succeeded = gfx::JPEGCodec::Encode(
48 reinterpret_cast<unsigned char*>(bm.getAddr32(0, 0)),
49 gfx::JPEGCodec::FORMAT_SkBitmap,
56 encoding_succeeded = gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &data);
59 if (encoding_succeeded) {
61 return SkData::NewWithCopy(&data.front(), data.size());
66 bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
67 const unsigned char* data = static_cast<const unsigned char *>(buffer);
70 if (gfx::PNGCodec::Decode(data, size, bm))
74 scoped_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodec::Decode(data, size));
84 scoped_refptr<Picture> Picture::Create(
85 const gfx::Rect& layer_rect,
86 ContentLayerClient* client,
87 const SkTileGridPicture::TileGridInfo& tile_grid_info,
88 bool gather_pixel_refs,
89 int num_raster_threads) {
90 scoped_refptr<Picture> picture = make_scoped_refptr(new Picture(layer_rect));
92 picture->Record(client, tile_grid_info);
93 if (gather_pixel_refs)
94 picture->GatherPixelRefs(tile_grid_info);
95 picture->CloneForDrawing(num_raster_threads);
100 Picture::Picture(const gfx::Rect& layer_rect)
101 : layer_rect_(layer_rect),
102 cell_size_(layer_rect.size()) {
103 // Instead of recording a trace event for object creation here, we wait for
104 // the picture to be recorded in Picture::Record.
107 scoped_refptr<Picture> Picture::CreateFromSkpValue(const base::Value* value) {
108 // Decode the picture from base64.
110 if (!value->GetAsString(&encoded))
114 base::Base64Decode(encoded, &decoded);
115 SkMemoryStream stream(decoded.data(), decoded.size());
117 // Read the picture. This creates an empty picture on failure.
118 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
119 if (skpicture == NULL)
122 gfx::Rect layer_rect(skpicture->width(), skpicture->height());
123 gfx::Rect opaque_rect(skpicture->width(), skpicture->height());
125 return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
128 scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
129 const base::DictionaryValue* value = NULL;
130 if (!raw_value->GetAsDictionary(&value))
133 // Decode the picture from base64.
135 if (!value->GetString("skp64", &encoded))
139 base::Base64Decode(encoded, &decoded);
140 SkMemoryStream stream(decoded.data(), decoded.size());
142 const base::Value* layer_rect_value = NULL;
143 if (!value->Get("params.layer_rect", &layer_rect_value))
146 gfx::Rect layer_rect;
147 if (!MathUtil::FromValue(layer_rect_value, &layer_rect))
150 const base::Value* opaque_rect_value = NULL;
151 if (!value->Get("params.opaque_rect", &opaque_rect_value))
154 gfx::Rect opaque_rect;
155 if (!MathUtil::FromValue(opaque_rect_value, &opaque_rect))
158 // Read the picture. This creates an empty picture on failure.
159 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
160 if (skpicture == NULL)
163 return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
166 Picture::Picture(SkPicture* picture,
167 const gfx::Rect& layer_rect,
168 const gfx::Rect& opaque_rect) :
169 layer_rect_(layer_rect),
170 opaque_rect_(opaque_rect),
171 picture_(skia::AdoptRef(picture)),
172 cell_size_(layer_rect.size()) {
175 Picture::Picture(const skia::RefPtr<SkPicture>& picture,
176 const gfx::Rect& layer_rect,
177 const gfx::Rect& opaque_rect,
178 const PixelRefMap& pixel_refs) :
179 layer_rect_(layer_rect),
180 opaque_rect_(opaque_rect),
182 pixel_refs_(pixel_refs),
183 cell_size_(layer_rect.size()) {
186 Picture::~Picture() {
187 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
188 TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
191 Picture* Picture::GetCloneForDrawingOnThread(unsigned thread_index) {
192 // SkPicture is not thread-safe to rasterize with, this returns a clone
193 // to rasterize with on a specific thread.
194 CHECK_GE(clones_.size(), thread_index);
195 return thread_index == clones_.size() ? this : clones_[thread_index].get();
198 void Picture::CloneForDrawing(int num_threads) {
199 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads);
202 DCHECK(clones_.empty());
204 // We can re-use this picture for one raster worker thread.
205 raster_thread_checker_.DetachFromThread();
207 if (num_threads > 1) {
208 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads - 1]);
209 picture_->clone(&clones[0], num_threads - 1);
211 for (int i = 0; i < num_threads - 1; i++) {
212 scoped_refptr<Picture> clone = make_scoped_refptr(
213 new Picture(skia::AdoptRef(new SkPicture(clones[i])),
217 clones_.push_back(clone);
219 clone->EmitTraceSnapshotAlias(this);
220 clone->raster_thread_checker_.DetachFromThread();
225 void Picture::Record(ContentLayerClient* painter,
226 const SkTileGridPicture::TileGridInfo& tile_grid_info) {
227 TRACE_EVENT1("cc", "Picture::Record",
228 "data", AsTraceableRecordData());
231 DCHECK(!tile_grid_info.fTileInterval.isEmpty());
232 picture_ = skia::AdoptRef(new SkTileGridPicture(
233 layer_rect_.width(), layer_rect_.height(), tile_grid_info));
235 SkCanvas* canvas = picture_->beginRecording(
237 layer_rect_.height(),
238 SkPicture::kUsePathBoundsForClip_RecordingFlag |
239 SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
242 canvas->translate(SkFloatToScalar(-layer_rect_.x()),
243 SkFloatToScalar(-layer_rect_.y()));
245 SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
248 layer_rect_.height());
249 canvas->clipRect(layer_skrect);
251 gfx::RectF opaque_layer_rect;
253 painter->PaintContents(canvas, layer_rect_, &opaque_layer_rect);
256 picture_->endRecording();
258 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
263 void Picture::GatherPixelRefs(
264 const SkTileGridPicture::TileGridInfo& tile_grid_info) {
265 TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
266 "width", layer_rect_.width(),
267 "height", layer_rect_.height());
270 DCHECK(pixel_refs_.empty());
271 if (!WillPlayBackBitmaps())
273 cell_size_ = gfx::Size(
274 tile_grid_info.fTileInterval.width() +
275 2 * tile_grid_info.fMargin.width(),
276 tile_grid_info.fTileInterval.height() +
277 2 * tile_grid_info.fMargin.height());
278 DCHECK_GT(cell_size_.width(), 0);
279 DCHECK_GT(cell_size_.height(), 0);
281 int min_x = std::numeric_limits<int>::max();
282 int min_y = std::numeric_limits<int>::max();
286 skia::DiscardablePixelRefList pixel_refs;
287 skia::PixelRefUtils::GatherDiscardablePixelRefs(picture_.get(), &pixel_refs);
288 for (skia::DiscardablePixelRefList::const_iterator it = pixel_refs.begin();
289 it != pixel_refs.end();
292 RoundDown(static_cast<int>(it->pixel_ref_rect.x()),
294 RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
295 cell_size_.height()));
297 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
299 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
300 cell_size_.height()));
302 for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
303 for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
304 PixelRefMapKey key(x, y);
305 pixel_refs_[key].push_back(it->pixel_ref);
309 min_x = std::min(min_x, min.x());
310 min_y = std::min(min_y, min.y());
311 max_x = std::max(max_x, max.x());
312 max_y = std::max(max_y, max.y());
315 min_pixel_cell_ = gfx::Point(min_x, min_y);
316 max_pixel_cell_ = gfx::Point(max_x, max_y);
321 SkDrawPictureCallback* callback,
322 const Region& negated_content_region,
323 float contents_scale) {
324 DCHECK(raster_thread_checker_.CalledOnValidThread());
329 AsTraceableRasterData(contents_scale));
335 for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
336 canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
338 canvas->scale(contents_scale, contents_scale);
339 canvas->translate(layer_rect_.x(), layer_rect_.y());
340 picture_->draw(canvas, callback);
342 canvas->getClipDeviceBounds(&bounds);
345 "cc", "Picture::Raster",
346 "num_pixels_rasterized", bounds.width() * bounds.height());
347 return bounds.width() * bounds.height();
350 void Picture::Replay(SkCanvas* canvas) {
351 DCHECK(raster_thread_checker_.CalledOnValidThread());
352 TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
355 picture_->draw(canvas);
357 canvas->getClipDeviceBounds(&bounds);
358 TRACE_EVENT_END1("cc", "Picture::Replay",
359 "num_pixels_replayed", bounds.width() * bounds.height());
362 scoped_ptr<base::Value> Picture::AsValue() const {
363 SkDynamicMemoryWStream stream;
365 // Serialize the picture.
366 picture_->serialize(&stream, &EncodeBitmap);
368 // Encode the picture as base64.
369 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
370 res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
371 res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release());
373 size_t serialized_size = stream.bytesWritten();
374 scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
375 stream.copyTo(serialized_picture.get());
376 std::string b64_picture;
377 base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
379 res->SetString("skp64", b64_picture);
380 return res.PassAs<base::Value>();
383 void Picture::EmitTraceSnapshot() const {
384 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
385 "cc::Picture", this, TracedPicture::AsTraceablePicture(this));
388 void Picture::EmitTraceSnapshotAlias(Picture* original) const {
389 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
390 TRACE_DISABLED_BY_DEFAULT("cc.debug"),
393 TracedPicture::AsTraceablePictureAlias(original));
396 base::LazyInstance<Picture::PixelRefs>
397 Picture::PixelRefIterator::empty_pixel_refs_;
399 Picture::PixelRefIterator::PixelRefIterator()
401 current_pixel_refs_(empty_pixel_refs_.Pointer()),
409 Picture::PixelRefIterator::PixelRefIterator(
410 const gfx::Rect& rect,
411 const Picture* picture)
413 current_pixel_refs_(empty_pixel_refs_.Pointer()),
415 gfx::Rect layer_rect = picture->layer_rect_;
416 gfx::Size cell_size = picture->cell_size_;
417 DCHECK(!cell_size.IsEmpty());
419 gfx::Rect query_rect(rect);
420 // Early out if the query rect doesn't intersect this picture.
421 if (!query_rect.Intersects(layer_rect)) {
422 min_point_ = gfx::Point(0, 0);
423 max_point_ = gfx::Point(0, 0);
429 // First, subtract the layer origin as cells are stored in layer space.
430 query_rect.Offset(-layer_rect.OffsetFromOrigin());
432 // We have to find a cell_size aligned point that corresponds to
433 // query_rect. Point is a multiple of cell_size.
434 min_point_ = gfx::Point(
435 RoundDown(query_rect.x(), cell_size.width()),
436 RoundDown(query_rect.y(), cell_size.height()));
437 max_point_ = gfx::Point(
438 RoundDown(query_rect.right() - 1, cell_size.width()),
439 RoundDown(query_rect.bottom() - 1, cell_size.height()));
441 // Limit the points to known pixel ref boundaries.
442 min_point_ = gfx::Point(
443 std::max(min_point_.x(), picture->min_pixel_cell_.x()),
444 std::max(min_point_.y(), picture->min_pixel_cell_.y()));
445 max_point_ = gfx::Point(
446 std::min(max_point_.x(), picture->max_pixel_cell_.x()),
447 std::min(max_point_.y(), picture->max_pixel_cell_.y()));
449 // Make the current x be cell_size.width() less than min point, so that
450 // the first increment will point at min_point_.
451 current_x_ = min_point_.x() - cell_size.width();
452 current_y_ = min_point_.y();
453 if (current_y_ <= max_point_.y())
457 Picture::PixelRefIterator::~PixelRefIterator() {
460 Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() {
462 // If we're not at the end of the list, then we have the next item.
463 if (current_index_ < current_pixel_refs_->size())
466 DCHECK(current_y_ <= max_point_.y());
468 gfx::Size cell_size = picture_->cell_size_;
470 // Advance the current grid cell.
471 current_x_ += cell_size.width();
472 if (current_x_ > max_point_.x()) {
473 current_y_ += cell_size.height();
474 current_x_ = min_point_.x();
475 if (current_y_ > max_point_.y()) {
476 current_pixel_refs_ = empty_pixel_refs_.Pointer();
482 // If there are no pixel refs at this grid cell, keep incrementing.
483 PixelRefMapKey key(current_x_, current_y_);
484 PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key);
485 if (iter == picture_->pixel_refs_.end())
488 // We found a non-empty list: store it and get the first pixel ref.
489 current_pixel_refs_ = &iter->second;
496 scoped_refptr<base::debug::ConvertableToTraceFormat>
497 Picture::AsTraceableRasterData(float scale) const {
498 scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue());
499 raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
500 raster_data->SetDouble("scale", scale);
501 return TracedValue::FromValue(raster_data.release());
504 scoped_refptr<base::debug::ConvertableToTraceFormat>
505 Picture::AsTraceableRecordData() const {
506 scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
507 record_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
508 record_data->SetInteger("width", layer_rect_.width());
509 record_data->SetInteger("height", layer_rect_.height());
510 return TracedValue::FromValue(record_data.release());