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 int ToMultiple(int value, int multiple) { | |
enne (OOO)
2013/04/23 01:59:39
Should this be moved to cc/base/util.h as RoundDow
vmpstr
2013/04/23 20:02:23
Done.
| |
37 return (value < 0) ? | |
38 (value / multiple - 1) * multiple | |
39 : (value / multiple) * multiple; | |
40 } | |
41 | |
30 class DisableLCDTextFilter : public SkDrawFilter { | 42 class DisableLCDTextFilter : public SkDrawFilter { |
31 public: | 43 public: |
32 // SkDrawFilter interface. | 44 // SkDrawFilter interface. |
33 virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE { | 45 virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) OVERRIDE { |
34 if (type != SkDrawFilter::kText_Type) | 46 if (type != SkDrawFilter::kText_Type) |
35 return true; | 47 return true; |
36 | 48 |
37 paint->setLCDRenderText(false); | 49 paint->setLCDRenderText(false); |
38 return true; | 50 return true; |
39 } | 51 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
94 opaque_rect_y, | 106 opaque_rect_y, |
95 opaque_rect_width, | 107 opaque_rect_width, |
96 opaque_rect_height); | 108 opaque_rect_height); |
97 | 109 |
98 // Read the picture. This creates an empty picture on failure. | 110 // Read the picture. This creates an empty picture on failure. |
99 picture_ = skia::AdoptRef(new SkPicture(&stream, success, NULL)); | 111 picture_ = skia::AdoptRef(new SkPicture(&stream, success, NULL)); |
100 } | 112 } |
101 | 113 |
102 Picture::Picture(const skia::RefPtr<SkPicture>& picture, | 114 Picture::Picture(const skia::RefPtr<SkPicture>& picture, |
103 gfx::Rect layer_rect, | 115 gfx::Rect layer_rect, |
104 gfx::Rect opaque_rect) : | 116 gfx::Rect opaque_rect, |
117 const PixelRefMap& lazy_pixel_refs) : | |
105 layer_rect_(layer_rect), | 118 layer_rect_(layer_rect), |
106 opaque_rect_(opaque_rect), | 119 opaque_rect_(opaque_rect), |
107 picture_(picture) { | 120 picture_(picture), |
121 lazy_pixel_refs_(lazy_pixel_refs) { | |
108 } | 122 } |
109 | 123 |
110 Picture::~Picture() { | 124 Picture::~Picture() { |
111 } | 125 } |
112 | 126 |
113 scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread( | 127 scoped_refptr<Picture> Picture::GetCloneForDrawingOnThread( |
114 unsigned thread_index) const { | 128 unsigned thread_index) const { |
115 // SkPicture is not thread-safe to rasterize with, this returns a clone | 129 // SkPicture is not thread-safe to rasterize with, this returns a clone |
116 // to rasterize with on a specific thread. | 130 // to rasterize with on a specific thread. |
117 CHECK_GT(clones_.size(), thread_index); | 131 CHECK_GT(clones_.size(), thread_index); |
118 return clones_[thread_index]; | 132 return clones_[thread_index]; |
119 } | 133 } |
120 | 134 |
121 void Picture::CloneForDrawing(int num_threads) { | 135 void Picture::CloneForDrawing(int num_threads) { |
122 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); | 136 TRACE_EVENT1("cc", "Picture::CloneForDrawing", "num_threads", num_threads); |
123 | 137 |
124 DCHECK(picture_); | 138 DCHECK(picture_); |
125 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]); | 139 scoped_ptr<SkPicture[]> clones(new SkPicture[num_threads]); |
126 picture_->clone(&clones[0], num_threads); | 140 picture_->clone(&clones[0], num_threads); |
127 | 141 |
128 clones_.clear(); | 142 clones_.clear(); |
129 for (int i = 0; i < num_threads; i++) { | 143 for (int i = 0; i < num_threads; i++) { |
130 scoped_refptr<Picture> clone = make_scoped_refptr( | 144 scoped_refptr<Picture> clone = make_scoped_refptr( |
131 new Picture(skia::AdoptRef(new SkPicture(clones[i])), | 145 new Picture(skia::AdoptRef(new SkPicture(clones[i])), |
132 layer_rect_, | 146 layer_rect_, |
133 opaque_rect_)); | 147 opaque_rect_, |
148 lazy_pixel_refs_)); | |
134 clones_.push_back(clone); | 149 clones_.push_back(clone); |
135 } | 150 } |
136 } | 151 } |
137 | 152 |
138 void Picture::Record(ContentLayerClient* painter, | 153 void Picture::Record(ContentLayerClient* painter, |
139 RenderingStats* stats, | 154 RenderingStats* stats, |
140 const SkTileGridPicture::TileGridInfo& tile_grid_info) { | 155 const SkTileGridPicture::TileGridInfo& tile_grid_info) { |
141 TRACE_EVENT2("cc", "Picture::Record", | 156 TRACE_EVENT2("cc", "Picture::Record", |
142 "width", layer_rect_.width(), "height", layer_rect_.height()); | 157 "width", layer_rect_.width(), "height", layer_rect_.height()); |
143 | 158 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
175 if (stats) { | 190 if (stats) { |
176 stats->total_paint_time += base::TimeTicks::Now() - begin_paint_time; | 191 stats->total_paint_time += base::TimeTicks::Now() - begin_paint_time; |
177 stats->total_pixels_painted += | 192 stats->total_pixels_painted += |
178 layer_rect_.width() * layer_rect_.height(); | 193 layer_rect_.width() * layer_rect_.height(); |
179 } | 194 } |
180 | 195 |
181 canvas->restore(); | 196 canvas->restore(); |
182 picture_->endRecording(); | 197 picture_->endRecording(); |
183 | 198 |
184 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); | 199 opaque_rect_ = gfx::ToEnclosedRect(opaque_layer_rect); |
200 | |
201 cell_size_ = gfx::Size( | |
enne (OOO)
2013/04/23 01:59:39
For what it's worth, this isn't going to line up w
reveman
2013/04/23 14:33:24
I would vote for getting this to line up properly
vmpstr
2013/04/23 20:02:23
I think I fixed this. Right now, when we do gather
| |
202 tile_grid_info.fTileInterval.width() + | |
203 2 * tile_grid_info.fMargin.width(), | |
204 tile_grid_info.fTileInterval.height() + | |
205 2 * tile_grid_info.fMargin.height()); | |
206 DCHECK_GT(cell_size_.width(), 0); | |
207 DCHECK_GT(cell_size_.height(), 0); | |
208 GatherAllPixelRefs(); | |
185 } | 209 } |
186 | 210 |
187 void Picture::Raster( | 211 void Picture::Raster( |
188 SkCanvas* canvas, | 212 SkCanvas* canvas, |
189 gfx::Rect content_rect, | 213 gfx::Rect content_rect, |
190 float contents_scale, | 214 float contents_scale, |
191 bool enable_lcd_text) { | 215 bool enable_lcd_text) { |
192 TRACE_EVENT2("cc", "Picture::Raster", | 216 TRACE_EVENT2("cc", "Picture::Raster", |
193 "layer width", layer_rect_.width(), | 217 "layer width", layer_rect_.width(), |
194 "layer height", layer_rect_.height()); | 218 "layer height", layer_rect_.height()); |
195 DCHECK(picture_); | 219 DCHECK(picture_); |
196 | 220 |
197 DisableLCDTextFilter disable_lcd_text_filter; | 221 DisableLCDTextFilter disable_lcd_text_filter; |
198 | 222 |
199 canvas->save(); | 223 canvas->save(); |
200 canvas->clipRect(gfx::RectToSkRect(content_rect)); | 224 canvas->clipRect(gfx::RectToSkRect(content_rect)); |
201 canvas->scale(contents_scale, contents_scale); | 225 canvas->scale(contents_scale, contents_scale); |
202 canvas->translate(layer_rect_.x(), layer_rect_.y()); | 226 canvas->translate(layer_rect_.x(), layer_rect_.y()); |
203 // Pictures by default have LCD text enabled. | 227 // Pictures by default have LCD text enabled. |
204 if (!enable_lcd_text) | 228 if (!enable_lcd_text) |
205 canvas->setDrawFilter(&disable_lcd_text_filter); | 229 canvas->setDrawFilter(&disable_lcd_text_filter); |
206 canvas->drawPicture(*picture_); | 230 canvas->drawPicture(*picture_); |
207 canvas->restore(); | 231 canvas->restore(); |
208 } | 232 } |
209 | 233 |
210 void Picture::GatherPixelRefs(const gfx::Rect& layer_rect, | 234 void Picture::GatherPixelRefsFromSkia( |
211 std::list<skia::LazyPixelRef*>& pixel_ref_list) { | 235 const gfx::Rect& query_rect, |
enne (OOO)
2013/04/23 01:59:39
const gfx::Rect& => gfx::Rect
vmpstr
2013/04/23 20:02:23
Done.
| |
236 std::list<skia::LazyPixelRef*>& pixel_ref_list) { | |
reveman
2013/04/23 14:33:24
nit: while you're here. I think the style guide re
vmpstr
2013/04/23 20:02:23
Done.
| |
212 DCHECK(picture_); | 237 DCHECK(picture_); |
213 SkData* pixel_refs = SkPictureUtils::GatherPixelRefs( | 238 SkData* pixel_refs = SkPictureUtils::GatherPixelRefs( |
214 picture_.get(), SkRect::MakeXYWH(layer_rect.x(), | 239 picture_.get(), SkRect::MakeXYWH(query_rect.x() - layer_rect_.x(), |
enne (OOO)
2013/04/23 01:59:39
Haha. Sorry for misreading earlier. Calling it q
vmpstr
2013/04/23 20:02:23
Yeah, I vote in general to avoid naming completely
| |
215 layer_rect.y(), | 240 query_rect.y() - layer_rect_.y(), |
216 layer_rect.width(), | 241 query_rect.width(), |
217 layer_rect.height())); | 242 query_rect.height())); |
218 if (!pixel_refs) | 243 if (!pixel_refs) |
219 return; | 244 return; |
220 | 245 |
221 void* data = const_cast<void*>(pixel_refs->data()); | 246 void* data = const_cast<void*>(pixel_refs->data()); |
222 if (!data) { | 247 if (!data) { |
223 pixel_refs->unref(); | 248 pixel_refs->unref(); |
224 return; | 249 return; |
225 } | 250 } |
226 | 251 |
227 SkPixelRef** refs = reinterpret_cast<SkPixelRef**>(data); | 252 SkPixelRef** refs = reinterpret_cast<SkPixelRef**>(data); |
(...skipping 27 matching lines...) Expand all Loading... | |
255 picture_->serialize(&stream); | 280 picture_->serialize(&stream); |
256 | 281 |
257 // Encode the picture as base64. | 282 // Encode the picture as base64. |
258 size_t serialized_size = stream.bytesWritten(); | 283 size_t serialized_size = stream.bytesWritten(); |
259 scoped_ptr<char[]> serialized_picture(new char[serialized_size]); | 284 scoped_ptr<char[]> serialized_picture(new char[serialized_size]); |
260 stream.copyTo(serialized_picture.get()); | 285 stream.copyTo(serialized_picture.get()); |
261 base::Base64Encode(std::string(serialized_picture.get(), serialized_size), | 286 base::Base64Encode(std::string(serialized_picture.get(), serialized_size), |
262 output); | 287 output); |
263 } | 288 } |
264 | 289 |
290 void Picture::GatherAllPixelRefs() { | |
291 int min_x = std::numeric_limits<int>::max(); | |
292 int min_y = std::numeric_limits<int>::max(); | |
293 int max_x = 0; | |
294 int max_y = 0; | |
295 | |
296 // Capture pixel refs for this picture in a grid | |
297 // with cell_size_ sized cells. | |
298 for (int y = layer_rect_.y(); | |
299 y < layer_rect_.bottom(); | |
300 y += cell_size_.height()) { | |
301 for (int x = layer_rect_.x(); | |
302 x < layer_rect_.right(); | |
303 x += cell_size_.width()) { | |
304 gfx::Size extent(std::min(cell_size_.width(), layer_rect_.right() - x), | |
enne (OOO)
2013/04/23 01:59:39
I think these lines would be more clearly put as:
vmpstr
2013/04/23 20:02:23
Done.
| |
305 std::min(cell_size_.height(), layer_rect_.bottom() - y)); | |
306 gfx::Rect rect(x, y, extent.width(), extent.height()); | |
307 | |
308 std::list<skia::LazyPixelRef*> lazy_pixel_refs; | |
309 GatherPixelRefsFromSkia(rect, lazy_pixel_refs); | |
310 | |
311 // Only capture non-empty cells. | |
312 if (!lazy_pixel_refs.empty()) { | |
313 lazy_pixel_refs_[PixelRefMapKey(x, y)].swap(lazy_pixel_refs); | |
314 min_x = std::min(min_x, x); | |
315 min_y = std::min(min_y, y); | |
316 max_x = std::max(max_x, x); | |
317 max_y = std::max(max_y, y); | |
318 } | |
319 } | |
320 } | |
321 | |
322 min_lazy_pixel_cell_ = gfx::Point(min_x, min_y); | |
323 max_lazy_pixel_cell_ = gfx::Point(max_x, max_y); | |
324 } | |
325 | |
326 Picture::LazyPixelRefIterator::LazyPixelRefIterator() | |
327 : picture_(NULL), | |
328 current_list_(NULL), | |
329 current_pixel_ref_(NULL), | |
330 min_point_(-1, -1), | |
331 max_point_(-1, -1), | |
332 current_x_(0), | |
333 current_y_(0) { | |
334 } | |
335 | |
336 Picture::LazyPixelRefIterator::LazyPixelRefIterator( | |
337 gfx::Rect rect, | |
enne (OOO)
2013/04/23 01:59:39
rect => query_rect?
vmpstr
2013/04/23 20:02:23
Done.
| |
338 const Picture* picture) | |
339 : picture_(picture), | |
340 current_list_(NULL), | |
341 current_pixel_ref_(NULL) { | |
342 gfx::Rect layer_rect = picture->layer_rect_; | |
343 gfx::Size cell_size = picture->cell_size_; | |
344 | |
345 // We have to find a cell_size aligned point that | |
346 // corresponds to the given rect. First, subtract the layer origin, | |
347 // then ensure the point is a multiple of cell_size, | |
348 // and finally, add the layer origin back. | |
349 min_point_ = gfx::Point( | |
350 ToMultiple(rect.x() - layer_rect.x(), cell_size.width()) | |
351 + layer_rect.x(), | |
352 ToMultiple(rect.y() - layer_rect.y(), cell_size.height()) | |
353 + layer_rect.y()); | |
354 max_point_ = gfx::Point( | |
355 ToMultiple(rect.right() - layer_rect.x(), cell_size.width()) | |
356 + layer_rect.x(), | |
357 ToMultiple(rect.bottom() - layer_rect.y(), cell_size.height()) | |
358 + layer_rect.y()); | |
359 | |
360 // Limit the points to knows pixel ref boundaries. | |
enne (OOO)
2013/04/23 01:59:39
knows => known?
vmpstr
2013/04/23 20:02:23
Oops. Fixed.
| |
361 min_point_ = gfx::Point( | |
362 std::max(min_point_.x(), picture->min_lazy_pixel_cell_.x()), | |
363 std::max(min_point_.y(), picture->min_lazy_pixel_cell_.y())); | |
364 max_point_ = gfx::Point( | |
365 std::min(max_point_.x(), picture->max_lazy_pixel_cell_.x()), | |
366 std::min(max_point_.y(), picture->max_lazy_pixel_cell_.y())); | |
367 | |
368 // Make the current x be cell_size.width() less than min point, so that | |
369 // the first increment will point at min_point_. | |
370 current_x_ = min_point_.x() - cell_size.width(); | |
371 current_y_ = min_point_.y(); | |
372 ++(*this); | |
373 } | |
374 | |
375 Picture::LazyPixelRefIterator::~LazyPixelRefIterator() { | |
376 } | |
377 | |
378 Picture::LazyPixelRefIterator& Picture::LazyPixelRefIterator::operator++() { | |
379 // If we're not at the end of the list, then just get the next item. | |
380 if (current_list_ && | |
381 current_list_iterator_ != current_list_->end()) { | |
reveman
2013/04/23 14:33:24
I think this would be cleaner if you used a sentin
vmpstr
2013/04/23 20:02:23
Done.
| |
382 current_pixel_ref_ = *current_list_iterator_; | |
383 ++current_list_iterator_; | |
384 return *this; | |
385 } | |
386 | |
387 // If we already passed the max y, do nothing. | |
388 if (current_y_ > max_point_.y()) | |
389 return *this; | |
390 | |
391 while (true) { | |
392 gfx::Size cell_size = picture_->cell_size_; | |
393 | |
394 // Advance the current grid cell. | |
395 current_x_ += cell_size.width(); | |
396 if (current_x_ > max_point_.x()) { | |
397 current_y_ += cell_size.height(); | |
398 current_x_ = min_point_.x(); | |
399 // Min x can be greater than max x if the query rect | |
400 // does not intersect the layer rect. | |
401 if (current_y_ > max_point_.y() || | |
402 current_x_ > max_point_.x()) { | |
403 current_pixel_ref_ = NULL; | |
404 break; | |
405 } | |
406 } | |
407 | |
408 // If there are no pixel refs at this grid cell, keep incrementing. | |
409 PixelRefMap::const_iterator iter = | |
410 picture_->lazy_pixel_refs_.find(PixelRefMapKey(current_x_, current_y_)); | |
reveman
2013/04/23 14:33:24
nit: think it might be a bit cleaner to put "Pixel
vmpstr
2013/04/23 20:02:23
Done.
| |
411 if (iter == picture_->lazy_pixel_refs_.end()) | |
412 continue; | |
413 | |
414 // We found a non-empty list: store it and get the first pixel ref. | |
415 current_list_ = &iter->second; | |
416 current_list_iterator_ = current_list_->begin(); | |
417 current_pixel_ref_ = *current_list_iterator_; | |
418 ++current_list_iterator_; | |
419 break; | |
420 } | |
421 return *this; | |
422 } | |
423 | |
265 } // namespace cc | 424 } // namespace cc |
OLD | NEW |