[NaCl SDK]: use standard __BEGIN_DECLS macros in sys/select.h
[chromium-blink-merge.git] / cc / resources / picture.cc
blob5be80b150271efa396716e3c114e610bb606eab1
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/traced_picture.h"
18 #include "cc/debug/traced_value.h"
19 #include "cc/layers/content_layer_client.h"
20 #include "skia/ext/pixel_ref_utils.h"
21 #include "third_party/skia/include/core/SkCanvas.h"
22 #include "third_party/skia/include/core/SkData.h"
23 #include "third_party/skia/include/core/SkDrawFilter.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/rect_conversions.h"
32 #include "ui/gfx/skia_util.h"
34 namespace cc {
36 namespace {
38 SkData* EncodeBitmap(size_t* offset, const SkBitmap& bm) {
39 const int kJpegQuality = 80;
40 std::vector<unsigned char> data;
42 // If bitmap is opaque, encode as JPEG.
43 // Otherwise encode as PNG.
44 bool encoding_succeeded = false;
45 if (bm.isOpaque()) {
46 SkAutoLockPixels lock_bitmap(bm);
47 if (bm.empty())
48 return NULL;
50 encoding_succeeded = gfx::JPEGCodec::Encode(
51 reinterpret_cast<unsigned char*>(bm.getAddr32(0, 0)),
52 gfx::JPEGCodec::FORMAT_SkBitmap,
53 bm.width(),
54 bm.height(),
55 bm.rowBytes(),
56 kJpegQuality,
57 &data);
58 } else {
59 encoding_succeeded = gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &data);
62 if (encoding_succeeded) {
63 *offset = 0;
64 return SkData::NewWithCopy(&data.front(), data.size());
66 return NULL;
69 bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
70 const unsigned char* data = static_cast<const unsigned char *>(buffer);
72 // Try PNG first.
73 if (gfx::PNGCodec::Decode(data, size, bm))
74 return true;
76 // Try JPEG.
77 scoped_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodec::Decode(data, size));
78 if (decoded_jpeg) {
79 *bm = *decoded_jpeg;
80 return true;
82 return false;
85 } // namespace
87 scoped_refptr<Picture> Picture::Create(
88 const gfx::Rect& layer_rect,
89 ContentLayerClient* client,
90 const SkTileGridFactory::TileGridInfo& tile_grid_info,
91 bool gather_pixel_refs,
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);
99 return picture;
102 Picture::Picture(const gfx::Rect& layer_rect)
103 : layer_rect_(layer_rect),
104 cell_size_(layer_rect.size()) {
105 // Instead of recording a trace event for object creation here, we wait for
106 // the picture to be recorded in Picture::Record.
109 scoped_refptr<Picture> Picture::CreateFromSkpValue(const base::Value* value) {
110 // Decode the picture from base64.
111 std::string encoded;
112 if (!value->GetAsString(&encoded))
113 return NULL;
115 std::string decoded;
116 base::Base64Decode(encoded, &decoded);
117 SkMemoryStream stream(decoded.data(), decoded.size());
119 // Read the picture. This creates an empty picture on failure.
120 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
121 if (skpicture == NULL)
122 return NULL;
124 gfx::Rect layer_rect(skpicture->width(), skpicture->height());
125 gfx::Rect opaque_rect(skpicture->width(), skpicture->height());
127 return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
130 scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
131 const base::DictionaryValue* value = NULL;
132 if (!raw_value->GetAsDictionary(&value))
133 return NULL;
135 // Decode the picture from base64.
136 std::string encoded;
137 if (!value->GetString("skp64", &encoded))
138 return NULL;
140 std::string decoded;
141 base::Base64Decode(encoded, &decoded);
142 SkMemoryStream stream(decoded.data(), decoded.size());
144 const base::Value* layer_rect_value = NULL;
145 if (!value->Get("params.layer_rect", &layer_rect_value))
146 return NULL;
148 gfx::Rect layer_rect;
149 if (!MathUtil::FromValue(layer_rect_value, &layer_rect))
150 return NULL;
152 const base::Value* opaque_rect_value = NULL;
153 if (!value->Get("params.opaque_rect", &opaque_rect_value))
154 return NULL;
156 gfx::Rect opaque_rect;
157 if (!MathUtil::FromValue(opaque_rect_value, &opaque_rect))
158 return NULL;
160 // Read the picture. This creates an empty picture on failure.
161 SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
162 if (skpicture == NULL)
163 return NULL;
165 return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
168 Picture::Picture(SkPicture* picture,
169 const gfx::Rect& layer_rect,
170 const gfx::Rect& opaque_rect) :
171 layer_rect_(layer_rect),
172 opaque_rect_(opaque_rect),
173 picture_(skia::AdoptRef(picture)),
174 cell_size_(layer_rect.size()) {
177 Picture::Picture(const skia::RefPtr<SkPicture>& picture,
178 const gfx::Rect& layer_rect,
179 const gfx::Rect& opaque_rect,
180 const PixelRefMap& pixel_refs) :
181 layer_rect_(layer_rect),
182 opaque_rect_(opaque_rect),
183 picture_(picture),
184 pixel_refs_(pixel_refs),
185 cell_size_(layer_rect.size()) {
188 Picture::~Picture() {
189 TRACE_EVENT_OBJECT_DELETED_WITH_ID(
190 TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
193 bool Picture::IsSuitableForGpuRasterization() const {
194 DCHECK(picture_);
196 // TODO(alokp): SkPicture::suitableForGpuRasterization needs a GrContext.
197 // Ideally this GrContext should be the same as that for rasterizing this
198 // picture. But we are on the main thread while the rasterization context
199 // may be on the compositor or raster thread.
200 // SkPicture::suitableForGpuRasterization is not implemented yet.
201 // Pass a NULL context for now and discuss with skia folks if the context
202 // is really needed.
203 return picture_->suitableForGpuRasterization(NULL);
206 int Picture::ApproximateOpCount() const {
207 DCHECK(picture_);
208 return picture_->approximateOpCount();
211 bool Picture::HasText() const {
212 DCHECK(picture_);
213 return picture_->hasText();
216 void Picture::Record(ContentLayerClient* painter,
217 const SkTileGridFactory::TileGridInfo& tile_grid_info,
218 RecordingMode recording_mode) {
219 TRACE_EVENT2("cc",
220 "Picture::Record",
221 "data",
222 AsTraceableRecordData(),
223 "recording_mode",
224 recording_mode);
226 DCHECK(!picture_);
227 DCHECK(!tile_grid_info.fTileInterval.isEmpty());
229 SkTileGridFactory factory(tile_grid_info);
230 SkPictureRecorder recorder;
232 scoped_ptr<EXPERIMENTAL::SkRecording> recording;
234 skia::RefPtr<SkCanvas> canvas;
235 canvas = skia::SharePtr(recorder.beginRecording(
236 layer_rect_.width(), layer_rect_.height(), &factory));
238 ContentLayerClient::GraphicsContextStatus graphics_context_status =
239 ContentLayerClient::GRAPHICS_CONTEXT_ENABLED;
241 switch (recording_mode) {
242 case RECORD_NORMALLY:
243 // Already setup for normal recording.
244 break;
245 case RECORD_WITH_SK_NULL_CANVAS:
246 canvas = skia::AdoptRef(SkCreateNullCanvas());
247 break;
248 case RECORD_WITH_PAINTING_DISABLED:
249 // We pass a disable flag through the paint calls when perfromance
250 // testing (the only time this case should ever arise) when we want to
251 // prevent the Blink GraphicsContext object from consuming any compute
252 // time.
253 canvas = skia::AdoptRef(SkCreateNullCanvas());
254 graphics_context_status = ContentLayerClient::GRAPHICS_CONTEXT_DISABLED;
255 break;
256 case RECORD_WITH_SKRECORD:
257 recording.reset(new EXPERIMENTAL::SkRecording(layer_rect_.width(),
258 layer_rect_.height()));
259 canvas = skia::SharePtr(recording->canvas());
260 break;
261 default:
262 NOTREACHED();
265 canvas->save();
266 canvas->translate(SkFloatToScalar(-layer_rect_.x()),
267 SkFloatToScalar(-layer_rect_.y()));
269 SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
270 layer_rect_.y(),
271 layer_rect_.width(),
272 layer_rect_.height());
273 canvas->clipRect(layer_skrect);
275 gfx::RectF opaque_layer_rect;
276 painter->PaintContents(
277 canvas.get(), layer_rect_, &opaque_layer_rect, graphics_context_status);
279 canvas->restore();
280 picture_ = skia::AdoptRef(recorder.endRecording());
281 DCHECK(picture_);
283 if (recording) {
284 // SkRecording requires it's the only one holding onto canvas before we
285 // may call releasePlayback(). (This helps enforce thread-safety.)
286 canvas.clear();
287 playback_.reset(recording->releasePlayback());
290 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
292 EmitTraceSnapshot();
295 void Picture::GatherPixelRefs(
296 const SkTileGridFactory::TileGridInfo& tile_grid_info) {
297 TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
298 "width", layer_rect_.width(),
299 "height", layer_rect_.height());
301 DCHECK(picture_);
302 DCHECK(pixel_refs_.empty());
303 if (!WillPlayBackBitmaps())
304 return;
305 cell_size_ = gfx::Size(
306 tile_grid_info.fTileInterval.width() +
307 2 * tile_grid_info.fMargin.width(),
308 tile_grid_info.fTileInterval.height() +
309 2 * tile_grid_info.fMargin.height());
310 DCHECK_GT(cell_size_.width(), 0);
311 DCHECK_GT(cell_size_.height(), 0);
313 int min_x = std::numeric_limits<int>::max();
314 int min_y = std::numeric_limits<int>::max();
315 int max_x = 0;
316 int max_y = 0;
318 skia::DiscardablePixelRefList pixel_refs;
319 skia::PixelRefUtils::GatherDiscardablePixelRefs(picture_.get(), &pixel_refs);
320 for (skia::DiscardablePixelRefList::const_iterator it = pixel_refs.begin();
321 it != pixel_refs.end();
322 ++it) {
323 gfx::Point min(
324 RoundDown(static_cast<int>(it->pixel_ref_rect.x()),
325 cell_size_.width()),
326 RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
327 cell_size_.height()));
328 gfx::Point max(
329 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
330 cell_size_.width()),
331 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
332 cell_size_.height()));
334 for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
335 for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
336 PixelRefMapKey key(x, y);
337 pixel_refs_[key].push_back(it->pixel_ref);
341 min_x = std::min(min_x, min.x());
342 min_y = std::min(min_y, min.y());
343 max_x = std::max(max_x, max.x());
344 max_y = std::max(max_y, max.y());
347 min_pixel_cell_ = gfx::Point(min_x, min_y);
348 max_pixel_cell_ = gfx::Point(max_x, max_y);
351 int Picture::Raster(SkCanvas* canvas,
352 SkDrawPictureCallback* callback,
353 const Region& negated_content_region,
354 float contents_scale) const {
355 TRACE_EVENT_BEGIN1(
356 "cc",
357 "Picture::Raster",
358 "data",
359 AsTraceableRasterData(contents_scale));
361 DCHECK(picture_);
363 canvas->save();
365 for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
366 canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
368 canvas->scale(contents_scale, contents_scale);
369 canvas->translate(layer_rect_.x(), layer_rect_.y());
370 if (playback_) {
371 playback_->draw(canvas);
372 } else {
373 picture_->draw(canvas, callback);
375 SkIRect bounds;
376 canvas->getClipDeviceBounds(&bounds);
377 canvas->restore();
378 TRACE_EVENT_END1(
379 "cc", "Picture::Raster",
380 "num_pixels_rasterized", bounds.width() * bounds.height());
381 return bounds.width() * bounds.height();
384 void Picture::Replay(SkCanvas* canvas) {
385 TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
386 DCHECK(picture_);
388 if (playback_) {
389 playback_->draw(canvas);
390 } else {
391 picture_->draw(canvas);
393 SkIRect bounds;
394 canvas->getClipDeviceBounds(&bounds);
395 TRACE_EVENT_END1("cc", "Picture::Replay",
396 "num_pixels_replayed", bounds.width() * bounds.height());
399 scoped_ptr<base::Value> Picture::AsValue() const {
400 SkDynamicMemoryWStream stream;
402 if (playback_) {
403 // SkPlayback can't serialize itself, so re-record into an SkPicture.
404 SkPictureRecorder recorder;
405 skia::RefPtr<SkCanvas> canvas(skia::SharePtr(recorder.beginRecording(
406 layer_rect_.width(),
407 layer_rect_.height(),
408 NULL))); // Default (no) bounding-box hierarchy is fastest.
409 playback_->draw(canvas.get());
410 skia::RefPtr<SkPicture> picture(skia::AdoptRef(recorder.endRecording()));
411 picture->serialize(&stream, &EncodeBitmap);
412 } else {
413 // Serialize the picture.
414 picture_->serialize(&stream, &EncodeBitmap);
417 // Encode the picture as base64.
418 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
419 res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
420 res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release());
422 size_t serialized_size = stream.bytesWritten();
423 scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
424 stream.copyTo(serialized_picture.get());
425 std::string b64_picture;
426 base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
427 &b64_picture);
428 res->SetString("skp64", b64_picture);
429 return res.PassAs<base::Value>();
432 void Picture::EmitTraceSnapshot() const {
433 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
434 TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
435 "devtools.timeline.picture"),
436 "cc::Picture",
437 this,
438 TracedPicture::AsTraceablePicture(this));
441 void Picture::EmitTraceSnapshotAlias(Picture* original) const {
442 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
443 TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
444 "devtools.timeline.picture"),
445 "cc::Picture",
446 this,
447 TracedPicture::AsTraceablePictureAlias(original));
450 base::LazyInstance<Picture::PixelRefs>
451 Picture::PixelRefIterator::empty_pixel_refs_;
453 Picture::PixelRefIterator::PixelRefIterator()
454 : picture_(NULL),
455 current_pixel_refs_(empty_pixel_refs_.Pointer()),
456 current_index_(0),
457 min_point_(-1, -1),
458 max_point_(-1, -1),
459 current_x_(0),
460 current_y_(0) {
463 Picture::PixelRefIterator::PixelRefIterator(
464 const gfx::Rect& rect,
465 const Picture* picture)
466 : picture_(picture),
467 current_pixel_refs_(empty_pixel_refs_.Pointer()),
468 current_index_(0) {
469 gfx::Rect layer_rect = picture->layer_rect_;
470 gfx::Size cell_size = picture->cell_size_;
471 DCHECK(!cell_size.IsEmpty());
473 gfx::Rect query_rect(rect);
474 // Early out if the query rect doesn't intersect this picture.
475 if (!query_rect.Intersects(layer_rect)) {
476 min_point_ = gfx::Point(0, 0);
477 max_point_ = gfx::Point(0, 0);
478 current_x_ = 1;
479 current_y_ = 1;
480 return;
483 // First, subtract the layer origin as cells are stored in layer space.
484 query_rect.Offset(-layer_rect.OffsetFromOrigin());
486 // We have to find a cell_size aligned point that corresponds to
487 // query_rect. Point is a multiple of cell_size.
488 min_point_ = gfx::Point(
489 RoundDown(query_rect.x(), cell_size.width()),
490 RoundDown(query_rect.y(), cell_size.height()));
491 max_point_ = gfx::Point(
492 RoundDown(query_rect.right() - 1, cell_size.width()),
493 RoundDown(query_rect.bottom() - 1, cell_size.height()));
495 // Limit the points to known pixel ref boundaries.
496 min_point_ = gfx::Point(
497 std::max(min_point_.x(), picture->min_pixel_cell_.x()),
498 std::max(min_point_.y(), picture->min_pixel_cell_.y()));
499 max_point_ = gfx::Point(
500 std::min(max_point_.x(), picture->max_pixel_cell_.x()),
501 std::min(max_point_.y(), picture->max_pixel_cell_.y()));
503 // Make the current x be cell_size.width() less than min point, so that
504 // the first increment will point at min_point_.
505 current_x_ = min_point_.x() - cell_size.width();
506 current_y_ = min_point_.y();
507 if (current_y_ <= max_point_.y())
508 ++(*this);
511 Picture::PixelRefIterator::~PixelRefIterator() {
514 Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() {
515 ++current_index_;
516 // If we're not at the end of the list, then we have the next item.
517 if (current_index_ < current_pixel_refs_->size())
518 return *this;
520 DCHECK(current_y_ <= max_point_.y());
521 while (true) {
522 gfx::Size cell_size = picture_->cell_size_;
524 // Advance the current grid cell.
525 current_x_ += cell_size.width();
526 if (current_x_ > max_point_.x()) {
527 current_y_ += cell_size.height();
528 current_x_ = min_point_.x();
529 if (current_y_ > max_point_.y()) {
530 current_pixel_refs_ = empty_pixel_refs_.Pointer();
531 current_index_ = 0;
532 break;
536 // If there are no pixel refs at this grid cell, keep incrementing.
537 PixelRefMapKey key(current_x_, current_y_);
538 PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key);
539 if (iter == picture_->pixel_refs_.end())
540 continue;
542 // We found a non-empty list: store it and get the first pixel ref.
543 current_pixel_refs_ = &iter->second;
544 current_index_ = 0;
545 break;
547 return *this;
550 scoped_refptr<base::debug::ConvertableToTraceFormat>
551 Picture::AsTraceableRasterData(float scale) const {
552 scoped_refptr<base::debug::TracedValue> raster_data =
553 new base::debug::TracedValue();
554 TracedValue::SetIDRef(this, raster_data.get(), "picture_id");
555 raster_data->SetDouble("scale", scale);
556 return raster_data;
559 scoped_refptr<base::debug::ConvertableToTraceFormat>
560 Picture::AsTraceableRecordData() const {
561 scoped_refptr<base::debug::TracedValue> record_data =
562 new base::debug::TracedValue();
563 TracedValue::SetIDRef(this, record_data.get(), "picture_id");
564 record_data->BeginArray("layer_rect");
565 MathUtil::AddToTracedValue(layer_rect_, record_data.get());
566 record_data->EndArray();
567 return record_data;
570 } // namespace cc