OLD | NEW |
| (Empty) |
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 "base/debug/trace_event.h" | |
6 #include "cc/base/region.h" | |
7 #include "cc/debug/debug_colors.h" | |
8 #include "cc/debug/rendering_stats.h" | |
9 #include "cc/picture_pile_impl.h" | |
10 #include "skia/ext/analysis_canvas.h" | |
11 #include "third_party/skia/include/core/SkCanvas.h" | |
12 #include "third_party/skia/include/core/SkSize.h" | |
13 #include "ui/gfx/rect_conversions.h" | |
14 #include "ui/gfx/size_conversions.h" | |
15 #include "ui/gfx/skia_util.h" | |
16 | |
17 namespace cc { | |
18 | |
19 PicturePileImpl::ClonesForDrawing::ClonesForDrawing( | |
20 const PicturePileImpl* pile, int num_threads) { | |
21 for (int i = 0; i < num_threads; i++) { | |
22 scoped_refptr<PicturePileImpl> clone = | |
23 PicturePileImpl::CreateCloneForDrawing(pile, i); | |
24 clones_.push_back(clone); | |
25 } | |
26 } | |
27 | |
28 PicturePileImpl::ClonesForDrawing::~ClonesForDrawing() { | |
29 } | |
30 | |
31 scoped_refptr<PicturePileImpl> PicturePileImpl::Create() { | |
32 return make_scoped_refptr(new PicturePileImpl()); | |
33 } | |
34 | |
35 scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther( | |
36 const PicturePileBase* other) { | |
37 return make_scoped_refptr(new PicturePileImpl(other)); | |
38 } | |
39 | |
40 scoped_refptr<PicturePileImpl> PicturePileImpl::CreateCloneForDrawing( | |
41 const PicturePileImpl* other, unsigned thread_index) { | |
42 return make_scoped_refptr(new PicturePileImpl(other, thread_index)); | |
43 } | |
44 | |
45 PicturePileImpl::PicturePileImpl() | |
46 : clones_for_drawing_(ClonesForDrawing(this, 0)) { | |
47 } | |
48 | |
49 PicturePileImpl::PicturePileImpl(const PicturePileBase* other) | |
50 : PicturePileBase(other), | |
51 clones_for_drawing_(ClonesForDrawing(this, num_raster_threads())) { | |
52 } | |
53 | |
54 PicturePileImpl::PicturePileImpl( | |
55 const PicturePileImpl* other, unsigned thread_index) | |
56 : PicturePileBase(other, thread_index), | |
57 clones_for_drawing_(ClonesForDrawing(this, 0)) { | |
58 } | |
59 | |
60 PicturePileImpl::~PicturePileImpl() { | |
61 } | |
62 | |
63 PicturePileImpl* PicturePileImpl::GetCloneForDrawingOnThread( | |
64 unsigned thread_index) const { | |
65 CHECK_GT(clones_for_drawing_.clones_.size(), thread_index); | |
66 return clones_for_drawing_.clones_[thread_index]; | |
67 } | |
68 | |
69 void PicturePileImpl::Raster( | |
70 SkCanvas* canvas, | |
71 gfx::Rect canvas_rect, | |
72 float contents_scale, | |
73 int64* total_pixels_rasterized) { | |
74 | |
75 DCHECK(contents_scale >= min_contents_scale_); | |
76 | |
77 #ifndef NDEBUG | |
78 // Any non-painted areas will be left in this color. | |
79 canvas->clear(DebugColors::NonPaintedFillColor()); | |
80 #endif // NDEBUG | |
81 | |
82 canvas->save(); | |
83 canvas->translate(-canvas_rect.x(), -canvas_rect.y()); | |
84 | |
85 gfx::SizeF total_content_size = gfx::ScaleSize(tiling_.total_size(), | |
86 contents_scale); | |
87 gfx::Rect total_content_rect(gfx::ToCeiledSize(total_content_size)); | |
88 gfx::Rect content_rect = total_content_rect; | |
89 content_rect.Intersect(canvas_rect); | |
90 | |
91 // Clear one texel inside the right/bottom edge of the content rect, | |
92 // as it may only be partially covered by the picture playback. | |
93 // Also clear one texel outside the right/bottom edge of the content rect, | |
94 // as it may get blended in by linear filtering when zoomed in. | |
95 gfx::Rect deflated_content_rect = total_content_rect; | |
96 deflated_content_rect.Inset(0, 0, 1, 1); | |
97 | |
98 gfx::Rect canvas_outside_content_rect = canvas_rect; | |
99 canvas_outside_content_rect.Subtract(deflated_content_rect); | |
100 | |
101 if (!canvas_outside_content_rect.IsEmpty()) { | |
102 gfx::Rect inflated_content_rect = total_content_rect; | |
103 inflated_content_rect.Inset(0, 0, -1, -1); | |
104 canvas->clipRect(gfx::RectToSkRect(inflated_content_rect), | |
105 SkRegion::kReplace_Op); | |
106 canvas->clipRect(gfx::RectToSkRect(deflated_content_rect), | |
107 SkRegion::kDifference_Op); | |
108 canvas->drawColor(background_color_, SkXfermode::kSrc_Mode); | |
109 } | |
110 | |
111 // Rasterize the collection of relevant picture piles. | |
112 gfx::Rect layer_rect = gfx::ToEnclosingRect( | |
113 gfx::ScaleRect(content_rect, 1.f / contents_scale)); | |
114 | |
115 canvas->clipRect(gfx::RectToSkRect(content_rect), | |
116 SkRegion::kReplace_Op); | |
117 Region unclipped(content_rect); | |
118 for (TilingData::Iterator tile_iter(&tiling_, layer_rect); | |
119 tile_iter; ++tile_iter) { | |
120 PictureListMap::iterator map_iter = | |
121 picture_list_map_.find(tile_iter.index()); | |
122 if (map_iter == picture_list_map_.end()) | |
123 continue; | |
124 PictureList& pic_list= map_iter->second; | |
125 if (pic_list.empty()) | |
126 continue; | |
127 | |
128 // Raster through the picture list top down, using clips to make sure that | |
129 // pictures on top are not overdrawn by pictures on the bottom. | |
130 for (PictureList::reverse_iterator i = pic_list.rbegin(); | |
131 i != pic_list.rend(); ++i) { | |
132 // This is intentionally *enclosed* rect, so that the clip is aligned on | |
133 // integral post-scale content pixels and does not extend past the edges | |
134 // of the picture's layer rect. The min_contents_scale enforces that | |
135 // enough buffer pixels have been added such that the enclosed rect | |
136 // encompasses all invalidated pixels at any larger scale level. | |
137 gfx::Rect content_clip = gfx::ToEnclosedRect( | |
138 gfx::ScaleRect((*i)->LayerRect(), contents_scale)); | |
139 DCHECK(!content_clip.IsEmpty()); | |
140 if (!unclipped.Intersects(content_clip)) | |
141 continue; | |
142 | |
143 if (slow_down_raster_scale_factor_for_debug_) { | |
144 for (int j = 0; j < slow_down_raster_scale_factor_for_debug_; ++j) | |
145 (*i)->Raster(canvas, content_clip, contents_scale); | |
146 } else { | |
147 (*i)->Raster(canvas, content_clip, contents_scale); | |
148 } | |
149 | |
150 // Don't allow pictures underneath to draw where this picture did. | |
151 canvas->clipRect( | |
152 gfx::RectToSkRect(content_clip), | |
153 SkRegion::kDifference_Op); | |
154 unclipped.Subtract(content_clip); | |
155 | |
156 *total_pixels_rasterized += | |
157 content_clip.width() * content_clip.height(); | |
158 } | |
159 } | |
160 | |
161 #ifndef NDEBUG | |
162 // Fill the remaining clip with debug color. This allows us to | |
163 // distinguish between non painted areas and problems with missing | |
164 // pictures. | |
165 SkPaint paint; | |
166 paint.setColor(DebugColors::MissingPictureFillColor()); | |
167 paint.setXfermodeMode(SkXfermode::kSrc_Mode); | |
168 canvas->drawPaint(paint); | |
169 #endif // NDEBUG | |
170 | |
171 // We should always paint some part of |content_rect|. | |
172 DCHECK(!unclipped.Contains(content_rect)); | |
173 | |
174 canvas->restore(); | |
175 } | |
176 | |
177 void PicturePileImpl::GatherPixelRefs( | |
178 gfx::Rect content_rect, | |
179 float contents_scale, | |
180 std::list<skia::LazyPixelRef*>& pixel_refs) { | |
181 std::list<skia::LazyPixelRef*> result; | |
182 | |
183 gfx::Rect layer_rect = gfx::ToEnclosingRect( | |
184 gfx::ScaleRect(content_rect, 1.f / contents_scale)); | |
185 | |
186 for (TilingData::Iterator tile_iter(&tiling_, layer_rect); | |
187 tile_iter; ++tile_iter) { | |
188 PictureListMap::iterator map_iter = | |
189 picture_list_map_.find(tile_iter.index()); | |
190 if (map_iter == picture_list_map_.end()) | |
191 continue; | |
192 | |
193 PictureList& pic_list = map_iter->second; | |
194 for (PictureList::const_iterator i = pic_list.begin(); | |
195 i != pic_list.end(); ++i) { | |
196 (*i)->GatherPixelRefs(layer_rect, result); | |
197 pixel_refs.splice(pixel_refs.end(), result); | |
198 } | |
199 } | |
200 } | |
201 | |
202 skia::RefPtr<SkPicture> PicturePileImpl::GetFlattenedPicture() { | |
203 TRACE_EVENT0("cc", "PicturePileImpl::GetFlattenedPicture"); | |
204 | |
205 gfx::Rect layer_rect(tiling_.total_size()); | |
206 skia::RefPtr<SkPicture> picture = skia::AdoptRef(new SkPicture); | |
207 if (layer_rect.IsEmpty()) | |
208 return picture; | |
209 | |
210 SkCanvas* canvas = picture->beginRecording( | |
211 layer_rect.width(), | |
212 layer_rect.height(), | |
213 SkPicture::kUsePathBoundsForClip_RecordingFlag); | |
214 | |
215 int64 total_pixels_rasterized = 0; | |
216 Raster(canvas, layer_rect, 1.0, &total_pixels_rasterized); | |
217 picture->endRecording(); | |
218 | |
219 return picture; | |
220 } | |
221 | |
222 void PicturePileImpl::AnalyzeInRect(const gfx::Rect& content_rect, | |
223 float contents_scale, | |
224 PicturePileImpl::Analysis* analysis) { | |
225 DCHECK(analysis); | |
226 TRACE_EVENT0("cc", "PicturePileImpl::AnalyzeInRect"); | |
227 | |
228 gfx::Rect layer_rect = gfx::ToEnclosingRect( | |
229 gfx::ScaleRect(content_rect, 1.f / contents_scale)); | |
230 | |
231 SkBitmap emptyBitmap; | |
232 emptyBitmap.setConfig(SkBitmap::kNo_Config, content_rect.width(), | |
233 content_rect.height()); | |
234 skia::AnalysisDevice device(emptyBitmap); | |
235 skia::AnalysisCanvas canvas(&device); | |
236 | |
237 int64 total_pixels_rasterized = 0; | |
238 Raster(&canvas, content_rect, contents_scale, &total_pixels_rasterized); | |
239 | |
240 analysis->is_transparent = canvas.isTransparent(); | |
241 analysis->is_solid_color = canvas.getColorIfSolid(&analysis->solid_color); | |
242 analysis->is_cheap_to_raster = canvas.isCheap(); | |
243 } | |
244 | |
245 PicturePileImpl::Analysis::Analysis() : | |
246 is_solid_color(false), | |
247 is_transparent(false), | |
248 is_cheap_to_raster(false) { | |
249 } | |
250 | |
251 } // namespace cc | |
OLD | NEW |