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" |
| 13 #include "cc/base/util.h" |
9 #include "cc/debug/rendering_stats.h" | 14 #include "cc/debug/rendering_stats.h" |
10 #include "cc/layers/content_layer_client.h" | 15 #include "cc/layers/content_layer_client.h" |
11 #include "skia/ext/analysis_canvas.h" | 16 #include "skia/ext/analysis_canvas.h" |
12 #include "third_party/skia/include/core/SkCanvas.h" | 17 #include "third_party/skia/include/core/SkCanvas.h" |
13 #include "third_party/skia/include/core/SkData.h" | 18 #include "third_party/skia/include/core/SkData.h" |
14 #include "third_party/skia/include/core/SkDrawFilter.h" | 19 #include "third_party/skia/include/core/SkDrawFilter.h" |
15 #include "third_party/skia/include/core/SkPaint.h" | 20 #include "third_party/skia/include/core/SkPaint.h" |
16 #include "third_party/skia/include/core/SkStream.h" | 21 #include "third_party/skia/include/core/SkStream.h" |
17 #include "third_party/skia/include/utils/SkPictureUtils.h" | 22 #include "third_party/skia/include/utils/SkPictureUtils.h" |
18 #include "ui/gfx/rect_conversions.h" | 23 #include "ui/gfx/rect_conversions.h" |
19 #include "ui/gfx/skia_util.h" | 24 #include "ui/gfx/skia_util.h" |
20 | 25 |
21 namespace { | 26 namespace { |
22 // URI label for a lazily decoded SkPixelRef. | 27 // URI label for a lazily decoded SkPixelRef. |
23 const char kLabelLazyDecoded[] = "lazy"; | 28 const char kLabelLazyDecoded[] = "lazy"; |
| 29 |
24 // Version ID; to be used in serialization. | 30 // Version ID; to be used in serialization. |
25 const int kPictureVersion = 1; | 31 const int kPictureVersion = 1; |
| 32 |
26 // Minimum size of a decoded stream that we need. | 33 // Minimum size of a decoded stream that we need. |
27 // 4 bytes for version, 4 * 4 for each of the 2 rects. | 34 // 4 bytes for version, 4 * 4 for each of the 2 rects. |
28 const unsigned int kMinPictureSizeBytes = 36; | 35 const unsigned int kMinPictureSizeBytes = 36; |
29 | 36 |
30 class DisableLCDTextFilter : public SkDrawFilter { | 37 class DisableLCDTextFilter : public SkDrawFilter { |
31 public: | 38 public: |
32 // SkDrawFilter interface. | 39 // SkDrawFilter interface. |
33 virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE { | 40 virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE { |
34 if (type != SkDrawFilter::kText_Type) | 41 if (type != SkDrawFilter::kText_Type) |
35 return true; | 42 return true; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 opaque_rect_y, | 101 opaque_rect_y, |
95 opaque_rect_width, | 102 opaque_rect_width, |
96 opaque_rect_height); | 103 opaque_rect_height); |
97 | 104 |
98 // Read the picture. This creates an empty picture on failure. | 105 // Read the picture. This creates an empty picture on failure. |
99 picture_ = skia::AdoptRef(new SkPicture(&stream, success, NULL)); | 106 picture_ = skia::AdoptRef(new SkPicture(&stream, success, NULL)); |
100 } | 107 } |
101 | 108 |
102 Picture::Picture(const skia::RefPtr<SkPicture>& picture, | 109 Picture::Picture(const skia::RefPtr<SkPicture>& picture, |
103 gfx::Rect layer_rect, | 110 gfx::Rect layer_rect, |
104 gfx::Rect opaque_rect) : | 111 gfx::Rect opaque_rect, |
| 112 const PixelRefMap& pixel_refs) : |
105 layer_rect_(layer_rect), | 113 layer_rect_(layer_rect), |
106 opaque_rect_(opaque_rect), | 114 opaque_rect_(opaque_rect), |
107 picture_(picture) { | 115 picture_(picture), |
| 116 pixel_refs_(pixel_refs) { |
108 } | 117 } |
109 | 118 |
110 Picture::~Picture() { | 119 Picture::~Picture() { |
111 } | 120 } |
112 | 121 |
113 scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread( | 122 scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread( |
114 unsigned thread_index) const { | 123 unsigned thread_index) const { |
115 // SkPicture is not thread-safe to rasterize with, this returns a clone | 124 // SkPicture is not thread-safe to rasterize with, this returns a clone |
116 // to rasterize with on a specific thread. | 125 // to rasterize with on a specific thread. |
117 CHECK_GT(clones_.size(), thread_index); | 126 CHECK_GT(clones_.size(), thread_index); |
118 return clones_[thread_index]; | 127 return clones_[thread_index]; |
119 } | 128 } |
120 | 129 |
121 void Picture::CloneForDrawing(int num_threads) { | 130 void Picture::CloneForDrawing(int num_threads) { |
122 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); | 131 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); |
123 | 132 |
124 DCHECK(picture_); | 133 DCHECK(picture_); |
125 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]); | 134 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]); |
126 picture_->clone(&clones[0], num_threads); | 135 picture_->clone(&clones[0], num_threads); |
127 | 136 |
128 clones_.clear(); | 137 clones_.clear(); |
129 for (int i = 0; i < num_threads; i++) { | 138 for (int i = 0; i < num_threads; i++) { |
130 scoped_refptr<Picture> clone = make_scoped_refptr( | 139 scoped_refptr<Picture> clone = make_scoped_refptr( |
131 new Picture(skia::AdoptRef(new SkPicture(clones[i])), | 140 new Picture(skia::AdoptRef(new SkPicture(clones[i])), |
132 layer_rect_, | 141 layer_rect_, |
133 opaque_rect_)); | 142 opaque_rect_, |
| 143 pixel_refs_)); |
134 clones_.push_back(clone); | 144 clones_.push_back(clone); |
135 } | 145 } |
136 } | 146 } |
137 | 147 |
138 void Picture::Record(ContentLayerClient* painter, | 148 void Picture::Record(ContentLayerClient* painter, |
139 RenderingStats* stats, | 149 RenderingStats* stats, |
140 const SkTileGridPicture::TileGridInfo& tile_grid_info) { | 150 const SkTileGridPicture::TileGridInfo& tile_grid_info) { |
141 TRACE_EVENT2("cc", "Picture::Record", | 151 TRACE_EVENT2("cc", "Picture::Record", |
142 "width", layer_rect_.width(), "height", layer_rect_.height()); | 152 "width", layer_rect_.width(), "height", layer_rect_.height()); |
143 | 153 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 if (stats) { | 185 if (stats) { |
176 stats->total_paint_time += base::TimeTicks::Now() - begin_paint_time; | 186 stats->total_paint_time += base::TimeTicks::Now() - begin_paint_time; |
177 stats->total_pixels_painted += | 187 stats->total_pixels_painted += |
178 layer_rect_.width() * layer_rect_.height(); | 188 layer_rect_.width() * layer_rect_.height(); |
179 } | 189 } |
180 | 190 |
181 canvas->restore(); | 191 canvas->restore(); |
182 picture_->endRecording(); | 192 picture_->endRecording(); |
183 | 193 |
184 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); | 194 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); |
| 195 |
| 196 cell_size_ = gfx::Size( |
| 197 tile_grid_info.fTileInterval.width() + |
| 198 2 * tile_grid_info.fMargin.width(), |
| 199 tile_grid_info.fTileInterval.height() + |
| 200 2 * tile_grid_info.fMargin.height()); |
| 201 DCHECK_GT(cell_size_.width(), 0); |
| 202 DCHECK_GT(cell_size_.height(), 0); |
| 203 GatherAllPixelRefs(); |
185 } | 204 } |
186 | 205 |
187 void Picture::Raster( | 206 void Picture::Raster( |
188 SkCanvas* canvas, | 207 SkCanvas* canvas, |
189 gfx::Rect content_rect, | 208 gfx::Rect content_rect, |
190 float contents_scale, | 209 float contents_scale, |
191 bool enable_lcd_text) { | 210 bool enable_lcd_text) { |
192 TRACE_EVENT2("cc", "Picture::Raster", | 211 TRACE_EVENT2("cc", "Picture::Raster", |
193 "layer width", layer_rect_.width(), | 212 "layer width", layer_rect_.width(), |
194 "layer height", layer_rect_.height()); | 213 "layer height", layer_rect_.height()); |
195 DCHECK(picture_); | 214 DCHECK(picture_); |
196 | 215 |
197 DisableLCDTextFilter disable_lcd_text_filter; | 216 DisableLCDTextFilter disable_lcd_text_filter; |
198 | 217 |
199 canvas->save(); | 218 canvas->save(); |
200 canvas->clipRect(gfx::RectToSkRect(content_rect)); | 219 canvas->clipRect(gfx::RectToSkRect(content_rect)); |
201 canvas->scale(contents_scale, contents_scale); | 220 canvas->scale(contents_scale, contents_scale); |
202 canvas->translate(layer_rect_.x(), layer_rect_.y()); | 221 canvas->translate(layer_rect_.x(), layer_rect_.y()); |
203 // Pictures by default have LCD text enabled. | 222 // Pictures by default have LCD text enabled. |
204 if (!enable_lcd_text) | 223 if (!enable_lcd_text) |
205 canvas->setDrawFilter(&disable_lcd_text_filter); | 224 canvas->setDrawFilter(&disable_lcd_text_filter); |
206 canvas->drawPicture(*picture_); | 225 canvas->drawPicture(*picture_); |
207 canvas->restore(); | 226 canvas->restore(); |
208 } | 227 } |
209 | 228 |
210 void Picture::GatherPixelRefs(const gfx::Rect& layer_rect, | 229 void Picture::GatherPixelRefsFromSkia( |
211 std::list<skia::LazyPixelRef*>& pixel_ref_list) { | 230 gfx::Rect query_rect, |
| 231 std::vector<skia::LazyPixelRef*>* pixel_refs) { |
212 DCHECK(picture_); | 232 DCHECK(picture_); |
213 SkData* pixel_refs = SkPictureUtils::GatherPixelRefs( | 233 SkData* pixel_ref_data = SkPictureUtils::GatherPixelRefs( |
214 picture_.get(), SkRect::MakeXYWH(layer_rect.x(), | 234 picture_.get(), |
215 layer_rect.y(), | 235 SkRect::MakeXYWH(query_rect.x() - layer_rect_.x(), |
216 layer_rect.width(), | 236 query_rect.y() - layer_rect_.y(), |
217 layer_rect.height())); | 237 query_rect.width(), |
218 if (!pixel_refs) | 238 query_rect.height())); |
| 239 if (!pixel_ref_data) |
219 return; | 240 return; |
220 | 241 |
221 void* data = const_cast<void*>(pixel_refs->data()); | 242 void* data = const_cast<void*>(pixel_ref_data->data()); |
222 if (!data) { | 243 if (!data) { |
223 pixel_refs->unref(); | 244 pixel_ref_data->unref(); |
224 return; | 245 return; |
225 } | 246 } |
226 | 247 |
227 SkPixelRef** refs = reinterpret_cast<SkPixelRef**>(data); | 248 SkPixelRef** refs = reinterpret_cast<SkPixelRef**>(data); |
228 for (size_t i = 0; i < pixel_refs->size() / sizeof(*refs); ++i) { | 249 for (size_t i = 0; i < pixel_ref_data->size() / sizeof(*refs); ++i) { |
229 if (*refs && (*refs)->getURI() && !strncmp( | 250 if (*refs && (*refs)->getURI() && !strncmp( |
230 (*refs)->getURI(), kLabelLazyDecoded, 4)) { | 251 (*refs)->getURI(), kLabelLazyDecoded, 4)) { |
231 pixel_ref_list.push_back(static_cast<skia::LazyPixelRef*>(*refs)); | 252 pixel_refs->push_back(static_cast<skia::LazyPixelRef*>(*refs)); |
232 } | 253 } |
233 refs++; | 254 refs++; |
234 } | 255 } |
235 pixel_refs->unref(); | 256 pixel_ref_data->unref(); |
236 } | 257 } |
237 | 258 |
238 void Picture::AsBase64String(std::string* output) const { | 259 void Picture::AsBase64String(std::string* output) const { |
239 SkDynamicMemoryWStream stream; | 260 SkDynamicMemoryWStream stream; |
240 | 261 |
241 // First save the version, layer_rect_ and opaque_rect. | 262 // First save the version, layer_rect_ and opaque_rect. |
242 stream.write32(kPictureVersion); | 263 stream.write32(kPictureVersion); |
243 | 264 |
244 stream.write32(layer_rect_.x()); | 265 stream.write32(layer_rect_.x()); |
245 stream.write32(layer_rect_.y()); | 266 stream.write32(layer_rect_.y()); |
246 stream.write32(layer_rect_.width()); | 267 stream.write32(layer_rect_.width()); |
247 stream.write32(layer_rect_.height()); | 268 stream.write32(layer_rect_.height()); |
248 | 269 |
249 stream.write32(opaque_rect_.x()); | 270 stream.write32(opaque_rect_.x()); |
250 stream.write32(opaque_rect_.y()); | 271 stream.write32(opaque_rect_.y()); |
251 stream.write32(opaque_rect_.width()); | 272 stream.write32(opaque_rect_.width()); |
252 stream.write32(opaque_rect_.height()); | 273 stream.write32(opaque_rect_.height()); |
253 | 274 |
254 // Serialize the picture. | 275 // Serialize the picture. |
255 picture_->serialize(&stream); | 276 picture_->serialize(&stream); |
256 | 277 |
257 // Encode the picture as base64. | 278 // Encode the picture as base64. |
258 size_t serialized_size = stream.bytesWritten(); | 279 size_t serialized_size = stream.bytesWritten(); |
259 scoped_ptr<char[]> serialized_picture(new char[serialized_size]); | 280 scoped_ptr<char[]> serialized_picture(new char[serialized_size]); |
260 stream.copyTo(serialized_picture.get()); | 281 stream.copyTo(serialized_picture.get()); |
261 base::Base64Encode(std::string(serialized_picture.get(), serialized_size), | 282 base::Base64Encode(std::string(serialized_picture.get(), serialized_size), |
262 output); | 283 output); |
263 } | 284 } |
264 | 285 |
| 286 void Picture::GatherAllPixelRefs() { |
| 287 int min_x = std::numeric_limits<int>::max(); |
| 288 int min_y = std::numeric_limits<int>::max(); |
| 289 int max_x = 0; |
| 290 int max_y = 0; |
| 291 |
| 292 // Capture pixel refs for this picture in a grid |
| 293 // with cell_size_ sized cells. |
| 294 for (int y = layer_rect_.y(); |
| 295 y < layer_rect_.bottom(); |
| 296 y += cell_size_.height()) { |
| 297 for (int x = layer_rect_.x(); |
| 298 x < layer_rect_.right(); |
| 299 x += cell_size_.width()) { |
| 300 gfx::Rect rect(gfx::Point(x, y), cell_size_); |
| 301 rect.Intersect(layer_rect_); |
| 302 |
| 303 std::vector<skia::LazyPixelRef*> pixel_refs; |
| 304 GatherPixelRefsFromSkia(rect, &pixel_refs); |
| 305 |
| 306 // Only capture non-empty cells. |
| 307 if (!pixel_refs.empty()) { |
| 308 pixel_refs_[PixelRefMapKey(x, y)].swap(pixel_refs); |
| 309 min_x = std::min(min_x, x); |
| 310 min_y = std::min(min_y, y); |
| 311 max_x = std::max(max_x, x); |
| 312 max_y = std::max(max_y, y); |
| 313 } |
| 314 } |
| 315 } |
| 316 |
| 317 min_pixel_cell_ = gfx::Point(min_x, min_y); |
| 318 max_pixel_cell_ = gfx::Point(max_x, max_y); |
| 319 } |
| 320 |
| 321 Picture::PixelRefIterator::PixelRefIterator() |
| 322 : picture_(NULL), |
| 323 min_point_(-1, -1), |
| 324 max_point_(-1, -1), |
| 325 current_x_(0), |
| 326 current_y_(0) { |
| 327 sentinel_.push_back(NULL); |
| 328 current_pixel_refs_ = &sentinel_; |
| 329 current_iterator_ = current_pixel_refs_->begin(); |
| 330 } |
| 331 |
| 332 Picture::PixelRefIterator::PixelRefIterator(const PixelRefIterator& other) { |
| 333 sentinel_.push_back(NULL); |
| 334 *this = other; |
| 335 } |
| 336 |
| 337 Picture::PixelRefIterator::PixelRefIterator( |
| 338 gfx::Rect query_rect, |
| 339 const Picture* picture) |
| 340 : picture_(picture) { |
| 341 gfx::Rect layer_rect = picture->layer_rect_; |
| 342 gfx::Size cell_size = picture->cell_size_; |
| 343 |
| 344 sentinel_.push_back(NULL); |
| 345 current_pixel_refs_ = &sentinel_; |
| 346 current_iterator_ = current_pixel_refs_->begin(); |
| 347 |
| 348 // Early out if the query rect doesn't intersect this picture |
| 349 if (!query_rect.Intersects(layer_rect)) { |
| 350 min_point_ = gfx::Point(0, 0); |
| 351 max_point_ = gfx::Point(0, 0); |
| 352 current_x_ = 1; |
| 353 current_y_ = 1; |
| 354 return; |
| 355 } |
| 356 |
| 357 // We have to find a cell_size aligned point that |
| 358 // corresponds to query_rect. First, subtract the layer origin, |
| 359 // then ensure the point is a multiple of cell_size, |
| 360 // and finally, add the layer origin back. |
| 361 min_point_ = gfx::Point( |
| 362 RoundDown(query_rect.x() - layer_rect.x(), cell_size.width()) |
| 363 + layer_rect.x(), |
| 364 RoundDown(query_rect.y() - layer_rect.y(), cell_size.height()) |
| 365 + layer_rect.y()); |
| 366 max_point_ = gfx::Point( |
| 367 RoundDown(query_rect.right() - layer_rect.x() - 1, cell_size.width()) |
| 368 + layer_rect.x(), |
| 369 RoundDown(query_rect.bottom() - layer_rect.y() - 1, cell_size.height()) |
| 370 + layer_rect.y()); |
| 371 |
| 372 // Limit the points to known pixel ref boundaries. |
| 373 min_point_ = gfx::Point( |
| 374 std::max(min_point_.x(), picture->min_pixel_cell_.x()), |
| 375 std::max(min_point_.y(), picture->min_pixel_cell_.y())); |
| 376 max_point_ = gfx::Point( |
| 377 std::min(max_point_.x(), picture->max_pixel_cell_.x()), |
| 378 std::min(max_point_.y(), picture->max_pixel_cell_.y())); |
| 379 |
| 380 // Make the current x be cell_size.width() less than min point, so that |
| 381 // the first increment will point at min_point_. |
| 382 current_x_ = min_point_.x() - cell_size.width(); |
| 383 current_y_ = min_point_.y(); |
| 384 ++(*this); |
| 385 } |
| 386 |
| 387 Picture::PixelRefIterator::~PixelRefIterator() { |
| 388 } |
| 389 |
| 390 Picture::PixelRefIterator& Picture::PixelRefIterator::operator++() { |
| 391 ++current_iterator_; |
| 392 // If we're not at the end of the list, then we have the next item. |
| 393 if (current_iterator_ != current_pixel_refs_->end()) |
| 394 return *this; |
| 395 |
| 396 // If we already passed the max y, reset back to sentinel list. |
| 397 if (current_y_ > max_point_.y()) { |
| 398 current_pixel_refs_ = &sentinel_; |
| 399 current_iterator_ = current_pixel_refs_->begin(); |
| 400 return *this; |
| 401 } |
| 402 |
| 403 while (true) { |
| 404 gfx::Size cell_size = picture_->cell_size_; |
| 405 |
| 406 // Advance the current grid cell. |
| 407 current_x_ += cell_size.width(); |
| 408 if (current_x_ > max_point_.x()) { |
| 409 current_y_ += cell_size.height(); |
| 410 current_x_ = min_point_.x(); |
| 411 if (current_y_ > max_point_.y()) { |
| 412 current_pixel_refs_ = &sentinel_; |
| 413 current_iterator_ = current_pixel_refs_->begin(); |
| 414 break; |
| 415 } |
| 416 } |
| 417 |
| 418 // If there are no pixel refs at this grid cell, keep incrementing. |
| 419 PixelRefMapKey key(current_x_, current_y_); |
| 420 PixelRefMap::const_iterator iter = picture_->pixel_refs_.find(key); |
| 421 if (iter == picture_->pixel_refs_.end()) |
| 422 continue; |
| 423 |
| 424 // We found a non-empty list: store it and get the first pixel ref. |
| 425 current_pixel_refs_ = &iter->second; |
| 426 current_iterator_ = current_pixel_refs_->begin(); |
| 427 break; |
| 428 } |
| 429 return *this; |
| 430 } |
| 431 |
| 432 Picture::PixelRefIterator& Picture::PixelRefIterator::operator=( |
| 433 const PixelRefIterator& other) { |
| 434 if (this == &other) |
| 435 return *this; |
| 436 |
| 437 picture_ = other.picture_; |
| 438 // If other is pointing to its sentinel list, set |
| 439 // the iterator to point to our sentinel list. |
| 440 if (other.current_pixel_refs_ == &other.sentinel_) { |
| 441 current_pixel_refs_ = &sentinel_; |
| 442 current_iterator_ = current_pixel_refs_->begin(); |
| 443 } else { |
| 444 current_pixel_refs_ = other.current_pixel_refs_; |
| 445 current_iterator_ = other.current_iterator_; |
| 446 } |
| 447 min_point_ = other.min_point_; |
| 448 max_point_ = other.max_point_; |
| 449 current_x_ = other.current_x_; |
| 450 current_y_ = other.current_y_; |
| 451 return *this; |
| 452 } |
| 453 |
265 } // namespace cc | 454 } // namespace cc |
OLD | NEW |