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