Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / cc / resources / picture_pile_impl.cc
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 <algorithm>
6 #include <limits>
7
8 #include "base/debug/trace_event.h"
9 #include "cc/base/region.h"
10 #include "cc/debug/debug_colors.h"
11 #include "cc/resources/picture_pile_impl.h"
12 #include "skia/ext/analysis_canvas.h"
13 #include "third_party/skia/include/core/SkCanvas.h"
14 #include "third_party/skia/include/core/SkPictureRecorder.h"
15 #include "ui/gfx/geometry/rect_conversions.h"
16
17 namespace cc {
18
19 scoped_refptr<PicturePileImpl> PicturePileImpl::Create() {
20   return make_scoped_refptr(new PicturePileImpl);
21 }
22
23 scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther(
24     const PicturePileBase* other) {
25   return make_scoped_refptr(new PicturePileImpl(other));
26 }
27
28 PicturePileImpl::PicturePileImpl()
29     : background_color_(SK_ColorTRANSPARENT),
30       contents_opaque_(false),
31       contents_fill_bounds_completely_(false),
32       is_solid_color_(false),
33       solid_color_(SK_ColorTRANSPARENT),
34       has_any_recordings_(false),
35       is_mask_(false),
36       clear_canvas_with_debug_color_(false),
37       min_contents_scale_(0.f),
38       slow_down_raster_scale_factor_for_debug_(0),
39       likely_to_be_used_for_transform_animation_(false) {
40 }
41
42 PicturePileImpl::PicturePileImpl(const PicturePileBase* other)
43     : picture_map_(other->picture_map_),
44       tiling_(other->tiling_),
45       background_color_(other->background_color_),
46       contents_opaque_(other->contents_opaque_),
47       contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
48       is_solid_color_(other->is_solid_color_),
49       solid_color_(other->solid_color_),
50       recorded_viewport_(other->recorded_viewport_),
51       has_any_recordings_(other->has_any_recordings_),
52       is_mask_(other->is_mask_),
53       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
54       min_contents_scale_(other->min_contents_scale_),
55       slow_down_raster_scale_factor_for_debug_(
56           other->slow_down_raster_scale_factor_for_debug_),
57       likely_to_be_used_for_transform_animation_(false) {
58 }
59
60 PicturePileImpl::~PicturePileImpl() {
61 }
62
63 void PicturePileImpl::RasterDirect(SkCanvas* canvas,
64                                    const gfx::Rect& canvas_rect,
65                                    float contents_scale) const {
66   RasterCommon(canvas,
67                NULL,
68                canvas_rect,
69                contents_scale,
70                false);
71 }
72
73 void PicturePileImpl::RasterForAnalysis(skia::AnalysisCanvas* canvas,
74                                         const gfx::Rect& canvas_rect,
75                                         float contents_scale) const {
76   RasterCommon(canvas, canvas, canvas_rect, contents_scale, true);
77 }
78
79 void PicturePileImpl::PlaybackToCanvas(SkCanvas* canvas,
80                                        const gfx::Rect& canvas_rect,
81                                        float contents_scale) const {
82   canvas->discard();
83   if (clear_canvas_with_debug_color_) {
84     // Any non-painted areas in the content bounds will be left in this color.
85     canvas->clear(DebugColors::NonPaintedFillColor());
86   }
87
88   // If this picture has opaque contents, it is guaranteeing that it will
89   // draw an opaque rect the size of the layer.  If it is not, then we must
90   // clear this canvas ourselves.
91   if (contents_opaque_ || contents_fill_bounds_completely_) {
92     // Even if completely covered, for rasterizations that touch the edge of the
93     // layer, we also need to raster the background color underneath the last
94     // texel (since the recording won't cover it) and outside the last texel
95     // (due to linear filtering when using this texture).
96     gfx::Rect content_tiling_rect = gfx::ToEnclosingRect(
97         gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale));
98
99     // The final texel of content may only be partially covered by a
100     // rasterization; this rect represents the content rect that is fully
101     // covered by content.
102     gfx::Rect deflated_content_tiling_rect = content_tiling_rect;
103     deflated_content_tiling_rect.Inset(0, 0, 1, 1);
104     if (!deflated_content_tiling_rect.Contains(canvas_rect)) {
105       if (clear_canvas_with_debug_color_) {
106         // Any non-painted areas outside of the content bounds are left in
107         // this color.  If this is seen then it means that cc neglected to
108         // rerasterize a tile that used to intersect with the content rect
109         // after the content bounds grew.
110         canvas->save();
111         canvas->translate(-canvas_rect.x(), -canvas_rect.y());
112         canvas->clipRect(gfx::RectToSkRect(content_tiling_rect),
113                          SkRegion::kDifference_Op);
114         canvas->drawColor(DebugColors::MissingResizeInvalidations(),
115                           SkXfermode::kSrc_Mode);
116         canvas->restore();
117       }
118
119       // Drawing at most 2 x 2 x (canvas width + canvas height) texels is 2-3X
120       // faster than clearing, so special case this.
121       canvas->save();
122       canvas->translate(-canvas_rect.x(), -canvas_rect.y());
123       gfx::Rect inflated_content_tiling_rect = content_tiling_rect;
124       inflated_content_tiling_rect.Inset(0, 0, -1, -1);
125       canvas->clipRect(gfx::RectToSkRect(inflated_content_tiling_rect),
126                        SkRegion::kReplace_Op);
127       canvas->clipRect(gfx::RectToSkRect(deflated_content_tiling_rect),
128                        SkRegion::kDifference_Op);
129       canvas->drawColor(background_color_, SkXfermode::kSrc_Mode);
130       canvas->restore();
131     }
132   } else {
133     TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
134     // Clearing is about ~4x faster than drawing a rect even if the content
135     // isn't covering a majority of the canvas.
136     canvas->clear(SK_ColorTRANSPARENT);
137   }
138
139   RasterCommon(canvas,
140                NULL,
141                canvas_rect,
142                contents_scale,
143                false);
144 }
145
146 void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect,
147                                       const gfx::Rect& content_rect,
148                                       float contents_scale,
149                                       PictureRegionMap* results) const {
150   DCHECK(results);
151   // Rasterize the collection of relevant picture piles.
152   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
153       content_rect, 1.f / contents_scale);
154
155   // Make sure pictures don't overlap by keeping track of previous right/bottom.
156   int min_content_left = -1;
157   int min_content_top = -1;
158   int last_row_index = -1;
159   int last_col_index = -1;
160   gfx::Rect last_content_rect;
161
162   // Coalesce rasters of the same picture into different rects:
163   //  - Compute the clip of each of the pile chunks,
164   //  - Subtract it from the canvas rect to get difference region
165   //  - Later, use the difference region to subtract each of the comprising
166   //    rects from the canvas.
167   // Note that in essence, we're trying to mimic clipRegion with intersect op
168   // that also respects the current canvas transform and clip. In order to use
169   // the canvas transform, we must stick to clipRect operations (clipRegion
170   // ignores the transform). Intersect then can be written as subtracting the
171   // negation of the region we're trying to intersect. Luckily, we know that all
172   // of the rects will have to fit into |content_rect|, so we can start with
173   // that and subtract chunk rects to get the region that we need to subtract
174   // from the canvas. Then, we can use clipRect with difference op to subtract
175   // each rect in the region.
176   bool include_borders = true;
177   for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
178        tile_iter;
179        ++tile_iter) {
180     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
181     if (map_iter == picture_map_.end())
182       continue;
183     const PictureInfo& info = map_iter->second;
184     const Picture* picture = info.GetPicture();
185     if (!picture)
186       continue;
187
188     // This is intentionally *enclosed* rect, so that the clip is aligned on
189     // integral post-scale content pixels and does not extend past the edges
190     // of the picture chunk's layer rect.  The min_contents_scale enforces that
191     // enough buffer pixels have been added such that the enclosed rect
192     // encompasses all invalidated pixels at any larger scale level.
193     gfx::Rect chunk_rect = PaddedRect(tile_iter.index());
194     gfx::Rect content_clip =
195         gfx::ScaleToEnclosedRect(chunk_rect, contents_scale);
196     DCHECK(!content_clip.IsEmpty()) << "Layer rect: "
197                                     << picture->LayerRect().ToString()
198                                     << "Contents scale: " << contents_scale;
199     content_clip.Intersect(canvas_rect);
200
201     // Make sure iterator goes top->bottom.
202     DCHECK_GE(tile_iter.index_y(), last_row_index);
203     if (tile_iter.index_y() > last_row_index) {
204       // First tile in a new row.
205       min_content_left = content_clip.x();
206       min_content_top = last_content_rect.bottom();
207     } else {
208       // Make sure iterator goes left->right.
209       DCHECK_GT(tile_iter.index_x(), last_col_index);
210       min_content_left = last_content_rect.right();
211       min_content_top = last_content_rect.y();
212     }
213
214     last_col_index = tile_iter.index_x();
215     last_row_index = tile_iter.index_y();
216
217     // Only inset if the content_clip is less than then previous min.
218     int inset_left = std::max(0, min_content_left - content_clip.x());
219     int inset_top = std::max(0, min_content_top - content_clip.y());
220     content_clip.Inset(inset_left, inset_top, 0, 0);
221
222     PictureRegionMap::iterator it = results->find(picture);
223     Region* clip_region;
224     if (it == results->end()) {
225       // The clip for a set of coalesced pictures starts out clipping the entire
226       // canvas.  Each picture added to the set must subtract its own bounds
227       // from the clip region, poking a hole so that the picture is unclipped.
228       clip_region = &(*results)[picture];
229       *clip_region = canvas_rect;
230     } else {
231       clip_region = &it->second;
232     }
233
234     DCHECK(clip_region->Contains(content_clip))
235         << "Content clips should not overlap.";
236     clip_region->Subtract(content_clip);
237     last_content_rect = content_clip;
238   }
239 }
240
241 void PicturePileImpl::RasterCommon(
242     SkCanvas* canvas,
243     SkDrawPictureCallback* callback,
244     const gfx::Rect& canvas_rect,
245     float contents_scale,
246     bool is_analysis) const {
247   DCHECK(contents_scale >= min_contents_scale_);
248
249   canvas->translate(-canvas_rect.x(), -canvas_rect.y());
250   gfx::Rect content_tiling_rect = gfx::ToEnclosingRect(
251       gfx::ScaleRect(gfx::Rect(tiling_.tiling_size()), contents_scale));
252   content_tiling_rect.Intersect(canvas_rect);
253
254   canvas->clipRect(gfx::RectToSkRect(content_tiling_rect),
255                    SkRegion::kIntersect_Op);
256
257   PictureRegionMap picture_region_map;
258   CoalesceRasters(
259       canvas_rect, content_tiling_rect, contents_scale, &picture_region_map);
260
261 #ifndef NDEBUG
262   Region total_clip;
263 #endif  // NDEBUG
264
265   // Iterate the coalesced map and use each picture's region
266   // to clip the canvas.
267   for (PictureRegionMap::iterator it = picture_region_map.begin();
268        it != picture_region_map.end();
269        ++it) {
270     const Picture* picture = it->first;
271     Region negated_clip_region = it->second;
272
273 #ifndef NDEBUG
274     Region positive_clip = content_tiling_rect;
275     positive_clip.Subtract(negated_clip_region);
276     // Make sure we never rasterize the same region twice.
277     DCHECK(!total_clip.Intersects(positive_clip));
278     total_clip.Union(positive_clip);
279 #endif  // NDEBUG
280
281     int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
282
283     for (int j = 0; j < repeat_count; ++j)
284       picture->Raster(canvas, callback, negated_clip_region, contents_scale);
285   }
286
287 #ifndef NDEBUG
288   // Fill the clip with debug color. This allows us to
289   // distinguish between non painted areas and problems with missing
290   // pictures.
291   SkPaint paint;
292   for (Region::Iterator it(total_clip); it.has_rect(); it.next())
293     canvas->clipRect(gfx::RectToSkRect(it.rect()), SkRegion::kDifference_Op);
294   paint.setColor(DebugColors::MissingPictureFillColor());
295   paint.setXfermodeMode(SkXfermode::kSrc_Mode);
296   canvas->drawPaint(paint);
297 #endif  // NDEBUG
298 }
299
300 skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() {
301   TRACE_EVENT0("cc", "PicturePileImpl::GetFlattenedPicture");
302
303   gfx::Rect tiling_rect(tiling_.tiling_size());
304   SkPictureRecorder recorder;
305   SkCanvas* canvas =
306       recorder.beginRecording(tiling_rect.width(), tiling_rect.height());
307   if (!tiling_rect.IsEmpty())
308     PlaybackToCanvas(canvas, tiling_rect, 1.0);
309   skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
310
311   return picture;
312 }
313
314 void PicturePileImpl::PerformSolidColorAnalysis(
315     const gfx::Rect& content_rect,
316     float contents_scale,
317     RasterSource::SolidColorAnalysis* analysis) const {
318   DCHECK(analysis);
319   TRACE_EVENT0("cc", "PicturePileImpl::PerformSolidColorAnalysis");
320
321   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
322       content_rect, 1.0f / contents_scale);
323
324   layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
325
326   skia::AnalysisCanvas canvas(layer_rect.width(), layer_rect.height());
327
328   RasterForAnalysis(&canvas, layer_rect, 1.0f);
329
330   analysis->is_solid_color = canvas.GetColorIfSolid(&analysis->solid_color);
331 }
332
333 void PicturePileImpl::GatherPixelRefs(
334     const gfx::Rect& content_rect,
335     float contents_scale,
336     std::vector<SkPixelRef*>* pixel_refs) const {
337   DCHECK_EQ(0u, pixel_refs->size());
338   for (PixelRefIterator iter(content_rect, contents_scale, this); iter;
339        ++iter) {
340     pixel_refs->push_back(*iter);
341   }
342 }
343
344 bool PicturePileImpl::CoversRect(const gfx::Rect& content_rect,
345                                  float contents_scale) const {
346   if (tiling_.tiling_size().IsEmpty())
347     return false;
348   gfx::Rect layer_rect =
349       gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale);
350   layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
351
352   // Common case inside of viewport to avoid the slower map lookups.
353   if (recorded_viewport_.Contains(layer_rect)) {
354     // Sanity check that there are no false positives in recorded_viewport_.
355     DCHECK(CanRasterSlowTileCheck(layer_rect));
356     return true;
357   }
358
359   return CanRasterSlowTileCheck(layer_rect);
360 }
361
362 gfx::Rect PicturePileImpl::PaddedRect(const PictureMapKey& key) const {
363   gfx::Rect padded_rect = tiling_.TileBounds(key.first, key.second);
364   padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(),
365                     -buffer_pixels());
366   return padded_rect;
367 }
368
369 bool PicturePileImpl::CanRasterSlowTileCheck(
370     const gfx::Rect& layer_rect) const {
371   bool include_borders = false;
372   for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
373        tile_iter; ++tile_iter) {
374     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
375     if (map_iter == picture_map_.end())
376       return false;
377     if (!map_iter->second.GetPicture())
378       return false;
379   }
380   return true;
381 }
382
383 bool PicturePileImpl::SuitableForDistanceFieldText() const {
384   return likely_to_be_used_for_transform_animation_;
385 }
386
387 void PicturePileImpl::AsValueInto(base::debug::TracedValue* pictures) const {
388   gfx::Rect tiling_rect(tiling_.tiling_size());
389   std::set<const void*> appended_pictures;
390   bool include_borders = true;
391   for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
392        tile_iter; ++tile_iter) {
393     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
394     if (map_iter == picture_map_.end())
395       continue;
396
397     const Picture* picture = map_iter->second.GetPicture();
398     if (picture && (appended_pictures.count(picture) == 0)) {
399       appended_pictures.insert(picture);
400       TracedValue::AppendIDRef(picture, pictures);
401     }
402   }
403 }
404
405 PicturePileImpl::PixelRefIterator::PixelRefIterator(
406     const gfx::Rect& content_rect,
407     float contents_scale,
408     const PicturePileImpl* picture_pile)
409     : picture_pile_(picture_pile),
410       layer_rect_(
411           gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale)),
412       tile_iterator_(&picture_pile_->tiling_,
413                      layer_rect_,
414                      false /* include_borders */) {
415   // Early out if there isn't a single tile.
416   if (!tile_iterator_)
417     return;
418
419   AdvanceToTilePictureWithPixelRefs();
420 }
421
422 PicturePileImpl::PixelRefIterator::~PixelRefIterator() {
423 }
424
425 PicturePileImpl::PixelRefIterator&
426     PicturePileImpl::PixelRefIterator::operator++() {
427   ++pixel_ref_iterator_;
428   if (pixel_ref_iterator_)
429     return *this;
430
431   ++tile_iterator_;
432   AdvanceToTilePictureWithPixelRefs();
433   return *this;
434 }
435
436 void PicturePileImpl::PixelRefIterator::AdvanceToTilePictureWithPixelRefs() {
437   for (; tile_iterator_; ++tile_iterator_) {
438     PictureMap::const_iterator it =
439         picture_pile_->picture_map_.find(tile_iterator_.index());
440     if (it == picture_pile_->picture_map_.end())
441       continue;
442
443     const Picture* picture = it->second.GetPicture();
444     if (!picture || (processed_pictures_.count(picture) != 0) ||
445         !picture->WillPlayBackBitmaps())
446       continue;
447
448     processed_pictures_.insert(picture);
449     pixel_ref_iterator_ = Picture::PixelRefIterator(layer_rect_, picture);
450     if (pixel_ref_iterator_)
451       break;
452   }
453 }
454
455 void PicturePileImpl::DidBeginTracing() {
456   std::set<const void*> processed_pictures;
457   for (PictureMap::iterator it = picture_map_.begin();
458        it != picture_map_.end();
459        ++it) {
460     const Picture* picture = it->second.GetPicture();
461     if (picture && (processed_pictures.count(picture) == 0)) {
462       picture->EmitTraceSnapshot();
463       processed_pictures.insert(picture);
464     }
465   }
466 }
467
468 }  // namespace cc