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