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