picture.cc revision 1e9bf3e0803691d0a228da41fc608347b6db4340
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/lazy_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"
30
31namespace cc {
32
33namespace {
34
35SkData* EncodeBitmap(size_t* offset, const SkBitmap& bm) {
36  const int kJpegQuality = 80;
37  std::vector<unsigned char> data;
38
39  // If bitmap is opaque, encode as JPEG.
40  // Otherwise encode as PNG.
41  bool encoding_succeeded = false;
42  if (bm.isOpaque()) {
43    SkAutoLockPixels lock_bitmap(bm);
44    if (bm.empty())
45      return NULL;
46
47    encoding_succeeded = gfx::JPEGCodec::Encode(
48        reinterpret_cast<unsigned char*>(bm.getAddr32(0, 0)),
49        gfx::JPEGCodec::FORMAT_SkBitmap,
50        bm.width(),
51        bm.height(),
52        bm.rowBytes(),
53        kJpegQuality,
54        &data);
55  } else {
56    encoding_succeeded = gfx::PNGCodec::EncodeBGRASkBitmap(bm, false, &data);
57  }
58
59  if (encoding_succeeded) {
60    *offset = 0;
61    return SkData::NewWithCopy(&data.front(), data.size());
62  }
63  return NULL;
64}
65
66bool DecodeBitmap(const void* buffer, size_t size, SkBitmap* bm) {
67  const unsigned char* data = static_cast<const unsigned char *>(buffer);
68
69  // Try PNG first.
70  if (gfx::PNGCodec::Decode(data, size, bm))
71    return true;
72
73  // Try JPEG.
74  scoped_ptr<SkBitmap> decoded_jpeg(gfx::JPEGCodec::Decode(data, size));
75  if (decoded_jpeg) {
76    *bm = *decoded_jpeg;
77    return true;
78  }
79  return false;
80}
81
82}  // namespace
83
84scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) {
85  return make_scoped_refptr(new Picture(layer_rect));
86}
87
88Picture::Picture(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.
93}
94
95scoped_refptr<Picture> Picture::CreateFromSkpValue(const base::Value* value) {
96  // Decode the picture from base64.
97  std::string encoded;
98  if (!value->GetAsString(&encoded))
99    return NULL;
100
101  std::string decoded;
102  base::Base64Decode(encoded, &decoded);
103  SkMemoryStream stream(decoded.data(), decoded.size());
104
105  // Read the picture. This creates an empty picture on failure.
106  SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
107  if (skpicture == NULL)
108    return NULL;
109
110  gfx::Rect layer_rect(skpicture->width(), skpicture->height());
111  gfx::Rect opaque_rect(skpicture->width(), skpicture->height());
112
113  return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
114}
115
116scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* raw_value) {
117  const base::DictionaryValue* value = NULL;
118  if (!raw_value->GetAsDictionary(&value))
119    return NULL;
120
121  // Decode the picture from base64.
122  std::string encoded;
123  if (!value->GetString("skp64", &encoded))
124    return NULL;
125
126  std::string decoded;
127  base::Base64Decode(encoded, &decoded);
128  SkMemoryStream stream(decoded.data(), decoded.size());
129
130  const base::Value* layer_rect_value = NULL;
131  if (!value->Get("params.layer_rect", &layer_rect_value))
132    return NULL;
133
134  gfx::Rect layer_rect;
135  if (!MathUtil::FromValue(layer_rect_value, &layer_rect))
136    return NULL;
137
138  const base::Value* opaque_rect_value = NULL;
139  if (!value->Get("params.opaque_rect", &opaque_rect_value))
140    return NULL;
141
142  gfx::Rect opaque_rect;
143  if (!MathUtil::FromValue(opaque_rect_value, &opaque_rect))
144    return NULL;
145
146  // Read the picture. This creates an empty picture on failure.
147  SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
148  if (skpicture == NULL)
149    return NULL;
150
151  return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
152}
153
154Picture::Picture(SkPicture* picture,
155                 gfx::Rect layer_rect,
156                 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()) {
161}
162
163Picture::Picture(const skia::RefPtr<SkPicture>& picture,
164                 gfx::Rect layer_rect,
165                 gfx::Rect opaque_rect,
166                 const PixelRefMap& pixel_refs) :
167    layer_rect_(layer_rect),
168    opaque_rect_(opaque_rect),
169    picture_(picture),
170    pixel_refs_(pixel_refs),
171    cell_size_(layer_rect.size()) {
172}
173
174Picture::~Picture() {
175  TRACE_EVENT_OBJECT_DELETED_WITH_ID(
176    TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
177}
178
179scoped_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];
185}
186
187void Picture::CloneForDrawing(int num_threads) {
188  TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads);
189
190  DCHECK(picture_);
191  scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]);
192  picture_->clone(&clones[0], num_threads);
193
194  clones_.clear();
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])),
198                    layer_rect_,
199                    opaque_rect_,
200                    pixel_refs_));
201    clones_.push_back(clone);
202
203    clone->EmitTraceSnapshotAlias(this);
204  }
205}
206
207void Picture::Record(ContentLayerClient* painter,
208                     const SkTileGridPicture::TileGridInfo& tile_grid_info) {
209  TRACE_EVENT1("cc", "Picture::Record",
210               "data", AsTraceableRecordData());
211
212  DCHECK(!tile_grid_info.fTileInterval.isEmpty());
213  picture_ = skia::AdoptRef(new SkTileGridPicture(
214      layer_rect_.width(), layer_rect_.height(), tile_grid_info));
215
216  SkCanvas* canvas = picture_->beginRecording(
217      layer_rect_.width(),
218      layer_rect_.height(),
219      SkPicture::kUsePathBoundsForClip_RecordingFlag |
220      SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
221
222  canvas->save();
223  canvas->translate(SkFloatToScalar(-layer_rect_.x()),
224                    SkFloatToScalar(-layer_rect_.y()));
225
226  SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
227                                         layer_rect_.y(),
228                                         layer_rect_.width(),
229                                         layer_rect_.height());
230  canvas->clipRect(layer_skrect);
231
232  gfx::RectF opaque_layer_rect;
233
234  painter->PaintContents(canvas, layer_rect_, &opaque_layer_rect);
235
236  canvas->restore();
237  picture_->endRecording();
238
239  opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
240
241  EmitTraceSnapshot();
242}
243
244void 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());
249
250  DCHECK(picture_);
251  cell_size_ = gfx::Size(
252      tile_grid_info.fTileInterval.width() +
253          2 * tile_grid_info.fMargin.width(),
254      tile_grid_info.fTileInterval.height() +
255          2 * tile_grid_info.fMargin.height());
256  DCHECK_GT(cell_size_.width(), 0);
257  DCHECK_GT(cell_size_.height(), 0);
258
259  int min_x = std::numeric_limits<int>::max();
260  int min_y = std::numeric_limits<int>::max();
261  int max_x = 0;
262  int max_y = 0;
263
264  skia::LazyPixelRefList pixel_refs;
265  skia::LazyPixelRefUtils::GatherPixelRefs(picture_.get(), &pixel_refs);
266  for (skia::LazyPixelRefList::const_iterator it = pixel_refs.begin();
267       it != pixel_refs.end();
268       ++it) {
269    gfx::Point min(
270        RoundDown(static_cast<int>(it->pixel_ref_rect.x()),
271                  cell_size_.width()),
272        RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
273                  cell_size_.height()));
274    gfx::Point max(
275        RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
276                  cell_size_.width()),
277        RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
278                  cell_size_.height()));
279
280    for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
281      for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
282        PixelRefMapKey key(x, y);
283        pixel_refs_[key].push_back(it->lazy_pixel_ref);
284      }
285    }
286
287    min_x = std::min(min_x, min.x());
288    min_y = std::min(min_y, min.y());
289    max_x = std::max(max_x, max.x());
290    max_y = std::max(max_y, max.y());
291  }
292
293  min_pixel_cell_ = gfx::Point(min_x, min_y);
294  max_pixel_cell_ = gfx::Point(max_x, max_y);
295}
296
297int Picture::Raster(
298    SkCanvas* canvas,
299    SkDrawPictureCallback* callback,
300    const Region& negated_content_region,
301    float contents_scale) {
302  TRACE_EVENT_BEGIN1(
303      "cc",
304      "Picture::Raster",
305      "data",
306      AsTraceableRasterData(contents_scale));
307
308  DCHECK(picture_);
309
310  canvas->save();
311
312  for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
313    canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
314
315  canvas->scale(contents_scale, contents_scale);
316  canvas->translate(layer_rect_.x(), layer_rect_.y());
317  picture_->draw(canvas, callback);
318  SkIRect bounds;
319  canvas->getClipDeviceBounds(&bounds);
320  canvas->restore();
321  TRACE_EVENT_END1(
322      "cc", "Picture::Raster",
323      "num_pixels_rasterized", bounds.width() * bounds.height());
324  return bounds.width() * bounds.height();
325}
326
327void Picture::Replay(SkCanvas* canvas) {
328  TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
329  DCHECK(picture_);
330
331  picture_->draw(canvas);
332  SkIRect bounds;
333  canvas->getClipDeviceBounds(&bounds);
334  TRACE_EVENT_END1("cc", "Picture::Replay",
335                   "num_pixels_replayed", bounds.width() * bounds.height());
336}
337
338scoped_ptr<base::Value> Picture::AsValue() const {
339  SkDynamicMemoryWStream stream;
340
341  // Serialize the picture.
342  picture_->serialize(&stream, &EncodeBitmap);
343
344  // Encode the picture as base64.
345  scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
346  res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
347  res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release());
348
349  size_t serialized_size = stream.bytesWritten();
350  scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
351  stream.copyTo(serialized_picture.get());
352  std::string b64_picture;
353  base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
354                     &b64_picture);
355  res->SetString("skp64", b64_picture);
356  return res.PassAs<base::Value>();
357}
358
359void Picture::EmitTraceSnapshot() {
360  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
361      "cc::Picture", this, TracedPicture::AsTraceablePicture(this));
362}
363
364void Picture::EmitTraceSnapshotAlias(Picture* original) {
365  TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
366      TRACE_DISABLED_BY_DEFAULT("cc.debug"),
367      "cc::Picture",
368      this,
369      TracedPicture::AsTraceablePictureAlias(original));
370}
371
372base::LazyInstance<Picture::PixelRefs>
373    Picture::PixelRefIterator::empty_pixel_refs_;
374
375Picture::PixelRefIterator::PixelRefIterator()
376    : picture_(NULL),
377      current_pixel_refs_(empty_pixel_refs_.Pointer()),
378      current_index_(0),
379      min_point_(-1, -1),
380      max_point_(-1, -1),
381      current_x_(0),
382      current_y_(0) {
383}
384
385Picture::PixelRefIterator::PixelRefIterator(
386    gfx::Rect query_rect,
387    const Picture* picture)
388    : picture_(picture),
389      current_pixel_refs_(empty_pixel_refs_.Pointer()),
390      current_index_(0) {
391  gfx::Rect layer_rect = picture->layer_rect_;
392  gfx::Size cell_size = picture->cell_size_;
393  DCHECK(!cell_size.IsEmpty());
394
395  // Early out if the query rect doesn't intersect this picture.
396  if (!query_rect.Intersects(layer_rect)) {
397    min_point_ = gfx::Point(0, 0);
398    max_point_ = gfx::Point(0, 0);
399    current_x_ = 1;
400    current_y_ = 1;
401    return;
402  }
403
404  // First, subtract the layer origin as cells are stored in layer space.
405  query_rect.Offset(-layer_rect.OffsetFromOrigin());
406
407  // We have to find a cell_size aligned point that corresponds to
408  // query_rect. Point is a multiple of cell_size.
409  min_point_ = gfx::Point(
410      RoundDown(query_rect.x(), cell_size.width()),
411      RoundDown(query_rect.y(), cell_size.height()));
412  max_point_ = gfx::Point(
413      RoundDown(query_rect.right() - 1, cell_size.width()),
414      RoundDown(query_rect.bottom() - 1, cell_size.height()));
415
416  // Limit the points to known pixel ref boundaries.
417  min_point_ = gfx::Point(
418      std::max(min_point_.x(), picture->min_pixel_cell_.x()),
419      std::max(min_point_.y(), picture->min_pixel_cell_.y()));
420  max_point_ = gfx::Point(
421      std::min(max_point_.x(), picture->max_pixel_cell_.x()),
422      std::min(max_point_.y(), picture->max_pixel_cell_.y()));
423
424  // Make the current x be cell_size.width() less than min point, so that
425  // the first increment will point at min_point_.
426  current_x_ = min_point_.x() - cell_size.width();
427  current_y_ = min_point_.y();
428  if (current_y_ <= max_point_.y())
429    ++(*this);
430}
431
432Picture::PixelRefIterator::~PixelRefIterator() {
433}
434
435Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() {
436  ++current_index_;
437  // If we're not at the end of the list, then we have the next item.
438  if (current_index_ < current_pixel_refs_->size())
439    return *this;
440
441  DCHECK(current_y_ <= max_point_.y());
442  while (true) {
443    gfx::Size cell_size = picture_->cell_size_;
444
445    // Advance the current grid cell.
446    current_x_ += cell_size.width();
447    if (current_x_ > max_point_.x()) {
448      current_y_ += cell_size.height();
449      current_x_ = min_point_.x();
450      if (current_y_ > max_point_.y()) {
451        current_pixel_refs_ = empty_pixel_refs_.Pointer();
452        current_index_ = 0;
453        break;
454      }
455    }
456
457    // If there are no pixel refs at this grid cell, keep incrementing.
458    PixelRefMapKey key(current_x_, current_y_);
459    PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key);
460    if (iter == picture_->pixel_refs_.end())
461      continue;
462
463    // We found a non-empty list: store it and get the first pixel ref.
464    current_pixel_refs_ = &iter->second;
465    current_index_ = 0;
466    break;
467  }
468  return *this;
469}
470
471scoped_refptr<base::debug::ConvertableToTraceFormat>
472    Picture::AsTraceableRasterData(float scale) const {
473  scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue());
474  raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
475  raster_data->SetDouble("scale", scale);
476  return TracedValue::FromValue(raster_data.release());
477}
478
479scoped_refptr<base::debug::ConvertableToTraceFormat>
480    Picture::AsTraceableRecordData() const {
481  scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
482  record_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
483  record_data->SetInteger("width", layer_rect_.width());
484  record_data->SetInteger("height", layer_rect_.height());
485  return TracedValue::FromValue(record_data.release());
486}
487
488}  // namespace cc
489