Home | History | Annotate | Download | only in resources
      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 
     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(gfx::Rect layer_rect) {
     85   return make_scoped_refptr(new Picture(layer_rect));
     86 }
     87 
     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 
     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 
    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 
    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 
    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 
    174 Picture::~Picture() {
    175   TRACE_EVENT_OBJECT_DELETED_WITH_ID(
    176     TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this);
    177 }
    178 
    179 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 
    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 
    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 
    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 
    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 
    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 
    340 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 
    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 
    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 
    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 
    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 
    434 Picture::PixelRefIterator::~PixelRefIterator() {
    435 }
    436 
    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>
    474     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>
    482     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