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(const gfx::Rect
& layer_rect
) {
85 return make_scoped_refptr(new Picture(layer_rect
));
88 Picture::Picture(const 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.
95 scoped_refptr
<Picture
> Picture::CreateFromSkpValue(const base::Value
* value
) {
96 // Decode the picture from base64.
98 if (!value
->GetAsString(&encoded
))
102 base::Base64Decode(encoded
, &decoded
);
103 SkMemoryStream
stream(decoded
.data(), decoded
.size());
105 // Read the picture. This creates an empty picture on failure.
106 SkPicture
* skpicture
= SkPicture::CreateFromStream(&stream
, &DecodeBitmap
);
107 if (skpicture
== NULL
)
110 gfx::Rect
layer_rect(skpicture
->width(), skpicture
->height());
111 gfx::Rect
opaque_rect(skpicture
->width(), skpicture
->height());
113 return make_scoped_refptr(new Picture(skpicture
, layer_rect
, opaque_rect
));
116 scoped_refptr
<Picture
> Picture::CreateFromValue(const base::Value
* raw_value
) {
117 const base::DictionaryValue
* value
= NULL
;
118 if (!raw_value
->GetAsDictionary(&value
))
121 // Decode the picture from base64.
123 if (!value
->GetString("skp64", &encoded
))
127 base::Base64Decode(encoded
, &decoded
);
128 SkMemoryStream
stream(decoded
.data(), decoded
.size());
130 const base::Value
* layer_rect_value
= NULL
;
131 if (!value
->Get("params.layer_rect", &layer_rect_value
))
134 gfx::Rect layer_rect
;
135 if (!MathUtil::FromValue(layer_rect_value
, &layer_rect
))
138 const base::Value
* opaque_rect_value
= NULL
;
139 if (!value
->Get("params.opaque_rect", &opaque_rect_value
))
142 gfx::Rect opaque_rect
;
143 if (!MathUtil::FromValue(opaque_rect_value
, &opaque_rect
))
146 // Read the picture. This creates an empty picture on failure.
147 SkPicture
* skpicture
= SkPicture::CreateFromStream(&stream
, &DecodeBitmap
);
148 if (skpicture
== NULL
)
151 return make_scoped_refptr(new Picture(skpicture
, layer_rect
, opaque_rect
));
154 Picture::Picture(SkPicture
* picture
,
155 const gfx::Rect
& layer_rect
,
156 const 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()) {
163 Picture::Picture(const skia::RefPtr
<SkPicture
>& picture
,
164 const gfx::Rect
& layer_rect
,
165 const gfx::Rect
& opaque_rect
,
166 const PixelRefMap
& pixel_refs
) :
167 layer_rect_(layer_rect
),
168 opaque_rect_(opaque_rect
),
170 pixel_refs_(pixel_refs
),
171 cell_size_(layer_rect
.size()) {
174 Picture::~Picture() {
175 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
176 TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
179 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
];
187 void Picture::CloneForDrawing(int num_threads
) {
188 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads
);
191 scoped_ptr
<SkPicture
[]> clones(new SkPicture
[num_threads
]);
192 picture_
->clone(&clones
[0], num_threads
);
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
])),
201 clones_
.push_back(clone
);
203 clone
->EmitTraceSnapshotAlias(this);
207 void Picture::Record(ContentLayerClient
* painter
,
208 const SkTileGridPicture::TileGridInfo
& tile_grid_info
) {
209 TRACE_EVENT1("cc", "Picture::Record",
210 "data", AsTraceableRecordData());
212 DCHECK(!tile_grid_info
.fTileInterval
.isEmpty());
213 picture_
= skia::AdoptRef(new SkTileGridPicture(
214 layer_rect_
.width(), layer_rect_
.height(), tile_grid_info
));
216 SkCanvas
* canvas
= picture_
->beginRecording(
218 layer_rect_
.height(),
219 SkPicture::kUsePathBoundsForClip_RecordingFlag
|
220 SkPicture::kOptimizeForClippedPlayback_RecordingFlag
);
223 canvas
->translate(SkFloatToScalar(-layer_rect_
.x()),
224 SkFloatToScalar(-layer_rect_
.y()));
226 SkRect layer_skrect
= SkRect::MakeXYWH(layer_rect_
.x(),
229 layer_rect_
.height());
230 canvas
->clipRect(layer_skrect
);
232 gfx::RectF opaque_layer_rect
;
234 painter
->PaintContents(canvas
, layer_rect_
, &opaque_layer_rect
);
237 picture_
->endRecording();
239 opaque_rect_
= gfx::ToEnclosedRect(opaque_layer_rect
);
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());
251 if (!WillPlayBackBitmaps())
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);
261 int min_x
= std::numeric_limits
<int>::max();
262 int min_y
= std::numeric_limits
<int>::max();
266 skia::DiscardablePixelRefList pixel_refs
;
267 skia::PixelRefUtils::GatherDiscardablePixelRefs(picture_
.get(), &pixel_refs
);
268 for (skia::DiscardablePixelRefList::const_iterator it
= pixel_refs
.begin();
269 it
!= pixel_refs
.end();
272 RoundDown(static_cast<int>(it
->pixel_ref_rect
.x()),
274 RoundDown(static_cast<int>(it
->pixel_ref_rect
.y()),
275 cell_size_
.height()));
277 RoundDown(static_cast<int>(std::ceil(it
->pixel_ref_rect
.right())),
279 RoundDown(static_cast<int>(std::ceil(it
->pixel_ref_rect
.bottom())),
280 cell_size_
.height()));
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
->pixel_ref
);
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());
295 min_pixel_cell_
= gfx::Point(min_x
, min_y
);
296 max_pixel_cell_
= gfx::Point(max_x
, max_y
);
301 SkDrawPictureCallback
* callback
,
302 const Region
& negated_content_region
,
303 float contents_scale
) {
308 AsTraceableRasterData(contents_scale
));
314 for (Region::Iterator
it(negated_content_region
); it
.has_rect(); it
.next())
315 canvas
->clipRect(gfx::RectToSkRect(it
.rect()), SkRegion::kDifference_Op
);
317 canvas
->scale(contents_scale
, contents_scale
);
318 canvas
->translate(layer_rect_
.x(), layer_rect_
.y());
319 picture_
->draw(canvas
, callback
);
321 canvas
->getClipDeviceBounds(&bounds
);
324 "cc", "Picture::Raster",
325 "num_pixels_rasterized", bounds
.width() * bounds
.height());
326 return bounds
.width() * bounds
.height();
329 void Picture::Replay(SkCanvas
* canvas
) {
330 TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
333 picture_
->draw(canvas
);
335 canvas
->getClipDeviceBounds(&bounds
);
336 TRACE_EVENT_END1("cc", "Picture::Replay",
337 "num_pixels_replayed", bounds
.width() * bounds
.height());
340 scoped_ptr
<base::Value
> Picture::AsValue() const {
341 SkDynamicMemoryWStream stream
;
343 // Serialize the picture.
344 picture_
->serialize(&stream
, &EncodeBitmap
);
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());
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
),
357 res
->SetString("skp64", b64_picture
);
358 return res
.PassAs
<base::Value
>();
361 void Picture::EmitTraceSnapshot() {
362 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
363 "cc::Picture", this, TracedPicture::AsTraceablePicture(this));
366 void Picture::EmitTraceSnapshotAlias(Picture
* original
) {
367 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
368 TRACE_DISABLED_BY_DEFAULT("cc.debug"),
371 TracedPicture::AsTraceablePictureAlias(original
));
374 base::LazyInstance
<Picture::PixelRefs
>
375 Picture::PixelRefIterator::empty_pixel_refs_
;
377 Picture::PixelRefIterator::PixelRefIterator()
379 current_pixel_refs_(empty_pixel_refs_
.Pointer()),
387 Picture::PixelRefIterator::PixelRefIterator(
388 const gfx::Rect
& rect
,
389 const Picture
* picture
)
391 current_pixel_refs_(empty_pixel_refs_
.Pointer()),
393 gfx::Rect layer_rect
= picture
->layer_rect_
;
394 gfx::Size cell_size
= picture
->cell_size_
;
395 DCHECK(!cell_size
.IsEmpty());
397 gfx::Rect
query_rect(rect
);
398 // Early out if the query rect doesn't intersect this picture.
399 if (!query_rect
.Intersects(layer_rect
)) {
400 min_point_
= gfx::Point(0, 0);
401 max_point_
= gfx::Point(0, 0);
407 // First, subtract the layer origin as cells are stored in layer space.
408 query_rect
.Offset(-layer_rect
.OffsetFromOrigin());
410 // We have to find a cell_size aligned point that corresponds to
411 // query_rect. Point is a multiple of cell_size.
412 min_point_
= gfx::Point(
413 RoundDown(query_rect
.x(), cell_size
.width()),
414 RoundDown(query_rect
.y(), cell_size
.height()));
415 max_point_
= gfx::Point(
416 RoundDown(query_rect
.right() - 1, cell_size
.width()),
417 RoundDown(query_rect
.bottom() - 1, cell_size
.height()));
419 // Limit the points to known pixel ref boundaries.
420 min_point_
= gfx::Point(
421 std::max(min_point_
.x(), picture
->min_pixel_cell_
.x()),
422 std::max(min_point_
.y(), picture
->min_pixel_cell_
.y()));
423 max_point_
= gfx::Point(
424 std::min(max_point_
.x(), picture
->max_pixel_cell_
.x()),
425 std::min(max_point_
.y(), picture
->max_pixel_cell_
.y()));
427 // Make the current x be cell_size.width() less than min point, so that
428 // the first increment will point at min_point_.
429 current_x_
= min_point_
.x() - cell_size
.width();
430 current_y_
= min_point_
.y();
431 if (current_y_
<= max_point_
.y())
435 Picture::PixelRefIterator::~PixelRefIterator() {
438 Picture::PixelRefIterator
& Picture::PixelRefIterator::operator++() {
440 // If we're not at the end of the list, then we have the next item.
441 if (current_index_
< current_pixel_refs_
->size())
444 DCHECK(current_y_
<= max_point_
.y());
446 gfx::Size cell_size
= picture_
->cell_size_
;
448 // Advance the current grid cell.
449 current_x_
+= cell_size
.width();
450 if (current_x_
> max_point_
.x()) {
451 current_y_
+= cell_size
.height();
452 current_x_
= min_point_
.x();
453 if (current_y_
> max_point_
.y()) {
454 current_pixel_refs_
= empty_pixel_refs_
.Pointer();
460 // If there are no pixel refs at this grid cell, keep incrementing.
461 PixelRefMapKey
key(current_x_
, current_y_
);
462 PixelRefMap::const_iterator iter
= picture_
->pixel_refs_
.find(key
);
463 if (iter
== picture_
->pixel_refs_
.end())
466 // We found a non-empty list: store it and get the first pixel ref.
467 current_pixel_refs_
= &iter
->second
;
474 scoped_refptr
<base::debug::ConvertableToTraceFormat
>
475 Picture::AsTraceableRasterData(float scale
) const {
476 scoped_ptr
<base::DictionaryValue
> raster_data(new base::DictionaryValue());
477 raster_data
->Set("picture_id", TracedValue::CreateIDRef(this).release());
478 raster_data
->SetDouble("scale", scale
);
479 return TracedValue::FromValue(raster_data
.release());
482 scoped_refptr
<base::debug::ConvertableToTraceFormat
>
483 Picture::AsTraceableRecordData() const {
484 scoped_ptr
<base::DictionaryValue
> record_data(new base::DictionaryValue());
485 record_data
->Set("picture_id", TracedValue::CreateIDRef(this).release());
486 record_data
->SetInteger("width", layer_rect_
.width());
487 record_data
->SetInteger("height", layer_rect_
.height());
488 return TracedValue::FromValue(record_data
.release());