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