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/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"
33
34namespace cc {
35
36namespace {
37
38SkData* EncodeBitmap(size_t* offset, const SkBitmap& bm) {
39  const int kJpegQuality = 80;
40  std::vector<unsigned char> data;
41
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;
49
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);
60  }
61
62  if (encoding_succeeded) {
63    *offset = 0;
64    return SkData::NewWithCopy(&data.front(), data.size());
65  }
66  return NULL;
67}
68
69bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
70  const unsigned char* data = static_cast<const unsigned char *>(buffer);
71
72  // Try PNG first.
73  if (gfx::PNGCodec::Decode(data, size, bm))
74    return true;
75
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;
81  }
82  return false;
83}
84
85}  // namespace
86
87scoped_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));
94
95  picture->Record(client, tile_grid_info, recording_mode);
96  if (gather_pixel_refs)
97    picture->GatherPixelRefs(tile_grid_info);
98
99  return picture;
100}
101
102Picture::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.
107}
108
109scoped_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;
114
115  std::string decoded;
116  base::Base64Decode(encoded, &decoded);
117  SkMemoryStream stream(decoded.data(), decoded.size());
118
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;
123
124  gfx::Rect layer_rect(skpicture->width(), skpicture->height());
125  return make_scoped_refptr(new Picture(skpicture, layer_rect));
126}
127
128scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
129  const base::DictionaryValue* value = NULL;
130  if (!raw_value->GetAsDictionary(&value))
131    return NULL;
132
133  // Decode the picture from base64.
134  std::string encoded;
135  if (!value->GetString("skp64", &encoded))
136    return NULL;
137
138  std::string decoded;
139  base::Base64Decode(encoded, &decoded);
140  SkMemoryStream stream(decoded.data(), decoded.size());
141
142  const base::Value* layer_rect_value = NULL;
143  if (!value->Get("params.layer_rect", &layer_rect_value))
144    return NULL;
145
146  gfx::Rect layer_rect;
147  if (!MathUtil::FromValue(layer_rect_value, &layer_rect))
148    return NULL;
149
150  // Read the picture. This creates an empty picture on failure.
151  SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
152  if (skpicture == NULL)
153    return NULL;
154
155  return make_scoped_refptr(new Picture(skpicture, layer_rect));
156}
157
158Picture::Picture(SkPicture* picture, const gfx::Rect& layer_rect)
159    : layer_rect_(layer_rect),
160      picture_(skia::AdoptRef(picture)),
161      cell_size_(layer_rect.size()) {
162}
163
164Picture::Picture(const skia::RefPtr<SkPicture>& picture,
165                 const gfx::Rect& layer_rect,
166                 const PixelRefMap& pixel_refs) :
167    layer_rect_(layer_rect),
168    picture_(picture),
169    pixel_refs_(pixel_refs),
170    cell_size_(layer_rect.size()) {
171}
172
173Picture::~Picture() {
174  TRACE_EVENT_OBJECT_DELETED_WITH_ID(
175    TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
176}
177
178bool Picture::IsSuitableForGpuRasterization() const {
179  DCHECK(picture_);
180
181  // TODO(alokp): SkPicture::suitableForGpuRasterization needs a GrContext.
182  // Ideally this GrContext should be the same as that for rasterizing this
183  // picture. But we are on the main thread while the rasterization context
184  // may be on the compositor or raster thread.
185  // SkPicture::suitableForGpuRasterization is not implemented yet.
186  // Pass a NULL context for now and discuss with skia folks if the context
187  // is really needed.
188  return picture_->suitableForGpuRasterization(NULL);
189}
190
191int Picture::ApproximateOpCount() const {
192  DCHECK(picture_);
193  return picture_->approximateOpCount();
194}
195
196bool Picture::HasText() const {
197  DCHECK(picture_);
198  return picture_->hasText();
199}
200
201void Picture::Record(ContentLayerClient* painter,
202                     const SkTileGridFactory::TileGridInfo& tile_grid_info,
203                     RecordingMode recording_mode) {
204  TRACE_EVENT2("cc",
205               "Picture::Record",
206               "data",
207               AsTraceableRecordData(),
208               "recording_mode",
209               recording_mode);
210
211  DCHECK(!picture_);
212  DCHECK(!tile_grid_info.fTileInterval.isEmpty());
213
214  SkTileGridFactory factory(tile_grid_info);
215  SkPictureRecorder recorder;
216
217  scoped_ptr<EXPERIMENTAL::SkRecording> recording;
218
219  skia::RefPtr<SkCanvas> canvas;
220  canvas = skia::SharePtr(recorder.beginRecording(
221      layer_rect_.width(), layer_rect_.height(), &factory));
222
223  ContentLayerClient::GraphicsContextStatus graphics_context_status =
224      ContentLayerClient::GRAPHICS_CONTEXT_ENABLED;
225
226  switch (recording_mode) {
227    case RECORD_NORMALLY:
228      // Already setup for normal recording.
229      break;
230    case RECORD_WITH_SK_NULL_CANVAS:
231      canvas = skia::AdoptRef(SkCreateNullCanvas());
232      break;
233    case RECORD_WITH_PAINTING_DISABLED:
234      // We pass a disable flag through the paint calls when perfromance
235      // testing (the only time this case should ever arise) when we want to
236      // prevent the Blink GraphicsContext object from consuming any compute
237      // time.
238      canvas = skia::AdoptRef(SkCreateNullCanvas());
239      graphics_context_status = ContentLayerClient::GRAPHICS_CONTEXT_DISABLED;
240      break;
241    case RECORD_WITH_SKRECORD:
242      recording.reset(new EXPERIMENTAL::SkRecording(layer_rect_.width(),
243                                                    layer_rect_.height()));
244      canvas = skia::SharePtr(recording->canvas());
245      break;
246    default:
247      NOTREACHED();
248  }
249
250  canvas->save();
251  canvas->translate(SkFloatToScalar(-layer_rect_.x()),
252                    SkFloatToScalar(-layer_rect_.y()));
253
254  SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
255                                         layer_rect_.y(),
256                                         layer_rect_.width(),
257                                         layer_rect_.height());
258  canvas->clipRect(layer_skrect);
259
260  painter->PaintContents(canvas.get(), layer_rect_, graphics_context_status);
261
262  canvas->restore();
263  picture_ = skia::AdoptRef(recorder.endRecording());
264  DCHECK(picture_);
265
266  if (recording) {
267    // SkRecording requires it's the only one holding onto canvas before we
268    // may call releasePlayback().  (This helps enforce thread-safety.)
269    canvas.clear();
270    playback_.reset(recording->releasePlayback());
271  }
272
273  EmitTraceSnapshot();
274}
275
276void Picture::GatherPixelRefs(
277    const SkTileGridFactory::TileGridInfo& tile_grid_info) {
278  TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
279               "width", layer_rect_.width(),
280               "height", layer_rect_.height());
281
282  DCHECK(picture_);
283  DCHECK(pixel_refs_.empty());
284  if (!WillPlayBackBitmaps())
285    return;
286  cell_size_ = gfx::Size(
287      tile_grid_info.fTileInterval.width() +
288          2 * tile_grid_info.fMargin.width(),
289      tile_grid_info.fTileInterval.height() +
290          2 * tile_grid_info.fMargin.height());
291  DCHECK_GT(cell_size_.width(), 0);
292  DCHECK_GT(cell_size_.height(), 0);
293
294  int min_x = std::numeric_limits<int>::max();
295  int min_y = std::numeric_limits<int>::max();
296  int max_x = 0;
297  int max_y = 0;
298
299  skia::DiscardablePixelRefList pixel_refs;
300  skia::PixelRefUtils::GatherDiscardablePixelRefs(picture_.get(), &pixel_refs);
301  for (skia::DiscardablePixelRefList::const_iterator it = pixel_refs.begin();
302       it != pixel_refs.end();
303       ++it) {
304    gfx::Point min(
305        RoundDown(static_cast<int>(it->pixel_ref_rect.x()),
306                  cell_size_.width()),
307        RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
308                  cell_size_.height()));
309    gfx::Point max(
310        RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
311                  cell_size_.width()),
312        RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
313                  cell_size_.height()));
314
315    for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
316      for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
317        PixelRefMapKey key(x, y);
318        pixel_refs_[key].push_back(it->pixel_ref);
319      }
320    }
321
322    min_x = std::min(min_x, min.x());
323    min_y = std::min(min_y, min.y());
324    max_x = std::max(max_x, max.x());
325    max_y = std::max(max_y, max.y());
326  }
327
328  min_pixel_cell_ = gfx::Point(min_x, min_y);
329  max_pixel_cell_ = gfx::Point(max_x, max_y);
330}
331
332int Picture::Raster(SkCanvas* canvas,
333                    SkDrawPictureCallback* callback,
334                    const Region& negated_content_region,
335                    float contents_scale) const {
336  TRACE_EVENT_BEGIN1(
337      "cc",
338      "Picture::Raster",
339      "data",
340      AsTraceableRasterData(contents_scale));
341
342  DCHECK(picture_);
343
344  canvas->save();
345
346  for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
347    canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
348
349  canvas->scale(contents_scale, contents_scale);
350  canvas->translate(layer_rect_.x(), layer_rect_.y());
351  if (playback_) {
352    playback_->draw(canvas);
353  } else if (callback) {
354    // If we have a callback, we need to call |draw()|, |drawPicture()| doesn't
355    // take a callback.  This is used by |AnalysisCanvas| to early out.
356    picture_->draw(canvas, callback);
357  } else {
358    // Prefer to call |drawPicture()| on the canvas since it could place the
359    // entire picture on the canvas instead of parsing the skia operations.
360    canvas->drawPicture(picture_.get());
361  }
362  SkIRect bounds;
363  canvas->getClipDeviceBounds(&bounds);
364  canvas->restore();
365  TRACE_EVENT_END1(
366      "cc", "Picture::Raster",
367      "num_pixels_rasterized", bounds.width() * bounds.height());
368  return bounds.width() * bounds.height();
369}
370
371void Picture::Replay(SkCanvas* canvas) {
372  TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
373  DCHECK(picture_);
374
375  if (playback_) {
376    playback_->draw(canvas);
377  } else {
378    picture_->draw(canvas);
379  }
380  SkIRect bounds;
381  canvas->getClipDeviceBounds(&bounds);
382  TRACE_EVENT_END1("cc", "Picture::Replay",
383                   "num_pixels_replayed", bounds.width() * bounds.height());
384}
385
386scoped_ptr<base::Value> Picture::AsValue() const {
387  SkDynamicMemoryWStream stream;
388
389  if (playback_) {
390    // SkPlayback can't serialize itself, so re-record into an SkPicture.
391    SkPictureRecorder recorder;
392    skia::RefPtr<SkCanvas> canvas(skia::SharePtr(recorder.beginRecording(
393        layer_rect_.width(),
394        layer_rect_.height(),
395        NULL)));  // Default (no) bounding-box hierarchy is fastest.
396    playback_->draw(canvas.get());
397    skia::RefPtr<SkPicture> picture(skia::AdoptRef(recorder.endRecording()));
398    picture->serialize(&stream, &EncodeBitmap);
399  } else {
400    // Serialize the picture.
401    picture_->serialize(&stream, &EncodeBitmap);
402  }
403
404  // Encode the picture as base64.
405  scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
406  res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
407
408  size_t serialized_size = stream.bytesWritten();
409  scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
410  stream.copyTo(serialized_picture.get());
411  std::string b64_picture;
412  base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
413                     &b64_picture);
414  res->SetString("skp64", b64_picture);
415  return res.PassAs<base::Value>();
416}
417
418void Picture::EmitTraceSnapshot() const {
419  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
420      TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
421          "devtools.timeline.picture"),
422      "cc::Picture",
423      this,
424      TracedPicture::AsTraceablePicture(this));
425}
426
427void Picture::EmitTraceSnapshotAlias(Picture* original) const {
428  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
429      TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
430          "devtools.timeline.picture"),
431      "cc::Picture",
432      this,
433      TracedPicture::AsTraceablePictureAlias(original));
434}
435
436base::LazyInstance<Picture::PixelRefs>
437    Picture::PixelRefIterator::empty_pixel_refs_;
438
439Picture::PixelRefIterator::PixelRefIterator()
440    : picture_(NULL),
441      current_pixel_refs_(empty_pixel_refs_.Pointer()),
442      current_index_(0),
443      min_point_(-1, -1),
444      max_point_(-1, -1),
445      current_x_(0),
446      current_y_(0) {
447}
448
449Picture::PixelRefIterator::PixelRefIterator(
450    const gfx::Rect& rect,
451    const Picture* picture)
452    : picture_(picture),
453      current_pixel_refs_(empty_pixel_refs_.Pointer()),
454      current_index_(0) {
455  gfx::Rect layer_rect = picture->layer_rect_;
456  gfx::Size cell_size = picture->cell_size_;
457  DCHECK(!cell_size.IsEmpty());
458
459  gfx::Rect query_rect(rect);
460  // Early out if the query rect doesn't intersect this picture.
461  if (!query_rect.Intersects(layer_rect)) {
462    min_point_ = gfx::Point(0, 0);
463    max_point_ = gfx::Point(0, 0);
464    current_x_ = 1;
465    current_y_ = 1;
466    return;
467  }
468
469  // First, subtract the layer origin as cells are stored in layer space.
470  query_rect.Offset(-layer_rect.OffsetFromOrigin());
471
472  // We have to find a cell_size aligned point that corresponds to
473  // query_rect. Point is a multiple of cell_size.
474  min_point_ = gfx::Point(
475      RoundDown(query_rect.x(), cell_size.width()),
476      RoundDown(query_rect.y(), cell_size.height()));
477  max_point_ = gfx::Point(
478      RoundDown(query_rect.right() - 1, cell_size.width()),
479      RoundDown(query_rect.bottom() - 1, cell_size.height()));
480
481  // Limit the points to known pixel ref boundaries.
482  min_point_ = gfx::Point(
483      std::max(min_point_.x(), picture->min_pixel_cell_.x()),
484      std::max(min_point_.y(), picture->min_pixel_cell_.y()));
485  max_point_ = gfx::Point(
486      std::min(max_point_.x(), picture->max_pixel_cell_.x()),
487      std::min(max_point_.y(), picture->max_pixel_cell_.y()));
488
489  // Make the current x be cell_size.width() less than min point, so that
490  // the first increment will point at min_point_.
491  current_x_ = min_point_.x() - cell_size.width();
492  current_y_ = min_point_.y();
493  if (current_y_ <= max_point_.y())
494    ++(*this);
495}
496
497Picture::PixelRefIterator::~PixelRefIterator() {
498}
499
500Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() {
501  ++current_index_;
502  // If we're not at the end of the list, then we have the next item.
503  if (current_index_ < current_pixel_refs_->size())
504    return *this;
505
506  DCHECK(current_y_ <= max_point_.y());
507  while (true) {
508    gfx::Size cell_size = picture_->cell_size_;
509
510    // Advance the current grid cell.
511    current_x_ += cell_size.width();
512    if (current_x_ > max_point_.x()) {
513      current_y_ += cell_size.height();
514      current_x_ = min_point_.x();
515      if (current_y_ > max_point_.y()) {
516        current_pixel_refs_ = empty_pixel_refs_.Pointer();
517        current_index_ = 0;
518        break;
519      }
520    }
521
522    // If there are no pixel refs at this grid cell, keep incrementing.
523    PixelRefMapKey key(current_x_, current_y_);
524    PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key);
525    if (iter == picture_->pixel_refs_.end())
526      continue;
527
528    // We found a non-empty list: store it and get the first pixel ref.
529    current_pixel_refs_ = &iter->second;
530    current_index_ = 0;
531    break;
532  }
533  return *this;
534}
535
536scoped_refptr<base::debug::ConvertableToTraceFormat>
537    Picture::AsTraceableRasterData(float scale) const {
538  scoped_refptr<base::debug::TracedValue> raster_data =
539      new base::debug::TracedValue();
540  TracedValue::SetIDRef(this, raster_data.get(), "picture_id");
541  raster_data->SetDouble("scale", scale);
542  return raster_data;
543}
544
545scoped_refptr<base::debug::ConvertableToTraceFormat>
546    Picture::AsTraceableRecordData() const {
547  scoped_refptr<base::debug::TracedValue> record_data =
548      new base::debug::TracedValue();
549  TracedValue::SetIDRef(this, record_data.get(), "picture_id");
550  record_data->BeginArray("layer_rect");
551  MathUtil::AddToTracedValue(layer_rect_, record_data.get());
552  record_data->EndArray();
553  return record_data;
554}
555
556}  // namespace cc
557