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.
4
5 #include "cc/resources/picture.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <set>
10
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/lazy_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"
30
31 namespace cc {
32
33 namespace {
34
EncodeBitmap(size_t * offset,const SkBitmap & bm)35 SkData* EncodeBitmap(size_t* offset, const SkBitmap& bm) {
36 const int kJpegQuality = 80;
37 std::vector<unsigned char> data;
38
39 // If bitmap is opaque, encode as JPEG.
40 // Otherwise encode as PNG.
41 bool encoding_succeeded = false;
42 if (bm.isOpaque()) {
43 SkAutoLockPixels lock_bitmap(bm);
44 if (bm.empty())
45 return NULL;
46
47 encoding_succeeded = gfx::JPEGCodec::Encode(
48 reinterpret_cast<unsigned char*>(bm.getAddr32(0, 0)),
49 gfx::JPEGCodec::FORMAT_SkBitmap,
50 bm.width(),
51 bm.height(),
52 bm.rowBytes(),
53 kJpegQuality,
54 &data);
55 } else {
56 encoding_succeeded = gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &data);
57 }
58
59 if (encoding_succeeded) {
60 *offset = 0;
61 return SkData::NewWithCopy(&data.front(), data.size());
62 }
63 return NULL;
64 }
65
DecodeBitmap(const void * buffer,size_t size,SkBitmap * bm)66 bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
67 const unsigned char* data = static_cast<const unsigned char *>(buffer);
68
69 // Try PNG first.
70 if (gfx::PNGCodec::Decode(data, size, bm))
71 return true;
72
73 // Try JPEG.
74 scoped_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodec::Decode(data, size));
75 if (decoded_jpeg) {
76 *bm = *decoded_jpeg;
77 return true;
78 }
79 return false;
80 }
81
82 } // namespace
83
Create(gfx::Rect layer_rect)84 scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) {
85 return make_scoped_refptr(new Picture(layer_rect));
86 }
87
Picture(gfx::Rect layer_rect)88 Picture::Picture(gfx::Rect layer_rect)
89 : layer_rect_(layer_rect),
90 cell_size_(layer_rect.size()) {
91 // Instead of recording a trace event for object creation here, we wait for
92 // the picture to be recorded in Picture::Record.
93 }
94
CreateFromSkpValue(const base::Value * value)95 scoped_refptr<Picture> Picture::CreateFromSkpValue(const base::Value* value) {
96 // Decode the picture from base64.
97 std::string encoded;
98 if (!value->GetAsString(&encoded))
99 return NULL;
100
101 std::string decoded;
102 base::Base64Decode(encoded, &decoded);
103 SkMemoryStream stream(decoded.data(), decoded.size());
104
105 // Read the picture. This creates an empty picture on failure.
106 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
107 if (skpicture == NULL)
108 return NULL;
109
110 gfx::Rect layer_rect(skpicture->width(), skpicture->height());
111 gfx::Rect opaque_rect(skpicture->width(), skpicture->height());
112
113 return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
114 }
115
CreateFromValue(const base::Value * raw_value)116 scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
117 const base::DictionaryValue* value = NULL;
118 if (!raw_value->GetAsDictionary(&value))
119 return NULL;
120
121 // Decode the picture from base64.
122 std::string encoded;
123 if (!value->GetString("skp64", &encoded))
124 return NULL;
125
126 std::string decoded;
127 base::Base64Decode(encoded, &decoded);
128 SkMemoryStream stream(decoded.data(), decoded.size());
129
130 const base::Value* layer_rect_value = NULL;
131 if (!value->Get("params.layer_rect", &layer_rect_value))
132 return NULL;
133
134 gfx::Rect layer_rect;
135 if (!MathUtil::FromValue(layer_rect_value, &layer_rect))
136 return NULL;
137
138 const base::Value* opaque_rect_value = NULL;
139 if (!value->Get("params.opaque_rect", &opaque_rect_value))
140 return NULL;
141
142 gfx::Rect opaque_rect;
143 if (!MathUtil::FromValue(opaque_rect_value, &opaque_rect))
144 return NULL;
145
146 // Read the picture. This creates an empty picture on failure.
147 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
148 if (skpicture == NULL)
149 return NULL;
150
151 return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
152 }
153
Picture(SkPicture * picture,gfx::Rect layer_rect,gfx::Rect opaque_rect)154 Picture::Picture(SkPicture* picture,
155 gfx::Rect layer_rect,
156 gfx::Rect opaque_rect) :
157 layer_rect_(layer_rect),
158 opaque_rect_(opaque_rect),
159 picture_(skia::AdoptRef(picture)),
160 cell_size_(layer_rect.size()) {
161 }
162
Picture(const skia::RefPtr<SkPicture> & picture,gfx::Rect layer_rect,gfx::Rect opaque_rect,const PixelRefMap & pixel_refs)163 Picture::Picture(const skia::RefPtr<SkPicture>& picture,
164 gfx::Rect layer_rect,
165 gfx::Rect opaque_rect,
166 const PixelRefMap& pixel_refs) :
167 layer_rect_(layer_rect),
168 opaque_rect_(opaque_rect),
169 picture_(picture),
170 pixel_refs_(pixel_refs),
171 cell_size_(layer_rect.size()) {
172 }
173
~Picture()174 Picture::~Picture() {
175 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
176 TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
177 }
178
GetCloneForDrawingOnThread(unsigned thread_index) const179 scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread(
180 unsigned thread_index) const {
181 // SkPicture is not thread-safe to rasterize with, this returns a clone
182 // to rasterize with on a specific thread.
183 CHECK_GT(clones_.size(), thread_index);
184 return clones_[thread_index];
185 }
186
CloneForDrawing(int num_threads)187 void Picture::CloneForDrawing(int num_threads) {
188 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads);
189
190 DCHECK(picture_);
191 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]);
192 picture_->clone(&clones[0], num_threads);
193
194 clones_.clear();
195 for (int i = 0; i < num_threads; i++) {
196 scoped_refptr<Picture> clone = make_scoped_refptr(
197 new Picture(skia::AdoptRef(new SkPicture(clones[i])),
198 layer_rect_,
199 opaque_rect_,
200 pixel_refs_));
201 clones_.push_back(clone);
202
203 clone->EmitTraceSnapshotAlias(this);
204 }
205 }
206
Record(ContentLayerClient * painter,const SkTileGridPicture::TileGridInfo & tile_grid_info)207 void Picture::Record(ContentLayerClient* painter,
208 const SkTileGridPicture::TileGridInfo& tile_grid_info) {
209 TRACE_EVENT1("cc", "Picture::Record",
210 "data", AsTraceableRecordData());
211
212 DCHECK(!tile_grid_info.fTileInterval.isEmpty());
213 picture_ = skia::AdoptRef(new SkTileGridPicture(
214 layer_rect_.width(), layer_rect_.height(), tile_grid_info));
215
216 SkCanvas* canvas = picture_->beginRecording(
217 layer_rect_.width(),
218 layer_rect_.height(),
219 SkPicture::kUsePathBoundsForClip_RecordingFlag |
220 SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
221
222 canvas->save();
223 canvas->translate(SkFloatToScalar(-layer_rect_.x()),
224 SkFloatToScalar(-layer_rect_.y()));
225
226 SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
227 layer_rect_.y(),
228 layer_rect_.width(),
229 layer_rect_.height());
230 canvas->clipRect(layer_skrect);
231
232 gfx::RectF opaque_layer_rect;
233
234 painter->PaintContents(canvas, layer_rect_, &opaque_layer_rect);
235
236 canvas->restore();
237 picture_->endRecording();
238
239 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
240
241 EmitTraceSnapshot();
242 }
243
GatherPixelRefs(const SkTileGridPicture::TileGridInfo & tile_grid_info)244 void Picture::GatherPixelRefs(
245 const SkTileGridPicture::TileGridInfo& tile_grid_info) {
246 TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
247 "width", layer_rect_.width(),
248 "height", layer_rect_.height());
249
250 DCHECK(picture_);
251 if (!WillPlayBackBitmaps())
252 return;
253 cell_size_ = gfx::Size(
254 tile_grid_info.fTileInterval.width() +
255 2 * tile_grid_info.fMargin.width(),
256 tile_grid_info.fTileInterval.height() +
257 2 * tile_grid_info.fMargin.height());
258 DCHECK_GT(cell_size_.width(), 0);
259 DCHECK_GT(cell_size_.height(), 0);
260
261 int min_x = std::numeric_limits<int>::max();
262 int min_y = std::numeric_limits<int>::max();
263 int max_x = 0;
264 int max_y = 0;
265
266 skia::LazyPixelRefList pixel_refs;
267 skia::LazyPixelRefUtils::GatherPixelRefs(picture_.get(), &pixel_refs);
268 for (skia::LazyPixelRefList::const_iterator it = pixel_refs.begin();
269 it != pixel_refs.end();
270 ++it) {
271 gfx::Point min(
272 RoundDown(static_cast<int>(it->pixel_ref_rect.x()),
273 cell_size_.width()),
274 RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
275 cell_size_.height()));
276 gfx::Point max(
277 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
278 cell_size_.width()),
279 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
280 cell_size_.height()));
281
282 for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
283 for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
284 PixelRefMapKey key(x, y);
285 pixel_refs_[key].push_back(it->lazy_pixel_ref);
286 }
287 }
288
289 min_x = std::min(min_x, min.x());
290 min_y = std::min(min_y, min.y());
291 max_x = std::max(max_x, max.x());
292 max_y = std::max(max_y, max.y());
293 }
294
295 min_pixel_cell_ = gfx::Point(min_x, min_y);
296 max_pixel_cell_ = gfx::Point(max_x, max_y);
297 }
298
Raster(SkCanvas * canvas,SkDrawPictureCallback * callback,const Region & negated_content_region,float contents_scale)299 int Picture::Raster(
300 SkCanvas* canvas,
301 SkDrawPictureCallback* callback,
302 const Region& negated_content_region,
303 float contents_scale) {
304 TRACE_EVENT_BEGIN1(
305 "cc",
306 "Picture::Raster",
307 "data",
308 AsTraceableRasterData(contents_scale));
309
310 DCHECK(picture_);
311
312 canvas->save();
313
314 for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
315 canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
316
317 canvas->scale(contents_scale, contents_scale);
318 canvas->translate(layer_rect_.x(), layer_rect_.y());
319 picture_->draw(canvas, callback);
320 SkIRect bounds;
321 canvas->getClipDeviceBounds(&bounds);
322 canvas->restore();
323 TRACE_EVENT_END1(
324 "cc", "Picture::Raster",
325 "num_pixels_rasterized", bounds.width() * bounds.height());
326 return bounds.width() * bounds.height();
327 }
328
Replay(SkCanvas * canvas)329 void Picture::Replay(SkCanvas* canvas) {
330 TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
331 DCHECK(picture_);
332
333 picture_->draw(canvas);
334 SkIRect bounds;
335 canvas->getClipDeviceBounds(&bounds);
336 TRACE_EVENT_END1("cc", "Picture::Replay",
337 "num_pixels_replayed", bounds.width() * bounds.height());
338 }
339
AsValue() const340 scoped_ptr<base::Value> Picture::AsValue() const {
341 SkDynamicMemoryWStream stream;
342
343 // Serialize the picture.
344 picture_->serialize(&stream, &EncodeBitmap);
345
346 // Encode the picture as base64.
347 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
348 res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
349 res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release());
350
351 size_t serialized_size = stream.bytesWritten();
352 scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
353 stream.copyTo(serialized_picture.get());
354 std::string b64_picture;
355 base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
356 &b64_picture);
357 res->SetString("skp64", b64_picture);
358 return res.PassAs<base::Value>();
359 }
360
EmitTraceSnapshot()361 void Picture::EmitTraceSnapshot() {
362 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
363 "cc::Picture", this, TracedPicture::AsTraceablePicture(this));
364 }
365
EmitTraceSnapshotAlias(Picture * original)366 void Picture::EmitTraceSnapshotAlias(Picture* original) {
367 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
368 TRACE_DISABLED_BY_DEFAULT("cc.debug"),
369 "cc::Picture",
370 this,
371 TracedPicture::AsTraceablePictureAlias(original));
372 }
373
374 base::LazyInstance<Picture::PixelRefs>
375 Picture::PixelRefIterator::empty_pixel_refs_;
376
PixelRefIterator()377 Picture::PixelRefIterator::PixelRefIterator()
378 : picture_(NULL),
379 current_pixel_refs_(empty_pixel_refs_.Pointer()),
380 current_index_(0),
381 min_point_(-1, -1),
382 max_point_(-1, -1),
383 current_x_(0),
384 current_y_(0) {
385 }
386
PixelRefIterator(gfx::Rect query_rect,const Picture * picture)387 Picture::PixelRefIterator::PixelRefIterator(
388 gfx::Rect query_rect,
389 const Picture* picture)
390 : picture_(picture),
391 current_pixel_refs_(empty_pixel_refs_.Pointer()),
392 current_index_(0) {
393 gfx::Rect layer_rect = picture->layer_rect_;
394 gfx::Size cell_size = picture->cell_size_;
395 DCHECK(!cell_size.IsEmpty());
396
397 // Early out if the query rect doesn't intersect this picture.
398 if (!query_rect.Intersects(layer_rect)) {
399 min_point_ = gfx::Point(0, 0);
400 max_point_ = gfx::Point(0, 0);
401 current_x_ = 1;
402 current_y_ = 1;
403 return;
404 }
405
406 // First, subtract the layer origin as cells are stored in layer space.
407 query_rect.Offset(-layer_rect.OffsetFromOrigin());
408
409 // We have to find a cell_size aligned point that corresponds to
410 // query_rect. Point is a multiple of cell_size.
411 min_point_ = gfx::Point(
412 RoundDown(query_rect.x(), cell_size.width()),
413 RoundDown(query_rect.y(), cell_size.height()));
414 max_point_ = gfx::Point(
415 RoundDown(query_rect.right() - 1, cell_size.width()),
416 RoundDown(query_rect.bottom() - 1, cell_size.height()));
417
418 // Limit the points to known pixel ref boundaries.
419 min_point_ = gfx::Point(
420 std::max(min_point_.x(), picture->min_pixel_cell_.x()),
421 std::max(min_point_.y(), picture->min_pixel_cell_.y()));
422 max_point_ = gfx::Point(
423 std::min(max_point_.x(), picture->max_pixel_cell_.x()),
424 std::min(max_point_.y(), picture->max_pixel_cell_.y()));
425
426 // Make the current x be cell_size.width() less than min point, so that
427 // the first increment will point at min_point_.
428 current_x_ = min_point_.x() - cell_size.width();
429 current_y_ = min_point_.y();
430 if (current_y_ <= max_point_.y())
431 ++(*this);
432 }
433
~PixelRefIterator()434 Picture::PixelRefIterator::~PixelRefIterator() {
435 }
436
operator ++()437 Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() {
438 ++current_index_;
439 // If we're not at the end of the list, then we have the next item.
440 if (current_index_ < current_pixel_refs_->size())
441 return *this;
442
443 DCHECK(current_y_ <= max_point_.y());
444 while (true) {
445 gfx::Size cell_size = picture_->cell_size_;
446
447 // Advance the current grid cell.
448 current_x_ += cell_size.width();
449 if (current_x_ > max_point_.x()) {
450 current_y_ += cell_size.height();
451 current_x_ = min_point_.x();
452 if (current_y_ > max_point_.y()) {
453 current_pixel_refs_ = empty_pixel_refs_.Pointer();
454 current_index_ = 0;
455 break;
456 }
457 }
458
459 // If there are no pixel refs at this grid cell, keep incrementing.
460 PixelRefMapKey key(current_x_, current_y_);
461 PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key);
462 if (iter == picture_->pixel_refs_.end())
463 continue;
464
465 // We found a non-empty list: store it and get the first pixel ref.
466 current_pixel_refs_ = &iter->second;
467 current_index_ = 0;
468 break;
469 }
470 return *this;
471 }
472
473 scoped_refptr<base::debug::ConvertableToTraceFormat>
AsTraceableRasterData(float scale) const474 Picture::AsTraceableRasterData(float scale) const {
475 scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue());
476 raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
477 raster_data->SetDouble("scale", scale);
478 return TracedValue::FromValue(raster_data.release());
479 }
480
481 scoped_refptr<base::debug::ConvertableToTraceFormat>
AsTraceableRecordData() const482 Picture::AsTraceableRecordData() const {
483 scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
484 record_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
485 record_data->SetInteger("width", layer_rect_.width());
486 record_data->SetInteger("height", layer_rect_.height());
487 return TracedValue::FromValue(record_data.release());
488 }
489
490 } // namespace cc
491