picture.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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/rendering_stats_instrumentation.h" 17#include "cc/debug/traced_picture.h" 18#include "cc/debug/traced_value.h" 19#include "cc/layers/content_layer_client.h" 20#include "skia/ext/lazy_pixel_ref_utils.h" 21#include "third_party/skia/include/core/SkCanvas.h" 22#include "third_party/skia/include/core/SkData.h" 23#include "third_party/skia/include/core/SkDrawFilter.h" 24#include "third_party/skia/include/core/SkPaint.h" 25#include "third_party/skia/include/core/SkStream.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(gfx::Rect layer_rect) { 86 return make_scoped_refptr(new Picture(layer_rect)); 87} 88 89scoped_refptr<Picture> Picture::CreateFromValue(const base::Value* value) { 90 bool success; 91 scoped_refptr<Picture> picture = 92 make_scoped_refptr(new Picture(value, &success)); 93 if (!success) 94 picture = NULL; 95 return picture; 96} 97 98Picture::Picture(gfx::Rect layer_rect) 99 : layer_rect_(layer_rect) { 100 // Instead of recording a trace event for object creation here, we wait for 101 // the picture to be recorded in Picture::Record. 102} 103 104Picture::Picture(const base::Value* raw_value, bool* success) { 105 const base::DictionaryValue* value = NULL; 106 if (!raw_value->GetAsDictionary(&value)) { 107 *success = false; 108 return; 109 } 110 111 // Decode the picture from base64. 112 std::string encoded; 113 if (!value->GetString("skp64", &encoded)) { 114 *success = false; 115 return; 116 } 117 118 std::string decoded; 119 base::Base64Decode(encoded, &decoded); 120 SkMemoryStream stream(decoded.data(), decoded.size()); 121 122 const base::Value* layer_rect = NULL; 123 if (!value->Get("params.layer_rect", &layer_rect)) { 124 *success = false; 125 return; 126 } 127 if (!MathUtil::FromValue(layer_rect, &layer_rect_)) { 128 *success = false; 129 return; 130 } 131 132 const base::Value* opaque_rect = NULL; 133 if (!value->Get("params.opaque_rect", &opaque_rect)) { 134 *success = false; 135 return; 136 } 137 if (!MathUtil::FromValue(opaque_rect, &opaque_rect_)) { 138 *success = false; 139 return; 140 } 141 142 // Read the picture. This creates an empty picture on failure. 143 picture_ = skia::AdoptRef(new SkPicture(&stream, success, &DecodeBitmap)); 144} 145 146Picture::Picture(const skia::RefPtr<SkPicture>& picture, 147 gfx::Rect layer_rect, 148 gfx::Rect opaque_rect, 149 const PixelRefMap& pixel_refs) : 150 layer_rect_(layer_rect), 151 opaque_rect_(opaque_rect), 152 picture_(picture), 153 pixel_refs_(pixel_refs) { 154} 155 156Picture::~Picture() { 157 TRACE_EVENT_OBJECT_DELETED_WITH_ID( 158 TRACE_DISABLED_BY_DEFAULT("cc.debug"), "cc::Picture", this); 159} 160 161scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread( 162 unsigned thread_index) const { 163 // SkPicture is not thread-safe to rasterize with, this returns a clone 164 // to rasterize with on a specific thread. 165 CHECK_GT(clones_.size(), thread_index); 166 return clones_[thread_index]; 167} 168 169void Picture::CloneForDrawing(int num_threads) { 170 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); 171 172 DCHECK(picture_); 173 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]); 174 picture_->clone(&clones[0], num_threads); 175 176 clones_.clear(); 177 for (int i = 0; i < num_threads; i++) { 178 scoped_refptr<Picture> clone = make_scoped_refptr( 179 new Picture(skia::AdoptRef(new SkPicture(clones[i])), 180 layer_rect_, 181 opaque_rect_, 182 pixel_refs_)); 183 clones_.push_back(clone); 184 185 clone->EmitTraceSnapshot(); 186 } 187} 188 189void Picture::Record(ContentLayerClient* painter, 190 const SkTileGridPicture::TileGridInfo& tile_grid_info, 191 RenderingStatsInstrumentation* stats_instrumentation) { 192 TRACE_EVENT2("cc", "Picture::Record", 193 "width", layer_rect_.width(), 194 "height", layer_rect_.height()); 195 196 DCHECK(!tile_grid_info.fTileInterval.isEmpty()); 197 picture_ = skia::AdoptRef(new SkTileGridPicture( 198 layer_rect_.width(), layer_rect_.height(), tile_grid_info)); 199 200 SkCanvas* canvas = picture_->beginRecording( 201 layer_rect_.width(), 202 layer_rect_.height(), 203 SkPicture::kUsePathBoundsForClip_RecordingFlag | 204 SkPicture::kOptimizeForClippedPlayback_RecordingFlag); 205 206 canvas->save(); 207 canvas->translate(SkFloatToScalar(-layer_rect_.x()), 208 SkFloatToScalar(-layer_rect_.y())); 209 210 SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(), 211 layer_rect_.y(), 212 layer_rect_.width(), 213 layer_rect_.height()); 214 canvas->clipRect(layer_skrect); 215 216 gfx::RectF opaque_layer_rect; 217 base::TimeTicks start_time = stats_instrumentation->StartRecording(); 218 219 painter->PaintContents(canvas, layer_rect_, &opaque_layer_rect); 220 221 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); 222 stats_instrumentation->AddRecord(duration, 223 layer_rect_.width() * layer_rect_.height()); 224 225 canvas->restore(); 226 picture_->endRecording(); 227 228 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); 229 230 EmitTraceSnapshot(); 231} 232 233void Picture::GatherPixelRefs( 234 const SkTileGridPicture::TileGridInfo& tile_grid_info, 235 RenderingStatsInstrumentation* stats_instrumentation) { 236 TRACE_EVENT2("cc", "Picture::GatherPixelRefs", 237 "width", layer_rect_.width(), 238 "height", layer_rect_.height()); 239 240 DCHECK(picture_); 241 cell_size_ = gfx::Size( 242 tile_grid_info.fTileInterval.width() + 243 2 * tile_grid_info.fMargin.width(), 244 tile_grid_info.fTileInterval.height() + 245 2 * tile_grid_info.fMargin.height()); 246 DCHECK_GT(cell_size_.width(), 0); 247 DCHECK_GT(cell_size_.height(), 0); 248 249 int min_x = std::numeric_limits<int>::max(); 250 int min_y = std::numeric_limits<int>::max(); 251 int max_x = 0; 252 int max_y = 0; 253 254 base::TimeTicks start_time = stats_instrumentation->StartRecording(); 255 256 skia::LazyPixelRefList pixel_refs; 257 skia::LazyPixelRefUtils::GatherPixelRefs(picture_.get(), &pixel_refs); 258 for (skia::LazyPixelRefList::const_iterator it = pixel_refs.begin(); 259 it != pixel_refs.end(); 260 ++it) { 261 gfx::Point min( 262 RoundDown(static_cast<int>(it->pixel_ref_rect.x()), 263 cell_size_.width()), 264 RoundDown(static_cast<int>(it->pixel_ref_rect.y()), 265 cell_size_.height())); 266 gfx::Point max( 267 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.right())), 268 cell_size_.width()), 269 RoundDown(static_cast<int>(std::ceil(it->pixel_ref_rect.bottom())), 270 cell_size_.height())); 271 272 for (int y = min.y(); y <= max.y(); y += cell_size_.height()) { 273 for (int x = min.x(); x <= max.x(); x += cell_size_.width()) { 274 PixelRefMapKey key(x, y); 275 pixel_refs_[key].push_back(it->lazy_pixel_ref); 276 } 277 } 278 279 min_x = std::min(min_x, min.x()); 280 min_y = std::min(min_y, min.y()); 281 max_x = std::max(max_x, max.x()); 282 max_y = std::max(max_y, max.y()); 283 } 284 285 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); 286 stats_instrumentation->AddImageGathering(duration); 287 288 min_pixel_cell_ = gfx::Point(min_x, min_y); 289 max_pixel_cell_ = gfx::Point(max_x, max_y); 290} 291 292void Picture::Raster( 293 SkCanvas* canvas, 294 SkDrawPictureCallback* callback, 295 gfx::Rect content_rect, 296 float contents_scale) { 297 TRACE_EVENT_BEGIN1("cc", "Picture::Raster", 298 "data", AsTraceableRasterData(content_rect, contents_scale)); 299 300 DCHECK(picture_); 301 302 canvas->save(); 303 canvas->clipRect(gfx::RectToSkRect(content_rect)); 304 canvas->scale(contents_scale, contents_scale); 305 canvas->translate(layer_rect_.x(), layer_rect_.y()); 306 picture_->draw(canvas, callback); 307 SkIRect bounds; 308 canvas->getClipDeviceBounds(&bounds); 309 canvas->restore(); 310 TRACE_EVENT_END1("cc", "Picture::Raster", 311 "num_pixels_rasterized", bounds.width() * bounds.height()); 312} 313 314void Picture::Replay(SkCanvas* canvas) { 315 TRACE_EVENT_BEGIN0("cc", "Picture::Replay"); 316 DCHECK(picture_); 317 318 picture_->draw(canvas); 319 SkIRect bounds; 320 canvas->getClipDeviceBounds(&bounds); 321 TRACE_EVENT_END1("cc", "Picture::Replay", 322 "num_pixels_replayed", bounds.width() * bounds.height()); 323} 324 325scoped_ptr<base::Value> Picture::AsValue() const { 326 SkDynamicMemoryWStream stream; 327 328 // Serialize the picture. 329 picture_->serialize(&stream, &EncodeBitmap); 330 331 // Encode the picture as base64. 332 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); 333 res->Set("params.layer_rect", MathUtil::AsValue(layer_rect_).release()); 334 res->Set("params.opaque_rect", MathUtil::AsValue(opaque_rect_).release()); 335 336 size_t serialized_size = stream.bytesWritten(); 337 scoped_ptr<char[]> serialized_picture(new char[serialized_size]); 338 stream.copyTo(serialized_picture.get()); 339 std::string b64_picture; 340 base::Base64Encode(std::string(serialized_picture.get(), serialized_size), 341 &b64_picture); 342 res->SetString("skp64", b64_picture); 343 return res.PassAs<base::Value>(); 344} 345 346void Picture::EmitTraceSnapshot() { 347 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(TRACE_DISABLED_BY_DEFAULT("cc.debug"), 348 "cc::Picture", this, TracedPicture::AsTraceablePicture(this)); 349} 350 351base::LazyInstance<Picture::PixelRefs> 352 Picture::PixelRefIterator::empty_pixel_refs_; 353 354Picture::PixelRefIterator::PixelRefIterator() 355 : picture_(NULL), 356 current_pixel_refs_(empty_pixel_refs_.Pointer()), 357 current_index_(0), 358 min_point_(-1, -1), 359 max_point_(-1, -1), 360 current_x_(0), 361 current_y_(0) { 362} 363 364Picture::PixelRefIterator::PixelRefIterator( 365 gfx::Rect query_rect, 366 const Picture* picture) 367 : picture_(picture), 368 current_pixel_refs_(empty_pixel_refs_.Pointer()), 369 current_index_(0) { 370 gfx::Rect layer_rect = picture->layer_rect_; 371 gfx::Size cell_size = picture->cell_size_; 372 373 // Early out if the query rect doesn't intersect this picture 374 if (!query_rect.Intersects(layer_rect)) { 375 min_point_ = gfx::Point(0, 0); 376 max_point_ = gfx::Point(0, 0); 377 current_x_ = 1; 378 current_y_ = 1; 379 return; 380 } 381 382 // First, subtract the layer origin as cells are stored in layer space. 383 query_rect.Offset(-layer_rect.OffsetFromOrigin()); 384 385 // We have to find a cell_size aligned point that corresponds to 386 // query_rect. Point is a multiple of cell_size. 387 min_point_ = gfx::Point( 388 RoundDown(query_rect.x(), cell_size.width()), 389 RoundDown(query_rect.y(), cell_size.height())); 390 max_point_ = gfx::Point( 391 RoundDown(query_rect.right() - 1, cell_size.width()), 392 RoundDown(query_rect.bottom() - 1, cell_size.height())); 393 394 // Limit the points to known pixel ref boundaries. 395 min_point_ = gfx::Point( 396 std::max(min_point_.x(), picture->min_pixel_cell_.x()), 397 std::max(min_point_.y(), picture->min_pixel_cell_.y())); 398 max_point_ = gfx::Point( 399 std::min(max_point_.x(), picture->max_pixel_cell_.x()), 400 std::min(max_point_.y(), picture->max_pixel_cell_.y())); 401 402 // Make the current x be cell_size.width() less than min point, so that 403 // the first increment will point at min_point_. 404 current_x_ = min_point_.x() - cell_size.width(); 405 current_y_ = min_point_.y(); 406 if (current_y_ <= max_point_.y()) 407 ++(*this); 408} 409 410Picture::PixelRefIterator::~PixelRefIterator() { 411} 412 413Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() { 414 ++current_index_; 415 // If we're not at the end of the list, then we have the next item. 416 if (current_index_ < current_pixel_refs_->size()) 417 return *this; 418 419 DCHECK(current_y_ <= max_point_.y()); 420 while (true) { 421 gfx::Size cell_size = picture_->cell_size_; 422 423 // Advance the current grid cell. 424 current_x_ += cell_size.width(); 425 if (current_x_ > max_point_.x()) { 426 current_y_ += cell_size.height(); 427 current_x_ = min_point_.x(); 428 if (current_y_ > max_point_.y()) { 429 current_pixel_refs_ = empty_pixel_refs_.Pointer(); 430 current_index_ = 0; 431 break; 432 } 433 } 434 435 // If there are no pixel refs at this grid cell, keep incrementing. 436 PixelRefMapKey key(current_x_, current_y_); 437 PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key); 438 if (iter == picture_->pixel_refs_.end()) 439 continue; 440 441 // We found a non-empty list: store it and get the first pixel ref. 442 current_pixel_refs_ = &iter->second; 443 current_index_ = 0; 444 break; 445 } 446 return *this; 447} 448 449scoped_ptr<base::debug::ConvertableToTraceFormat> 450 Picture::AsTraceableRasterData(gfx::Rect rect, float scale) { 451 scoped_ptr<base::DictionaryValue> raster_data(new base::DictionaryValue()); 452 raster_data->Set("picture_id", TracedValue::CreateIDRef(this).release()); 453 raster_data->SetDouble("scale", scale); 454 raster_data->SetDouble("rect_x", rect.x()); 455 raster_data->SetDouble("rect_y", rect.y()); 456 raster_data->SetDouble("rect_width", rect.width()); 457 raster_data->SetDouble("rect_height", rect.height()); 458 return TracedValue::FromValue(raster_data.release()); 459} 460 461} // namespace cc 462