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