Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / cc / resources / picture.cc
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/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
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
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
84 scoped_refptr<Picture> Picture::Create(
85     const gfx::Rect& layer_rect,
86     ContentLayerClient* client,
87     const SkTileGridPicture::TileGridInfo& tile_grid_info,
88     bool gather_pixel_refs,
89     int num_raster_threads) {
90   scoped_refptr<Picture> picture = make_scoped_refptr(new Picture(layer_rect));
91
92   picture->Record(client, tile_grid_info);
93   if (gather_pixel_refs)
94     picture->GatherPixelRefs(tile_grid_info);
95   picture->CloneForDrawing(num_raster_threads);
96
97   return picture;
98 }
99
100 Picture::Picture(const gfx::Rect& layer_rect)
101   : layer_rect_(layer_rect),
102     cell_size_(layer_rect.size()) {
103   // Instead of recording a trace event for object creation here, we wait for
104   // the picture to be recorded in Picture::Record.
105 }
106
107 scoped_refptr<Picture> Picture::CreateFromSkpValue(const base::Value* value) {
108   // Decode the picture from base64.
109   std::string encoded;
110   if (!value->GetAsString(&encoded))
111     return NULL;
112
113   std::string decoded;
114   base::Base64Decode(encoded, &decoded);
115   SkMemoryStream stream(decoded.data(), decoded.size());
116
117   // Read the picture. This creates an empty picture on failure.
118   SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
119   if (skpicture == NULL)
120     return NULL;
121
122   gfx::Rect layer_rect(skpicture->width(), skpicture->height());
123   gfx::Rect opaque_rect(skpicture->width(), skpicture->height());
124
125   return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
126 }
127
128 scoped_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   const base::Value* opaque_rect_value = NULL;
151   if (!value->Get("params.opaque_rect", &opaque_rect_value))
152     return NULL;
153
154   gfx::Rect opaque_rect;
155   if (!MathUtil::FromValue(opaque_rect_value, &opaque_rect))
156     return NULL;
157
158   // Read the picture. This creates an empty picture on failure.
159   SkPicture* skpicture = SkPicture::CreateFromStream(&stream, &DecodeBitmap);
160   if (skpicture == NULL)
161     return NULL;
162
163   return make_scoped_refptr(new Picture(skpicture, layer_rect, opaque_rect));
164 }
165
166 Picture::Picture(SkPicture* picture,
167                  const gfx::Rect& layer_rect,
168                  const gfx::Rect& opaque_rect) :
169     layer_rect_(layer_rect),
170     opaque_rect_(opaque_rect),
171     picture_(skia::AdoptRef(picture)),
172     cell_size_(layer_rect.size()) {
173 }
174
175 Picture::Picture(const skia::RefPtr<SkPicture>& picture,
176                  const gfx::Rect& layer_rect,
177                  const gfx::Rect& opaque_rect,
178                  const PixelRefMap& pixel_refs) :
179     layer_rect_(layer_rect),
180     opaque_rect_(opaque_rect),
181     picture_(picture),
182     pixel_refs_(pixel_refs),
183     cell_size_(layer_rect.size()) {
184 }
185
186 Picture::~Picture() {
187   TRACE_EVENT_OBJECT_DELETED_WITH_ID(
188     TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
189 }
190
191 Picture* Picture::GetCloneForDrawingOnThread(unsigned thread_index) {
192   // SkPicture is not thread-safe to rasterize with, this returns a clone
193   // to rasterize with on a specific thread.
194   CHECK_GE(clones_.size(), thread_index);
195   return thread_index == clones_.size() ? this : clones_[thread_index].get();
196 }
197
198 void Picture::CloneForDrawing(int num_threads) {
199   TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads);
200
201   DCHECK(picture_);
202   DCHECK(clones_.empty());
203
204   // We can re-use this picture for one raster worker thread.
205   raster_thread_checker_.DetachFromThread();
206
207   if (num_threads > 1) {
208     scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads - 1]);
209     picture_->clone(&clones[0], num_threads - 1);
210
211     for (int i = 0; i < num_threads - 1; i++) {
212       scoped_refptr<Picture> clone = make_scoped_refptr(
213           new Picture(skia::AdoptRef(new SkPicture(clones[i])),
214                       layer_rect_,
215                       opaque_rect_,
216                       pixel_refs_));
217       clones_.push_back(clone);
218
219       clone->EmitTraceSnapshotAlias(this);
220       clone->raster_thread_checker_.DetachFromThread();
221     }
222   }
223 }
224
225 void Picture::Record(ContentLayerClient* painter,
226                      const SkTileGridPicture::TileGridInfo& tile_grid_info) {
227   TRACE_EVENT1("cc", "Picture::Record",
228                "data", AsTraceableRecordData());
229
230   DCHECK(!picture_);
231   DCHECK(!tile_grid_info.fTileInterval.isEmpty());
232   picture_ = skia::AdoptRef(new SkTileGridPicture(
233       layer_rect_.width(), layer_rect_.height(), tile_grid_info));
234
235   SkCanvas* canvas = picture_->beginRecording(
236       layer_rect_.width(),
237       layer_rect_.height(),
238       SkPicture::kUsePathBoundsForClip_RecordingFlag |
239       SkPicture::kOptimizeForClippedPlayback_RecordingFlag);
240
241   canvas->save();
242   canvas->translate(SkFloatToScalar(-layer_rect_.x()),
243                     SkFloatToScalar(-layer_rect_.y()));
244
245   SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
246                                          layer_rect_.y(),
247                                          layer_rect_.width(),
248                                          layer_rect_.height());
249   canvas->clipRect(layer_skrect);
250
251   gfx::RectF opaque_layer_rect;
252
253   painter->PaintContents(canvas, layer_rect_, &opaque_layer_rect);
254
255   canvas->restore();
256   picture_->endRecording();
257
258   opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect);
259
260   EmitTraceSnapshot();
261 }
262
263 void Picture::GatherPixelRefs(
264     const SkTileGridPicture::TileGridInfo& tile_grid_info) {
265   TRACE_EVENT2("cc", "Picture::GatherPixelRefs",
266                "width", layer_rect_.width(),
267                "height", layer_rect_.height());
268
269   DCHECK(picture_);
270   DCHECK(pixel_refs_.empty());
271   if (!WillPlayBackBitmaps())
272     return;
273   cell_size_ = gfx::Size(
274       tile_grid_info.fTileInterval.width() +
275           2 * tile_grid_info.fMargin.width(),
276       tile_grid_info.fTileInterval.height() +
277           2 * tile_grid_info.fMargin.height());
278   DCHECK_GT(cell_size_.width(), 0);
279   DCHECK_GT(cell_size_.height(), 0);
280
281   int min_x = std::numeric_limits<int>::max();
282   int min_y = std::numeric_limits<int>::max();
283   int max_x = 0;
284   int max_y = 0;
285
286   skia::DiscardablePixelRefList pixel_refs;
287   skia::PixelRefUtils::GatherDiscardablePixelRefs(picture_.get(), &pixel_refs);
288   for (skia::DiscardablePixelRefList::const_iterator it = pixel_refs.begin();
289        it != pixel_refs.end();
290        ++it) {
291     gfx::Point min(
292         RoundDown(static_cast<int>(it->pixel_ref_rect.x()),
293                   cell_size_.width()),
294         RoundDown(static_cast<int>(it->pixel_ref_rect.y()),
295                   cell_size_.height()));
296     gfx::Point max(
297         RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())),
298                   cell_size_.width()),
299         RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())),
300                   cell_size_.height()));
301
302     for (int y = min.y(); y <= max.y(); y += cell_size_.height()) {
303       for (int x = min.x(); x <= max.x(); x += cell_size_.width()) {
304         PixelRefMapKey key(x, y);
305         pixel_refs_[key].push_back(it->pixel_ref);
306       }
307     }
308
309     min_x = std::min(min_x, min.x());
310     min_y = std::min(min_y, min.y());
311     max_x = std::max(max_x, max.x());
312     max_y = std::max(max_y, max.y());
313   }
314
315   min_pixel_cell_ = gfx::Point(min_x, min_y);
316   max_pixel_cell_ = gfx::Point(max_x, max_y);
317 }
318
319 int Picture::Raster(
320     SkCanvas* canvas,
321     SkDrawPictureCallback* callback,
322     const Region& negated_content_region,
323     float contents_scale) {
324   DCHECK(raster_thread_checker_.CalledOnValidThread());
325   TRACE_EVENT_BEGIN1(
326       "cc",
327       "Picture::Raster",
328       "data",
329       AsTraceableRasterData(contents_scale));
330
331   DCHECK(picture_);
332
333   canvas->save();
334
335   for (Region::Iterator it(negated_content_region); it.has_rect(); it.next())
336     canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
337
338   canvas->scale(contents_scale, contents_scale);
339   canvas->translate(layer_rect_.x(), layer_rect_.y());
340   picture_->draw(canvas, callback);
341   SkIRect bounds;
342   canvas->getClipDeviceBounds(&bounds);
343   canvas->restore();
344   TRACE_EVENT_END1(
345       "cc", "Picture::Raster",
346       "num_pixels_rasterized", bounds.width() * bounds.height());
347   return bounds.width() * bounds.height();
348 }
349
350 void Picture::Replay(SkCanvas* canvas) {
351   DCHECK(raster_thread_checker_.CalledOnValidThread());
352   TRACE_EVENT_BEGIN0("cc", "Picture::Replay");
353   DCHECK(picture_);
354
355   picture_->draw(canvas);
356   SkIRect bounds;
357   canvas->getClipDeviceBounds(&bounds);
358   TRACE_EVENT_END1("cc", "Picture::Replay",
359                    "num_pixels_replayed", bounds.width() * bounds.height());
360 }
361
362 scoped_ptr<base::Value> Picture::AsValue() const {
363   SkDynamicMemoryWStream stream;
364
365   // Serialize the picture.
366   picture_->serialize(&stream, &EncodeBitmap);
367
368   // Encode the picture as base64.
369   scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue());
370   res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release());
371   res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release());
372
373   size_t serialized_size = stream.bytesWritten();
374   scoped_ptr<char[]> serialized_picture(new char[serialized_size]);
375   stream.copyTo(serialized_picture.get());
376   std::string b64_picture;
377   base::Base64Encode(std::string(serialized_picture.get(), serialized_size),
378                      &b64_picture);
379   res->SetString("skp64", b64_picture);
380   return res.PassAs<base::Value>();
381 }
382
383 void Picture::EmitTraceSnapshot() const {
384   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
385       "cc::Picture", this, TracedPicture::AsTraceablePicture(this));
386 }
387
388 void Picture::EmitTraceSnapshotAlias(Picture* original) const {
389   TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
390       TRACE_DISABLED_BY_DEFAULT("cc.debug"),
391       "cc::Picture",
392       this,
393       TracedPicture::AsTraceablePictureAlias(original));
394 }
395
396 base::LazyInstance<Picture::PixelRefs>
397     Picture::PixelRefIterator::empty_pixel_refs_;
398
399 Picture::PixelRefIterator::PixelRefIterator()
400     : picture_(NULL),
401       current_pixel_refs_(empty_pixel_refs_.Pointer()),
402       current_index_(0),
403       min_point_(-1, -1),
404       max_point_(-1, -1),
405       current_x_(0),
406       current_y_(0) {
407 }
408
409 Picture::PixelRefIterator::PixelRefIterator(
410     const gfx::Rect& rect,
411     const Picture* picture)
412     : picture_(picture),
413       current_pixel_refs_(empty_pixel_refs_.Pointer()),
414       current_index_(0) {
415   gfx::Rect layer_rect = picture->layer_rect_;
416   gfx::Size cell_size = picture->cell_size_;
417   DCHECK(!cell_size.IsEmpty());
418
419   gfx::Rect query_rect(rect);
420   // Early out if the query rect doesn't intersect this picture.
421   if (!query_rect.Intersects(layer_rect)) {
422     min_point_ = gfx::Point(0, 0);
423     max_point_ = gfx::Point(0, 0);
424     current_x_ = 1;
425     current_y_ = 1;
426     return;
427   }
428
429   // First, subtract the layer origin as cells are stored in layer space.
430   query_rect.Offset(-layer_rect.OffsetFromOrigin());
431
432   // We have to find a cell_size aligned point that corresponds to
433   // query_rect. Point is a multiple of cell_size.
434   min_point_ = gfx::Point(
435       RoundDown(query_rect.x(), cell_size.width()),
436       RoundDown(query_rect.y(), cell_size.height()));
437   max_point_ = gfx::Point(
438       RoundDown(query_rect.right() - 1, cell_size.width()),
439       RoundDown(query_rect.bottom() - 1, cell_size.height()));
440
441   // Limit the points to known pixel ref boundaries.
442   min_point_ = gfx::Point(
443       std::max(min_point_.x(), picture->min_pixel_cell_.x()),
444       std::max(min_point_.y(), picture->min_pixel_cell_.y()));
445   max_point_ = gfx::Point(
446       std::min(max_point_.x(), picture->max_pixel_cell_.x()),
447       std::min(max_point_.y(), picture->max_pixel_cell_.y()));
448
449   // Make the current x be cell_size.width() less than min point, so that
450   // the first increment will point at min_point_.
451   current_x_ = min_point_.x() - cell_size.width();
452   current_y_ = min_point_.y();
453   if (current_y_ <= max_point_.y())
454     ++(*this);
455 }
456
457 Picture::PixelRefIterator::~PixelRefIterator() {
458 }
459
460 Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() {
461   ++current_index_;
462   // If we're not at the end of the list, then we have the next item.
463   if (current_index_ < current_pixel_refs_->size())
464     return *this;
465
466   DCHECK(current_y_ <= max_point_.y());
467   while (true) {
468     gfx::Size cell_size = picture_->cell_size_;
469
470     // Advance the current grid cell.
471     current_x_ += cell_size.width();
472     if (current_x_ > max_point_.x()) {
473       current_y_ += cell_size.height();
474       current_x_ = min_point_.x();
475       if (current_y_ > max_point_.y()) {
476         current_pixel_refs_ = empty_pixel_refs_.Pointer();
477         current_index_ = 0;
478         break;
479       }
480     }
481
482     // If there are no pixel refs at this grid cell, keep incrementing.
483     PixelRefMapKey key(current_x_, current_y_);
484     PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key);
485     if (iter == picture_->pixel_refs_.end())
486       continue;
487
488     // We found a non-empty list: store it and get the first pixel ref.
489     current_pixel_refs_ = &iter->second;
490     current_index_ = 0;
491     break;
492   }
493   return *this;
494 }
495
496 scoped_refptr<base::debug::ConvertableToTraceFormat>
497     Picture::AsTraceableRasterData(float scale) const {
498   scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue());
499   raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
500   raster_data->SetDouble("scale", scale);
501   return TracedValue::FromValue(raster_data.release());
502 }
503
504 scoped_refptr<base::debug::ConvertableToTraceFormat>
505     Picture::AsTraceableRecordData() const {
506   scoped_ptr<base::DictionaryValue> record_data(new base::DictionaryValue());
507   record_data->Set("picture_id", TracedValue::CreateIDRef(this).release());
508   record_data->SetInteger("width", layer_rect_.width());
509   record_data->SetInteger("height", layer_rect_.height());
510   return TracedValue::FromValue(record_data.release());
511 }
512
513 }  // namespace cc