OLD | NEW |
1 | |
2 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
3 // 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 |
4 // found in the LICENSE file. | 3 // found in the LICENSE file. |
5 | 4 |
6 #include "cc/layers/scrollbar_layer.h" | 5 #include "cc/layers/scrollbar_layer.h" |
7 | 6 |
8 #include "base/auto_reset.h" | 7 #include "base/auto_reset.h" |
9 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
10 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 10 #include "base/memory/weak_ptr.h" |
11 #include "cc/layers/scrollbar_layer_impl.h" | 11 #include "cc/layers/scrollbar_layer_impl.h" |
12 #include "cc/resources/caching_bitmap_content_layer_updater.h" | 12 #include "cc/resources/ui_resource_bitmap.h" |
13 #include "cc/resources/layer_painter.h" | |
14 #include "cc/resources/prioritized_resource.h" | |
15 #include "cc/resources/resource_update_queue.h" | |
16 #include "cc/trees/layer_tree_host.h" | 13 #include "cc/trees/layer_tree_host.h" |
| 14 #include "cc/trees/layer_tree_impl.h" |
| 15 #include "skia/ext/platform_canvas.h" |
| 16 #include "skia/ext/refptr.h" |
| 17 #include "third_party/skia/include/core/SkSize.h" |
17 #include "ui/gfx/rect_conversions.h" | 18 #include "ui/gfx/rect_conversions.h" |
18 | 19 |
19 namespace cc { | 20 namespace cc { |
20 | 21 |
21 scoped_ptr<LayerImpl> ScrollbarLayer::CreateLayerImpl( | 22 scoped_ptr<LayerImpl> ScrollbarLayer::CreateLayerImpl( |
22 LayerTreeImpl* tree_impl) { | 23 LayerTreeImpl* tree_impl) { |
23 return ScrollbarLayerImpl::Create( | 24 return ScrollbarLayerImpl::Create( |
24 tree_impl, id(), scrollbar_->Orientation()).PassAs<LayerImpl>(); | 25 tree_impl, id(), scrollbar_->Orientation()).PassAs<LayerImpl>(); |
25 } | 26 } |
26 | 27 |
27 scoped_refptr<ScrollbarLayer> ScrollbarLayer::Create( | 28 scoped_refptr<ScrollbarLayer> ScrollbarLayer::Create( |
28 scoped_ptr<Scrollbar> scrollbar, | 29 scoped_ptr<Scrollbar> scrollbar, |
29 int scroll_layer_id) { | 30 int scroll_layer_id) { |
30 return make_scoped_refptr(new ScrollbarLayer(scrollbar.Pass(), | 31 return make_scoped_refptr( |
31 scroll_layer_id)); | 32 new ScrollbarLayer(scrollbar.Pass(), scroll_layer_id)); |
32 } | 33 } |
33 | 34 |
34 ScrollbarLayer::ScrollbarLayer( | 35 ScrollbarLayer::ScrollbarLayer( |
35 scoped_ptr<Scrollbar> scrollbar, | 36 scoped_ptr<Scrollbar> scrollbar, |
36 int scroll_layer_id) | 37 int scroll_layer_id) |
37 : scrollbar_(scrollbar.Pass()), | 38 : scrollbar_(scrollbar.Pass()), |
38 scroll_layer_id_(scroll_layer_id), | 39 scroll_layer_id_(scroll_layer_id), |
39 texture_format_(GL_INVALID_ENUM) { | 40 track_ui_resource_id_(0), |
| 41 thumb_ui_resource_id_(0) { |
40 if (!scrollbar_->IsOverlay()) | 42 if (!scrollbar_->IsOverlay()) |
41 SetShouldScrollOnMainThread(true); | 43 SetShouldScrollOnMainThread(true); |
42 } | 44 } |
43 | 45 |
44 ScrollbarLayer::~ScrollbarLayer() {} | 46 ScrollbarLayer::~ScrollbarLayer() {} |
45 | 47 |
46 void ScrollbarLayer::SetScrollLayerId(int id) { | 48 void ScrollbarLayer::SetScrollLayerId(int id) { |
47 if (id == scroll_layer_id_) | 49 if (id == scroll_layer_id_) |
48 return; | 50 return; |
49 | 51 |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
121 } | 123 } |
122 scrollbar_layer->set_thumb_length(thumb_length_); | 124 scrollbar_layer->set_thumb_length(thumb_length_); |
123 if (Orientation() == HORIZONTAL) { | 125 if (Orientation() == HORIZONTAL) { |
124 scrollbar_layer->set_track_start(track_rect_.x()); | 126 scrollbar_layer->set_track_start(track_rect_.x()); |
125 scrollbar_layer->set_track_length(track_rect_.width()); | 127 scrollbar_layer->set_track_length(track_rect_.width()); |
126 } else { | 128 } else { |
127 scrollbar_layer->set_track_start(track_rect_.y()); | 129 scrollbar_layer->set_track_start(track_rect_.y()); |
128 scrollbar_layer->set_track_length(track_rect_.height()); | 130 scrollbar_layer->set_track_length(track_rect_.height()); |
129 } | 131 } |
130 | 132 |
131 if (track_ && track_->texture()->have_backing_texture()) | 133 scrollbar_layer->set_track_ui_resource_id(track_ui_resource_id_); |
132 scrollbar_layer->set_track_resource_id(track_->texture()->resource_id()); | 134 scrollbar_layer->set_thumb_ui_resource_id(thumb_ui_resource_id_); |
133 else | |
134 scrollbar_layer->set_track_resource_id(0); | |
135 | |
136 if (thumb_ && thumb_->texture()->have_backing_texture()) | |
137 scrollbar_layer->set_thumb_resource_id(thumb_->texture()->resource_id()); | |
138 else | |
139 scrollbar_layer->set_thumb_resource_id(0); | |
140 | 135 |
141 scrollbar_layer->set_is_overlay_scrollbar(scrollbar_->IsOverlay()); | 136 scrollbar_layer->set_is_overlay_scrollbar(scrollbar_->IsOverlay()); |
142 | 137 |
143 // ScrollbarLayer must push properties every frame. crbug.com/259095 | 138 // ScrollbarLayer must push properties every frame. crbug.com/259095 |
144 needs_push_properties_ = true; | 139 needs_push_properties_ = true; |
145 } | 140 } |
146 | 141 |
147 ScrollbarLayer* ScrollbarLayer::ToScrollbarLayer() { | 142 ScrollbarLayer* ScrollbarLayer::ToScrollbarLayer() { |
148 return this; | 143 return this; |
149 } | 144 } |
150 | 145 |
151 void ScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) { | 146 void ScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) { |
| 147 // When the LTH is set to null, then this layer should remove all of |
| 148 // its associated textures. |
152 if (!host || host != layer_tree_host()) { | 149 if (!host || host != layer_tree_host()) { |
153 track_updater_ = NULL; | 150 if (track_ui_resource_id_) { |
154 track_.reset(); | 151 if (layer_tree_host()) |
155 thumb_updater_ = NULL; | 152 layer_tree_host()->DeleteUIResource(track_ui_resource_id_); |
156 thumb_.reset(); | 153 track_ui_resource_id_ = 0; |
| 154 track_bitmap_ = NULL; |
| 155 } |
| 156 |
| 157 if (thumb_ui_resource_id_) { |
| 158 if (layer_tree_host()) |
| 159 layer_tree_host()->DeleteUIResource(thumb_ui_resource_id_); |
| 160 thumb_ui_resource_id_ = 0; |
| 161 thumb_bitmap_ = NULL; |
| 162 } |
157 } | 163 } |
158 | 164 |
159 ContentsScalingLayer::SetLayerTreeHost(host); | 165 ContentsScalingLayer::SetLayerTreeHost(host); |
160 } | 166 } |
161 | 167 |
162 class ScrollbarPartPainter : public LayerPainter { | |
163 public: | |
164 ScrollbarPartPainter(Scrollbar* scrollbar, ScrollbarPart part) | |
165 : scrollbar_(scrollbar), | |
166 part_(part) {} | |
167 virtual ~ScrollbarPartPainter() {} | |
168 | |
169 // LayerPainter implementation | |
170 virtual void Paint(SkCanvas* canvas, | |
171 gfx::Rect content_rect, | |
172 gfx::RectF* opaque) OVERRIDE { | |
173 scrollbar_->PaintPart(canvas, part_, content_rect); | |
174 } | |
175 | |
176 private: | |
177 Scrollbar* scrollbar_; | |
178 ScrollbarPart part_; | |
179 }; | |
180 | |
181 void ScrollbarLayer::CreateUpdaterIfNeeded() { | |
182 if (layer_tree_host()->settings().solid_color_scrollbars) | |
183 return; | |
184 | |
185 texture_format_ = | |
186 layer_tree_host()->GetRendererCapabilities().best_texture_format; | |
187 | |
188 if (!track_updater_.get()) { | |
189 track_updater_ = CachingBitmapContentLayerUpdater::Create( | |
190 scoped_ptr<LayerPainter>( | |
191 new ScrollbarPartPainter(scrollbar_.get(), TRACK)) | |
192 .Pass(), | |
193 rendering_stats_instrumentation(), | |
194 id()); | |
195 } | |
196 if (!track_) { | |
197 track_ = track_updater_->CreateResource( | |
198 layer_tree_host()->contents_texture_manager()); | |
199 } | |
200 | |
201 if (!thumb_updater_.get()) { | |
202 thumb_updater_ = CachingBitmapContentLayerUpdater::Create( | |
203 scoped_ptr<LayerPainter>( | |
204 new ScrollbarPartPainter(scrollbar_.get(), THUMB)) | |
205 .Pass(), | |
206 rendering_stats_instrumentation(), | |
207 id()); | |
208 } | |
209 if (!thumb_ && scrollbar_->HasThumb()) { | |
210 thumb_ = thumb_updater_->CreateResource( | |
211 layer_tree_host()->contents_texture_manager()); | |
212 } | |
213 } | |
214 | |
215 bool ScrollbarLayer::UpdatePart(CachingBitmapContentLayerUpdater* painter, | |
216 LayerUpdater::Resource* resource, | |
217 gfx::Rect rect, | |
218 ResourceUpdateQueue* queue) { | |
219 if (layer_tree_host()->settings().solid_color_scrollbars) | |
220 return false; | |
221 | |
222 // Skip painting and uploading if there are no invalidations and | |
223 // we already have valid texture data. | |
224 if (resource->texture()->have_backing_texture() && | |
225 resource->texture()->size() == rect.size() && | |
226 !is_dirty()) | |
227 return false; | |
228 | |
229 // We should always have enough memory for UI. | |
230 DCHECK(resource->texture()->can_acquire_backing_texture()); | |
231 if (!resource->texture()->can_acquire_backing_texture()) | |
232 return false; | |
233 | |
234 // Paint and upload the entire part. | |
235 gfx::Rect painted_opaque_rect; | |
236 painter->PrepareToUpdate(rect, | |
237 rect.size(), | |
238 contents_scale_x(), | |
239 contents_scale_y(), | |
240 &painted_opaque_rect); | |
241 if (!painter->pixels_did_change() && | |
242 resource->texture()->have_backing_texture()) { | |
243 TRACE_EVENT_INSTANT0("cc", | |
244 "ScrollbarLayer::UpdatePart no texture upload needed", | |
245 TRACE_EVENT_SCOPE_THREAD); | |
246 return false; | |
247 } | |
248 | |
249 bool partial_updates_allowed = | |
250 layer_tree_host()->settings().max_partial_texture_updates > 0; | |
251 if (!partial_updates_allowed) | |
252 resource->texture()->ReturnBackingTexture(); | |
253 | |
254 gfx::Vector2d dest_offset(0, 0); | |
255 resource->Update(queue, rect, dest_offset, partial_updates_allowed); | |
256 return true; | |
257 } | |
258 | |
259 gfx::Rect ScrollbarLayer::ScrollbarLayerRectToContentRect( | 168 gfx::Rect ScrollbarLayer::ScrollbarLayerRectToContentRect( |
260 gfx::Rect layer_rect) const { | 169 gfx::Rect layer_rect) const { |
261 // Don't intersect with the bounds as in LayerRectToContentRect() because | 170 // Don't intersect with the bounds as in LayerRectToContentRect() because |
262 // layer_rect here might be in coordinates of the containing layer. | 171 // layer_rect here might be in coordinates of the containing layer. |
263 gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect( | 172 gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect( |
264 layer_rect, contents_scale_y(), contents_scale_y()); | 173 layer_rect, contents_scale_y(), contents_scale_y()); |
265 // We should never return a rect bigger than the content_bounds(). | 174 // We should never return a rect bigger than the content_bounds(). |
266 gfx::Size clamped_size = expanded_rect.size(); | 175 gfx::Size clamped_size = expanded_rect.size(); |
267 clamped_size.SetToMin(content_bounds()); | 176 clamped_size.SetToMin(content_bounds()); |
268 expanded_rect.set_size(clamped_size); | 177 expanded_rect.set_size(clamped_size); |
269 return expanded_rect; | 178 return expanded_rect; |
270 } | 179 } |
271 | 180 |
272 void ScrollbarLayer::SetTexturePriorities( | 181 gfx::Rect ScrollbarLayer::OriginThumbRect() const { |
273 const PriorityCalculator& priority_calc) { | 182 gfx::Size thumb_size; |
274 if (layer_tree_host()->settings().solid_color_scrollbars) | 183 if (Orientation() == HORIZONTAL) { |
275 return; | 184 thumb_size = |
276 | 185 gfx::Size(scrollbar_->ThumbLength(), scrollbar_->ThumbThickness()); |
277 if (content_bounds().IsEmpty()) | 186 } else { |
278 return; | 187 thumb_size = |
279 DCHECK_LE(content_bounds().width(), MaxTextureSize()); | 188 gfx::Size(scrollbar_->ThumbThickness(), scrollbar_->ThumbLength()); |
280 DCHECK_LE(content_bounds().height(), MaxTextureSize()); | |
281 | |
282 CreateUpdaterIfNeeded(); | |
283 | |
284 bool draws_to_root = !render_target()->parent(); | |
285 if (track_) { | |
286 track_->texture()->SetDimensions(content_bounds(), texture_format_); | |
287 track_->texture()->set_request_priority( | |
288 PriorityCalculator::UIPriority(draws_to_root)); | |
289 } | 189 } |
290 if (thumb_) { | 190 return ScrollbarLayerRectToContentRect(gfx::Rect(thumb_size)); |
291 gfx::Size thumb_size = OriginThumbRect().size(); | |
292 thumb_->texture()->SetDimensions(thumb_size, texture_format_); | |
293 thumb_->texture()->set_request_priority( | |
294 PriorityCalculator::UIPriority(draws_to_root)); | |
295 } | |
296 } | 191 } |
297 | 192 |
298 bool ScrollbarLayer::Update(ResourceUpdateQueue* queue, | 193 bool ScrollbarLayer::Update(ResourceUpdateQueue* queue, |
299 const OcclusionTracker* occlusion) { | 194 const OcclusionTracker* occlusion) { |
300 track_rect_ = scrollbar_->TrackRect(); | 195 track_rect_ = scrollbar_->TrackRect(); |
301 | 196 |
302 if (layer_tree_host()->settings().solid_color_scrollbars) | 197 if (layer_tree_host()->settings().solid_color_scrollbars) |
303 return false; | 198 return false; |
304 | 199 |
| 200 // Setting this boolean is still necessary to ensure no extra commits. |
305 { | 201 { |
306 base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_, | 202 base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_, |
307 true); | 203 true); |
308 ContentsScalingLayer::Update(queue, occlusion); | 204 ContentsScalingLayer::Update(queue, occlusion); |
309 } | 205 } |
310 | 206 |
311 dirty_rect_.Union(update_rect_); | |
312 if (content_bounds().IsEmpty()) | |
313 return false; | |
314 if (visible_content_rect().IsEmpty()) | |
315 return false; | |
316 | |
317 CreateUpdaterIfNeeded(); | |
318 | |
319 gfx::Rect content_rect = ScrollbarLayerRectToContentRect( | |
320 gfx::Rect(scrollbar_->Location(), bounds())); | |
321 bool updated = UpdatePart(track_updater_.get(), track_.get(), content_rect, | |
322 queue); | |
323 | |
324 if (scrollbar_->HasThumb()) { | 207 if (scrollbar_->HasThumb()) { |
325 thumb_thickness_ = scrollbar_->ThumbThickness(); | 208 thumb_thickness_ = scrollbar_->ThumbThickness(); |
326 thumb_length_ = scrollbar_->ThumbLength(); | 209 thumb_length_ = scrollbar_->ThumbLength(); |
327 gfx::Rect origin_thumb_rect = OriginThumbRect(); | |
328 if (!origin_thumb_rect.IsEmpty()) { | |
329 updated |= UpdatePart(thumb_updater_.get(), thumb_.get(), | |
330 origin_thumb_rect, queue); | |
331 } | |
332 } | 210 } |
333 | 211 |
334 dirty_rect_ = gfx::RectF(); | 212 RasterizeTrackAndThumb(); |
335 return updated; | 213 |
| 214 if (track_ui_resource_id_) |
| 215 layer_tree_host()->DeleteUIResource(track_ui_resource_id_); |
| 216 track_ui_resource_id_ = layer_tree_host()->CreateUIResource( |
| 217 base::Bind(&ScrollbarLayer::GetTrackBitmap, this)); |
| 218 |
| 219 if (scrollbar_->HasThumb()) { |
| 220 if (thumb_ui_resource_id_) |
| 221 layer_tree_host()->DeleteUIResource(thumb_ui_resource_id_); |
| 222 thumb_ui_resource_id_ = layer_tree_host()->CreateUIResource( |
| 223 base::Bind(&ScrollbarLayer::GetThumbBitmap, this)); |
| 224 } |
| 225 |
| 226 return true; |
336 } | 227 } |
337 | 228 |
338 gfx::Rect ScrollbarLayer::OriginThumbRect() const { | 229 void ScrollbarLayer::RasterizeTrackAndThumb() { |
339 gfx::Size thumb_size; | 230 DCHECK(!layer_tree_host()->settings().solid_color_scrollbars); |
340 if (Orientation() == HORIZONTAL) { | 231 |
341 thumb_size = gfx::Size(scrollbar_->ThumbLength(), | 232 gfx::Rect track_rect = ScrollbarLayerRectToContentRect( |
342 scrollbar_->ThumbThickness()); | 233 gfx::Rect(scrollbar_->Location(), bounds())); |
343 } else { | 234 track_bitmap_ = UIResourceBitmap::Create( |
344 thumb_size = gfx::Size(scrollbar_->ThumbThickness(), | 235 new uint8_t[track_rect.width() * track_rect.height() * 4], |
345 scrollbar_->ThumbLength()); | 236 UIResourceBitmap::RGBA8, |
| 237 track_rect.size()); |
| 238 |
| 239 skia::RefPtr<SkCanvas> track_canvas = |
| 240 skia::AdoptRef(skia::CreatePlatformCanvas(track_rect.width(), |
| 241 track_rect.height(), |
| 242 false, |
| 243 track_bitmap_->GetPixels(), |
| 244 skia::CRASH_ON_FAILURE)); |
| 245 track_canvas->save(); |
| 246 track_canvas->translate(SkFloatToScalar(-track_rect.x()), |
| 247 SkFloatToScalar(-track_rect.y())); |
| 248 SkRect layer_sk_rect = SkRect::MakeXYWH( |
| 249 track_rect.x(), track_rect.y(), track_rect.width(), track_rect.height()); |
| 250 |
| 251 track_canvas->clipRect(layer_sk_rect); |
| 252 scrollbar_->PaintPart(track_canvas.get(), TRACK, track_rect); |
| 253 track_canvas->restore(); |
| 254 |
| 255 if (scrollbar_->HasThumb()) { |
| 256 gfx::Rect thumb_rect = OriginThumbRect(); |
| 257 thumb_bitmap_ = UIResourceBitmap::Create( |
| 258 new uint8_t[thumb_rect.width() * thumb_rect.height() * 4], |
| 259 UIResourceBitmap::RGBA8, |
| 260 thumb_rect.size()); |
| 261 |
| 262 skia::RefPtr<SkCanvas> thumb_canvas = |
| 263 skia::AdoptRef(skia::CreatePlatformCanvas(thumb_rect.width(), |
| 264 thumb_rect.height(), |
| 265 false, |
| 266 thumb_bitmap_->GetPixels(), |
| 267 skia::CRASH_ON_FAILURE)); |
| 268 |
| 269 scrollbar_->PaintPart(thumb_canvas.get(), THUMB, thumb_rect); |
346 } | 270 } |
347 return ScrollbarLayerRectToContentRect(gfx::Rect(thumb_size)); | 271 } |
| 272 |
| 273 scoped_refptr<UIResourceBitmap> ScrollbarLayer::GetTrackBitmap( |
| 274 bool resource_lost) { |
| 275 return track_bitmap_; |
| 276 } |
| 277 |
| 278 scoped_refptr<UIResourceBitmap> ScrollbarLayer::GetThumbBitmap( |
| 279 bool resource_lost) { |
| 280 return thumb_bitmap_; |
348 } | 281 } |
349 | 282 |
350 } // namespace cc | 283 } // namespace cc |
OLD | NEW |