Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/resources/picture.h" | 5 #include "cc/resources/picture.h" |
| 6 | 6 |
| 7 #include <algorithm> | |
| 8 #include <limits> | |
| 9 #include <set> | |
| 10 | |
| 7 #include "base/base64.h" | 11 #include "base/base64.h" |
| 8 #include "base/debug/trace_event.h" | 12 #include "base/debug/trace_event.h" |
| 9 #include "cc/debug/rendering_stats.h" | 13 #include "cc/debug/rendering_stats.h" |
| 10 #include "cc/layers/content_layer_client.h" | 14 #include "cc/layers/content_layer_client.h" |
| 11 #include "skia/ext/analysis_canvas.h" | 15 #include "skia/ext/analysis_canvas.h" |
| 12 #include "third_party/skia/include/core/SkCanvas.h" | 16 #include "third_party/skia/include/core/SkCanvas.h" |
| 13 #include "third_party/skia/include/core/SkData.h" | 17 #include "third_party/skia/include/core/SkData.h" |
| 14 #include "third_party/skia/include/core/SkDrawFilter.h" | 18 #include "third_party/skia/include/core/SkDrawFilter.h" |
| 15 #include "third_party/skia/include/core/SkPaint.h" | 19 #include "third_party/skia/include/core/SkPaint.h" |
| 16 #include "third_party/skia/include/core/SkStream.h" | 20 #include "third_party/skia/include/core/SkStream.h" |
| 17 #include "third_party/skia/include/utils/SkPictureUtils.h" | 21 #include "third_party/skia/include/utils/SkPictureUtils.h" |
| 18 #include "ui/gfx/rect_conversions.h" | 22 #include "ui/gfx/rect_conversions.h" |
| 19 #include "ui/gfx/skia_util.h" | 23 #include "ui/gfx/skia_util.h" |
| 20 | 24 |
| 21 namespace { | 25 namespace { |
| 22 // URI label for a lazily decoded SkPixelRef. | 26 // URI label for a lazily decoded SkPixelRef. |
| 23 const char kLabelLazyDecoded[] = "lazy"; | 27 const char kLabelLazyDecoded[] = "lazy"; |
| 28 | |
| 24 // Version ID; to be used in serialization. | 29 // Version ID; to be used in serialization. |
| 25 const int kPictureVersion = 1; | 30 const int kPictureVersion = 1; |
| 31 | |
| 26 // Minimum size of a decoded stream that we need. | 32 // Minimum size of a decoded stream that we need. |
| 27 // 4 bytes for version, 4 * 4 for each of the 2 rects. | 33 // 4 bytes for version, 4 * 4 for each of the 2 rects. |
| 28 const unsigned int kMinPictureSizeBytes = 36; | 34 const unsigned int kMinPictureSizeBytes = 36; |
| 29 | 35 |
| 36 // Size of each of the grid cells for storing lazy pixel refs. | |
| 37 const int kRegionWidth = 512; | |
| 38 const int kRegionHeight = 512; | |
|
reveman
2013/04/22 19:56:06
Can we avoid these constants and use SkTileGridPic
vmpstr
2013/04/22 22:38:16
Done.
| |
| 39 | |
| 30 class DisableLCDTextFilter : public SkDrawFilter { | 40 class DisableLCDTextFilter : public SkDrawFilter { |
| 31 public: | 41 public: |
| 32 // SkDrawFilter interface. | 42 // SkDrawFilter interface. |
| 33 virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE { | 43 virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE { |
| 34 if (type != SkDrawFilter::kText_Type) | 44 if (type != SkDrawFilter::kText_Type) |
| 35 return true; | 45 return true; |
| 36 | 46 |
| 37 paint->setLCDRenderText(false); | 47 paint->setLCDRenderText(false); |
| 38 return true; | 48 return true; |
| 39 } | 49 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 94 opaque_rect_y, | 104 opaque_rect_y, |
| 95 opaque_rect_width, | 105 opaque_rect_width, |
| 96 opaque_rect_height); | 106 opaque_rect_height); |
| 97 | 107 |
| 98 // Read the picture. This creates an empty picture on failure. | 108 // Read the picture. This creates an empty picture on failure. |
| 99 picture_ = skia::AdoptRef(new SkPicture(&stream, success, NULL)); | 109 picture_ = skia::AdoptRef(new SkPicture(&stream, success, NULL)); |
| 100 } | 110 } |
| 101 | 111 |
| 102 Picture::Picture(const skia::RefPtr<SkPicture>& picture, | 112 Picture::Picture(const skia::RefPtr<SkPicture>& picture, |
| 103 gfx::Rect layer_rect, | 113 gfx::Rect layer_rect, |
| 104 gfx::Rect opaque_rect) : | 114 gfx::Rect opaque_rect, |
| 115 const PixelRefsMap& lazy_pixel_refs) : | |
|
enne (OOO)
2013/04/22 19:10:56
PixelRefsMap => PixelRefMap?
vmpstr
2013/04/22 22:38:16
Done.
| |
| 105 layer_rect_(layer_rect), | 116 layer_rect_(layer_rect), |
| 106 opaque_rect_(opaque_rect), | 117 opaque_rect_(opaque_rect), |
| 107 picture_(picture) { | 118 picture_(picture), |
| 119 lazy_pixel_refs_(lazy_pixel_refs) { | |
| 108 } | 120 } |
| 109 | 121 |
| 110 Picture::~Picture() { | 122 Picture::~Picture() { |
| 111 } | 123 } |
| 112 | 124 |
| 113 scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread( | 125 scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread( |
| 114 unsigned thread_index) const { | 126 unsigned thread_index) const { |
| 115 // SkPicture is not thread-safe to rasterize with, this returns a clone | 127 // SkPicture is not thread-safe to rasterize with, this returns a clone |
| 116 // to rasterize with on a specific thread. | 128 // to rasterize with on a specific thread. |
| 117 CHECK_GT(clones_.size(), thread_index); | 129 CHECK_GT(clones_.size(), thread_index); |
| 118 return clones_[thread_index]; | 130 return clones_[thread_index]; |
| 119 } | 131 } |
| 120 | 132 |
| 121 void Picture::CloneForDrawing(int num_threads) { | 133 void Picture::CloneForDrawing(int num_threads) { |
| 122 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); | 134 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); |
| 123 | 135 |
| 124 DCHECK(picture_); | 136 DCHECK(picture_); |
| 125 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]); | 137 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]); |
| 126 picture_->clone(&clones[0], num_threads); | 138 picture_->clone(&clones[0], num_threads); |
| 127 | 139 |
| 128 clones_.clear(); | 140 clones_.clear(); |
| 129 for (int i = 0; i < num_threads; i++) { | 141 for (int i = 0; i < num_threads; i++) { |
| 130 scoped_refptr<Picture> clone = make_scoped_refptr( | 142 scoped_refptr<Picture> clone = make_scoped_refptr( |
| 131 new Picture(skia::AdoptRef(new SkPicture(clones[i])), | 143 new Picture(skia::AdoptRef(new SkPicture(clones[i])), |
| 132 layer_rect_, | 144 layer_rect_, |
| 133 opaque_rect_)); | 145 opaque_rect_, |
| 146 lazy_pixel_refs_)); | |
| 134 clones_.push_back(clone); | 147 clones_.push_back(clone); |
| 135 } | 148 } |
| 136 } | 149 } |
| 137 | 150 |
| 138 void Picture::Record(ContentLayerClient* painter, | 151 void Picture::Record(ContentLayerClient* painter, |
| 139 RenderingStats* stats, | 152 RenderingStats* stats, |
| 140 const SkTileGridPicture::TileGridInfo& tile_grid_info) { | 153 const SkTileGridPicture::TileGridInfo& tile_grid_info) { |
| 141 TRACE_EVENT2("cc", "Picture::Record", | 154 TRACE_EVENT2("cc", "Picture::Record", |
| 142 "width", layer_rect_.width(), "height", layer_rect_.height()); | 155 "width", layer_rect_.width(), "height", layer_rect_.height()); |
| 143 | 156 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 175 if (stats) { | 188 if (stats) { |
| 176 stats->total_paint_time += base::TimeTicks::Now() - begin_paint_time; | 189 stats->total_paint_time += base::TimeTicks::Now() - begin_paint_time; |
| 177 stats->total_pixels_painted += | 190 stats->total_pixels_painted += |
| 178 layer_rect_.width() * layer_rect_.height(); | 191 layer_rect_.width() * layer_rect_.height(); |
| 179 } | 192 } |
| 180 | 193 |
| 181 canvas->restore(); | 194 canvas->restore(); |
| 182 picture_->endRecording(); | 195 picture_->endRecording(); |
| 183 | 196 |
| 184 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); | 197 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); |
| 198 | |
| 199 GatherAllPixelRefs(); | |
| 185 } | 200 } |
| 186 | 201 |
| 187 void Picture::Raster( | 202 void Picture::Raster( |
| 188 SkCanvas* canvas, | 203 SkCanvas* canvas, |
| 189 gfx::Rect content_rect, | 204 gfx::Rect content_rect, |
| 190 float contents_scale, | 205 float contents_scale, |
| 191 bool enable_lcd_text) { | 206 bool enable_lcd_text) { |
| 192 TRACE_EVENT2("cc", "Picture::Raster", | 207 TRACE_EVENT2("cc", "Picture::Raster", |
| 193 "layer width", layer_rect_.width(), | 208 "layer width", layer_rect_.width(), |
| 194 "layer height", layer_rect_.height()); | 209 "layer height", layer_rect_.height()); |
| 195 DCHECK(picture_); | 210 DCHECK(picture_); |
| 196 | 211 |
| 197 DisableLCDTextFilter disable_lcd_text_filter; | 212 DisableLCDTextFilter disable_lcd_text_filter; |
| 198 | 213 |
| 199 canvas->save(); | 214 canvas->save(); |
| 200 canvas->clipRect(gfx::RectToSkRect(content_rect)); | 215 canvas->clipRect(gfx::RectToSkRect(content_rect)); |
| 201 canvas->scale(contents_scale, contents_scale); | 216 canvas->scale(contents_scale, contents_scale); |
| 202 canvas->translate(layer_rect_.x(), layer_rect_.y()); | 217 canvas->translate(layer_rect_.x(), layer_rect_.y()); |
| 203 // Pictures by default have LCD text enabled. | 218 // Pictures by default have LCD text enabled. |
| 204 if (!enable_lcd_text) | 219 if (!enable_lcd_text) |
| 205 canvas->setDrawFilter(&disable_lcd_text_filter); | 220 canvas->setDrawFilter(&disable_lcd_text_filter); |
| 206 canvas->drawPicture(*picture_); | 221 canvas->drawPicture(*picture_); |
| 207 canvas->restore(); | 222 canvas->restore(); |
| 208 } | 223 } |
| 209 | 224 |
| 210 void Picture::GatherPixelRefs(const gfx::Rect& layer_rect, | 225 void Picture::GatherPixelRefsFromSkia( |
| 211 std::list<skia::LazyPixelRef*>& pixel_ref_list) { | 226 const gfx::Rect& layer_rect, |
| 227 std::list<skia::LazyPixelRef*>& pixel_ref_list) { | |
| 212 DCHECK(picture_); | 228 DCHECK(picture_); |
| 213 SkData* pixel_refs = SkPictureUtils::GatherPixelRefs( | 229 SkData* pixel_refs = SkPictureUtils::GatherPixelRefs( |
| 214 picture_.get(), SkRect::MakeXYWH(layer_rect.x(), | 230 picture_.get(), SkRect::MakeXYWH(layer_rect.x() - layer_rect_.x(), |
| 215 layer_rect.y(), | 231 layer_rect.y() - layer_rect_.y(), |
|
enne (OOO)
2013/04/22 19:10:56
I think you mean 0? ;)
Is the reason for this bec
vmpstr
2013/04/22 22:38:16
No, it's actually a different rect... I renamed th
| |
| 216 layer_rect.width(), | 232 layer_rect.width(), |
| 217 layer_rect.height())); | 233 layer_rect.height())); |
| 218 if (!pixel_refs) | 234 if (!pixel_refs) |
| 219 return; | 235 return; |
| 220 | 236 |
| 221 void* data = const_cast<void*>(pixel_refs->data()); | 237 void* data = const_cast<void*>(pixel_refs->data()); |
| 222 if (!data) { | 238 if (!data) { |
| 223 pixel_refs->unref(); | 239 pixel_refs->unref(); |
| 224 return; | 240 return; |
| 225 } | 241 } |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 255 picture_->serialize(&stream); | 271 picture_->serialize(&stream); |
| 256 | 272 |
| 257 // Encode the picture as base64. | 273 // Encode the picture as base64. |
| 258 size_t serialized_size = stream.bytesWritten(); | 274 size_t serialized_size = stream.bytesWritten(); |
| 259 scoped_ptr<char[]> serialized_picture(new char[serialized_size]); | 275 scoped_ptr<char[]> serialized_picture(new char[serialized_size]); |
| 260 stream.copyTo(serialized_picture.get()); | 276 stream.copyTo(serialized_picture.get()); |
| 261 base::Base64Encode(std::string(serialized_picture.get(), serialized_size), | 277 base::Base64Encode(std::string(serialized_picture.get(), serialized_size), |
| 262 output); | 278 output); |
| 263 } | 279 } |
| 264 | 280 |
| 281 void Picture::GatherAllPixelRefs() { | |
| 282 int min_x = std::numeric_limits<int>::max(); | |
| 283 int min_y = std::numeric_limits<int>::max(); | |
| 284 int max_x = 0; | |
| 285 int max_y = 0; | |
| 286 | |
| 287 // Capture pixel refs for this picture in a grid | |
| 288 // with kRegionWidth by kRegionHeight cells. | |
| 289 for (int y = layer_rect_.y(); y < layer_rect_.bottom(); y += kRegionHeight) { | |
| 290 for (int x = layer_rect_.x(); x < layer_rect_.right(); x += kRegionWidth) { | |
| 291 gfx::Size extent(std::min(kRegionWidth, layer_rect_.right() - x), | |
| 292 std::min(kRegionHeight, layer_rect_.bottom() - y)); | |
| 293 gfx::Rect rect(x, y, extent.width(), extent.height()); | |
| 294 | |
| 295 std::list<skia::LazyPixelRef*> lazy_pixel_refs; | |
| 296 GatherPixelRefsFromSkia(rect, lazy_pixel_refs); | |
|
enne (OOO)
2013/04/22 19:10:56
If only Skia could just give us bounding rectangle
vmpstr
2013/04/22 22:38:16
Yep. Maybe they will in the future :D
| |
| 297 | |
| 298 // Only capture non-empty cells. | |
| 299 if (!lazy_pixel_refs.empty()) { | |
| 300 lazy_pixel_refs_[std::make_pair(x, y)].swap(lazy_pixel_refs); | |
| 301 min_x = std::min(min_x, x); | |
| 302 min_y = std::min(min_y, y); | |
| 303 max_x = std::max(max_x, x); | |
| 304 max_y = std::max(max_y, y); | |
| 305 } | |
| 306 } | |
| 307 } | |
| 308 | |
| 309 min_lazy_pixel_cell_ = gfx::Point(min_x, min_y); | |
| 310 max_lazy_pixel_cell_ = gfx::Point(max_x, max_y); | |
| 311 } | |
| 312 | |
| 313 Picture::LazyPixelRefIterator::LazyPixelRefIterator() | |
|
enne (OOO)
2013/04/22 19:10:56
Ok, this makes sense. Thanks for the default ctor
| |
| 314 : picture_(0), | |
|
reveman
2013/04/22 19:56:06
nit: indent 4 spaces
vmpstr
2013/04/22 22:38:16
Done.
| |
| 315 current_pixel_ref_(0), | |
| 316 min_point_(-1, -1), | |
| 317 max_point_(-1, -1), | |
| 318 current_x_(0), | |
| 319 current_y_(0) { | |
| 320 } | |
| 321 | |
| 322 Picture::LazyPixelRefIterator::LazyPixelRefIterator( | |
| 323 gfx::Rect rect, | |
| 324 const Picture* picture) | |
| 325 : picture_(picture), | |
| 326 current_pixel_ref_(NULL) { | |
| 327 gfx::Rect layer_rect = picture->layer_rect_; | |
| 328 | |
| 329 // We have to find a kRegionWidth/kRegionHeight aligned point that | |
| 330 // corresponds to the given rect. First, subtract the layer origin, | |
| 331 // then ensure the point is a multiple of kRegionWidth/kRegionHeight, | |
| 332 // and finally, add the layer origin back. | |
| 333 min_point_ = gfx::Point( | |
| 334 ((rect.x() - layer_rect.x()) / kRegionWidth) * kRegionWidth | |
| 335 + layer_rect.x(), | |
| 336 ((rect.y() - layer_rect.y()) / kRegionHeight) * kRegionHeight | |
| 337 + layer_rect.y()); | |
| 338 max_point_ = gfx::Point( | |
| 339 ((rect.right() - layer_rect.x()) / kRegionWidth) * kRegionWidth | |
| 340 + layer_rect.x(), | |
| 341 ((rect.bottom() - layer_rect.y()) / kRegionHeight) * kRegionHeight | |
| 342 + layer_rect.y()); | |
| 343 | |
| 344 // Limit the points to knows pixel ref boundaries. | |
| 345 min_point_ = gfx::Point( | |
| 346 std::max(min_point_.x(), picture->min_lazy_pixel_cell_.x()), | |
|
enne (OOO)
2013/04/22 19:10:56
I think this is wrong. lazy_pixel_cell is in laye
vmpstr
2013/04/22 22:38:16
This is actually in layer space, since I add layer
| |
| 347 std::max(min_point_.y(), picture->min_lazy_pixel_cell_.y())); | |
| 348 max_point_ = gfx::Point( | |
| 349 std::min(max_point_.x(), picture->max_lazy_pixel_cell_.x()), | |
| 350 std::min(max_point_.y(), picture->max_lazy_pixel_cell_.y())); | |
| 351 | |
| 352 // Make the current x be kRegionWidth less than min point, so that | |
| 353 // the first increment will point at min_point_. | |
| 354 current_x_ = min_point_.x() - kRegionWidth; | |
| 355 current_y_ = min_point_.y(); | |
| 356 ++(*this); | |
| 357 } | |
| 358 | |
| 359 Picture::LazyPixelRefIterator::~LazyPixelRefIterator() { | |
| 360 } | |
| 361 | |
| 362 Picture::LazyPixelRefIterator& Picture::LazyPixelRefIterator::operator++() { | |
| 363 // If we're not at the end of the list, then just get the next item. | |
| 364 if (!current_list_.empty()) { | |
| 365 current_pixel_ref_ = current_list_.front(); | |
| 366 current_list_.pop_front(); | |
| 367 return *this; | |
| 368 } | |
| 369 | |
| 370 // If we already passed the max y, do nothing. | |
| 371 if (current_y_ > max_point_.y()) | |
| 372 return *this; | |
| 373 | |
| 374 while (true) { | |
| 375 // Advance the current grid cell. | |
| 376 current_x_ += kRegionWidth; | |
| 377 if (current_x_ > max_point_.x()) { | |
| 378 current_y_ += kRegionHeight; | |
| 379 current_x_ = min_point_.x(); | |
| 380 if (current_y_ > max_point_.y()) { | |
| 381 current_pixel_ref_ = NULL; | |
| 382 break; | |
| 383 } | |
| 384 } | |
| 385 | |
| 386 // If there are no pixel refs at this grid cell, keep incrementing. | |
| 387 PixelRefsMap::const_iterator iter = | |
| 388 picture_->lazy_pixel_refs_.find(std::make_pair(current_x_, current_y_)); | |
| 389 if (iter == picture_->lazy_pixel_refs_.end() || iter->second.empty()) | |
|
reveman
2013/04/22 19:56:06
can "iter->second.empty()" ever be true?
vmpstr
2013/04/22 22:38:16
Nope, I removed it.
| |
| 390 continue; | |
| 391 | |
| 392 // We found a non-empty list: store it and get the first pixel ref. | |
| 393 current_list_ = iter->second; | |
|
reveman
2013/04/22 19:56:06
Can we avoid copying this list while iterating? lo
vmpstr
2013/04/22 22:38:16
Done.
| |
| 394 current_pixel_ref_ = current_list_.front(); | |
| 395 current_list_.pop_front(); | |
| 396 break; | |
| 397 } | |
| 398 return *this; | |
| 399 } | |
| 400 | |
| 265 } // namespace cc | 401 } // namespace cc |
| OLD | NEW |