• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 namespace cc {
32 
33 namespace {
34 
EncodeBitmap(size_t * offset,const SkBitmap & bm)35 SkData* 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 
DecodeBitmap(const void * buffer,size_t size,SkBitmap * bm)66 bool 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 
Create(gfx::Rect layer_rect)84 scoped_refptr<Picture> Picture::Create(gfx::Rect layer_rect) {
85   return make_scoped_refptr(new Picture(layer_rect));
86 }
87 
Picture(gfx::Rect layer_rect)88 Picture::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 
CreateFromSkpValue(const base::Value * value)95 scoped_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 
CreateFromValue(const base::Value * raw_value)116 scoped_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 
Picture(SkPicture * picture,gfx::Rect layer_rect,gfx::Rect opaque_rect)154 Picture::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 
Picture(const skia::RefPtr<SkPicture> & picture,gfx::Rect layer_rect,gfx::Rect opaque_rect,const PixelRefMap & pixel_refs)163 Picture::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 
~Picture()174 Picture::~Picture() {
175   TRACE_EVENT_OBJECT_DELETED_WITH_ID(
176     TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
177 }
178 
GetCloneForDrawingOnThread(unsigned thread_index) const179 scoped_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 
CloneForDrawing(int num_threads)187 void 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 
Record(ContentLayerClient * painter,const SkTileGridPicture::TileGridInfo & tile_grid_info)207 void 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 
GatherPixelRefs(const SkTileGridPicture::TileGridInfo & tile_grid_info)244 void 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   if (!WillPlayBackBitmaps())
252     return;
253   cell_size_ = gfx::Size(
254       tile_grid_info.fTileInterval.width() +
255           2 * tile_grid_info.fMargin.width(),
256       tile_grid_info.fTileInterval.height() +
257           2 * tile_grid_info.fMargin.height());
258   DCHECK_GT(cell_size_.width(), 0);
259   DCHECK_GT(cell_size_.height(), 0);
260 
261   int min_x = std::numeric_limits<int>::max();
262   int min_y = std::numeric_limits<int>::max();
263   int max_x = 0;
264   int max_y = 0;
265 
266   skia::LazyPixelRefList pixel_refs;
267   skia::LazyPixelRefUtils::GatherPixelRefs(picture_.get(), &pixel_refs);
268   for (skia::LazyPixelRefList::const_iterator it = pixel_refs.begin();
269        it != pixel_refs.end();
270        ++it) {
271     gfx::Point min(
272         RoundDown(static_cast<int>(it->pixel_ref_rect.x()),
273                   cell_size_.width()),
274         RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
275                   cell_size_.height()));
276     gfx::Point max(
277         RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
278                   cell_size_.width()),
279         RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
280                   cell_size_.height()));
281 
282     for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
283       for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
284         PixelRefMapKey key(x, y);
285         pixel_refs_[key].push_back(it->lazy_pixel_ref);
286       }
287     }
288 
289     min_x = std::min(min_x, min.x());
290     min_y = std::min(min_y, min.y());
291     max_x = std::max(max_x, max.x());
292     max_y = std::max(max_y, max.y());
293   }
294 
295   min_pixel_cell_ = gfx::Point(min_x, min_y);
296   max_pixel_cell_ = gfx::Point(max_x, max_y);
297 }
298 
Raster(SkCanvas * canvas,SkDrawPictureCallback * callback,const Region & negated_content_region,float contents_scale)299 int Picture::Raster(
300     SkCanvas* canvas,
301     SkDrawPictureCallback* callback,
302     const Region& negated_content_region,
303     float contents_scale) {
304   TRACE_EVENT_BEGIN1(
305       "cc",
306       "Picture::Raster",
307       "data",
308       AsTraceableRasterData(contents_scale));
309 
310   DCHECK(picture_);
311 
312   canvas->save();
313 
314   for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
315     canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
316 
317   canvas->scale(contents_scale, contents_scale);
318   canvas->translate(layer_rect_.x(), layer_rect_.y());
319   picture_->draw(canvas, callback);
320   SkIRect bounds;
321   canvas->getClipDeviceBounds(&bounds);
322   canvas->restore();
323   TRACE_EVENT_END1(
324       "cc", "Picture::Raster",
325       "num_pixels_rasterized", bounds.width() * bounds.height());
326   return bounds.width() * bounds.height();
327 }
328 
Replay(SkCanvas * canvas)329 void Picture::Replay(SkCanvas* canvas) {
330   TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
331   DCHECK(picture_);
332 
333   picture_->draw(canvas);
334   SkIRect bounds;
335   canvas->getClipDeviceBounds(&bounds);
336   TRACE_EVENT_END1("cc", "Picture::Replay",
337                    "num_pixels_replayed", bounds.width() * bounds.height());
338 }
339 
AsValue() const340 scoped_ptr<base::Value> Picture::AsValue() const {
341   SkDynamicMemoryWStream stream;
342 
343   // Serialize the picture.
344   picture_->serialize(&stream, &EncodeBitmap);
345 
346   // Encode the picture as base64.
347   scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
348   res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
349   res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release());
350 
351   size_t serialized_size = stream.bytesWritten();
352   scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
353   stream.copyTo(serialized_picture.get());
354   std::string b64_picture;
355   base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
356                      &b64_picture);
357   res->SetString("skp64", b64_picture);
358   return res.PassAs<base::Value>();
359 }
360 
EmitTraceSnapshot()361 void Picture::EmitTraceSnapshot() {
362   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
363       "cc::Picture", this, TracedPicture::AsTraceablePicture(this));
364 }
365 
EmitTraceSnapshotAlias(Picture * original)366 void Picture::EmitTraceSnapshotAlias(Picture* original) {
367   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
368       TRACE_DISABLED_BY_DEFAULT("cc.debug"),
369       "cc::Picture",
370       this,
371       TracedPicture::AsTraceablePictureAlias(original));
372 }
373 
374 base::LazyInstance<Picture::PixelRefs>
375     Picture::PixelRefIterator::empty_pixel_refs_;
376 
PixelRefIterator()377 Picture::PixelRefIterator::PixelRefIterator()
378     : picture_(NULL),
379       current_pixel_refs_(empty_pixel_refs_.Pointer()),
380       current_index_(0),
381       min_point_(-1, -1),
382       max_point_(-1, -1),
383       current_x_(0),
384       current_y_(0) {
385 }
386 
PixelRefIterator(gfx::Rect query_rect,const Picture * picture)387 Picture::PixelRefIterator::PixelRefIterator(
388     gfx::Rect query_rect,
389     const Picture* picture)
390     : picture_(picture),
391       current_pixel_refs_(empty_pixel_refs_.Pointer()),
392       current_index_(0) {
393   gfx::Rect layer_rect = picture->layer_rect_;
394   gfx::Size cell_size = picture->cell_size_;
395   DCHECK(!cell_size.IsEmpty());
396 
397   // Early out if the query rect doesn't intersect this picture.
398   if (!query_rect.Intersects(layer_rect)) {
399     min_point_ = gfx::Point(0, 0);
400     max_point_ = gfx::Point(0, 0);
401     current_x_ = 1;
402     current_y_ = 1;
403     return;
404   }
405 
406   // First, subtract the layer origin as cells are stored in layer space.
407   query_rect.Offset(-layer_rect.OffsetFromOrigin());
408 
409   // We have to find a cell_size aligned point that corresponds to
410   // query_rect. Point is a multiple of cell_size.
411   min_point_ = gfx::Point(
412       RoundDown(query_rect.x(), cell_size.width()),
413       RoundDown(query_rect.y(), cell_size.height()));
414   max_point_ = gfx::Point(
415       RoundDown(query_rect.right() - 1, cell_size.width()),
416       RoundDown(query_rect.bottom() - 1, cell_size.height()));
417 
418   // Limit the points to known pixel ref boundaries.
419   min_point_ = gfx::Point(
420       std::max(min_point_.x(), picture->min_pixel_cell_.x()),
421       std::max(min_point_.y(), picture->min_pixel_cell_.y()));
422   max_point_ = gfx::Point(
423       std::min(max_point_.x(), picture->max_pixel_cell_.x()),
424       std::min(max_point_.y(), picture->max_pixel_cell_.y()));
425 
426   // Make the current x be cell_size.width() less than min point, so that
427   // the first increment will point at min_point_.
428   current_x_ = min_point_.x() - cell_size.width();
429   current_y_ = min_point_.y();
430   if (current_y_ <= max_point_.y())
431     ++(*this);
432 }
433 
~PixelRefIterator()434 Picture::PixelRefIterator::~PixelRefIterator() {
435 }
436 
operator ++()437 Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() {
438   ++current_index_;
439   // If we're not at the end of the list, then we have the next item.
440   if (current_index_ < current_pixel_refs_->size())
441     return *this;
442 
443   DCHECK(current_y_ <= max_point_.y());
444   while (true) {
445     gfx::Size cell_size = picture_->cell_size_;
446 
447     // Advance the current grid cell.
448     current_x_ += cell_size.width();
449     if (current_x_ > max_point_.x()) {
450       current_y_ += cell_size.height();
451       current_x_ = min_point_.x();
452       if (current_y_ > max_point_.y()) {
453         current_pixel_refs_ = empty_pixel_refs_.Pointer();
454         current_index_ = 0;
455         break;
456       }
457     }
458 
459     // If there are no pixel refs at this grid cell, keep incrementing.
460     PixelRefMapKey key(current_x_, current_y_);
461     PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key);
462     if (iter == picture_->pixel_refs_.end())
463       continue;
464 
465     // We found a non-empty list: store it and get the first pixel ref.
466     current_pixel_refs_ = &iter->second;
467     current_index_ = 0;
468     break;
469   }
470   return *this;
471 }
472 
473 scoped_refptr<base::debug::ConvertableToTraceFormat>
AsTraceableRasterData(float scale) const474     Picture::AsTraceableRasterData(float scale) const {
475   scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue());
476   raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
477   raster_data->SetDouble("scale", scale);
478   return TracedValue::FromValue(raster_data.release());
479 }
480 
481 scoped_refptr<base::debug::ConvertableToTraceFormat>
AsTraceableRecordData() const482     Picture::AsTraceableRecordData() const {
483   scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
484   record_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
485   record_data->SetInteger("width", layer_rect_.width());
486   record_data->SetInteger("height", layer_rect_.height());
487   return TracedValue::FromValue(record_data.release());
488 }
489 
490 }  // namespace cc
491