OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 "cc/layers/painted_scrollbar_layer.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/auto_reset.h" | |
10 #include "base/basictypes.h" | |
11 #include "base/trace_event/trace_event.h" | |
12 #include "cc/base/math_util.h" | |
13 #include "cc/layers/painted_scrollbar_layer_impl.h" | |
14 #include "cc/resources/ui_resource_bitmap.h" | |
15 #include "cc/trees/layer_tree_host.h" | |
16 #include "cc/trees/layer_tree_impl.h" | |
17 #include "skia/ext/platform_canvas.h" | |
18 #include "skia/ext/refptr.h" | |
19 #include "third_party/skia/include/core/SkBitmap.h" | |
20 #include "third_party/skia/include/core/SkCanvas.h" | |
21 #include "third_party/skia/include/core/SkSize.h" | |
22 #include "ui/gfx/geometry/size_conversions.h" | |
23 #include "ui/gfx/skia_util.h" | |
24 | |
25 namespace cc { | |
26 | |
27 scoped_ptr<LayerImpl> PaintedScrollbarLayer::CreateLayerImpl( | |
28 LayerTreeImpl* tree_impl) { | |
29 return PaintedScrollbarLayerImpl::Create( | |
30 tree_impl, id(), scrollbar_->Orientation()); | |
31 } | |
32 | |
33 scoped_refptr<PaintedScrollbarLayer> PaintedScrollbarLayer::Create( | |
34 scoped_ptr<Scrollbar> scrollbar, | |
35 int scroll_layer_id) { | |
36 return make_scoped_refptr( | |
37 new PaintedScrollbarLayer(scrollbar.Pass(), scroll_layer_id)); | |
38 } | |
39 | |
40 PaintedScrollbarLayer::PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar, | |
41 int scroll_layer_id) | |
42 : scrollbar_(scrollbar.Pass()), | |
43 scroll_layer_id_(scroll_layer_id), | |
44 clip_layer_id_(Layer::INVALID_ID), | |
45 internal_contents_scale_(0.f), | |
46 thumb_thickness_(scrollbar_->ThumbThickness()), | |
47 thumb_length_(scrollbar_->ThumbLength()), | |
48 is_overlay_(scrollbar_->IsOverlay()), | |
49 has_thumb_(scrollbar_->HasThumb()) { | |
50 if (!scrollbar_->IsOverlay()) | |
51 SetShouldScrollOnMainThread(true); | |
52 } | |
53 | |
54 PaintedScrollbarLayer::~PaintedScrollbarLayer() {} | |
55 | |
56 int PaintedScrollbarLayer::ScrollLayerId() const { | |
57 return scroll_layer_id_; | |
58 } | |
59 | |
60 void PaintedScrollbarLayer::SetScrollLayer(int layer_id) { | |
61 if (layer_id == scroll_layer_id_) | |
62 return; | |
63 | |
64 scroll_layer_id_ = layer_id; | |
65 SetNeedsFullTreeSync(); | |
66 } | |
67 | |
68 void PaintedScrollbarLayer::SetClipLayer(int layer_id) { | |
69 if (layer_id == clip_layer_id_) | |
70 return; | |
71 | |
72 clip_layer_id_ = layer_id; | |
73 SetNeedsFullTreeSync(); | |
74 } | |
75 | |
76 bool PaintedScrollbarLayer::OpacityCanAnimateOnImplThread() const { | |
77 return scrollbar_->IsOverlay(); | |
78 } | |
79 | |
80 ScrollbarOrientation PaintedScrollbarLayer::orientation() const { | |
81 return scrollbar_->Orientation(); | |
82 } | |
83 | |
84 int PaintedScrollbarLayer::MaxTextureSize() { | |
85 DCHECK(layer_tree_host()); | |
86 return layer_tree_host()->GetRendererCapabilities().max_texture_size; | |
87 } | |
88 | |
89 float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) { | |
90 // If the scaled bounds() is bigger than the max texture size of the | |
91 // device, we need to clamp it by rescaling, since this is used | |
92 // below to set the texture size. | |
93 gfx::Size scaled_bounds = gfx::ToCeiledSize(gfx::ScaleSize(bounds(), scale)); | |
94 if (scaled_bounds.width() > MaxTextureSize() || | |
95 scaled_bounds.height() > MaxTextureSize()) { | |
96 if (scaled_bounds.width() > scaled_bounds.height()) | |
97 return (MaxTextureSize() - 1) / static_cast<float>(bounds().width()); | |
98 else | |
99 return (MaxTextureSize() - 1) / static_cast<float>(bounds().height()); | |
100 } | |
101 return scale; | |
102 } | |
103 | |
104 void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { | |
105 Layer::PushPropertiesTo(layer); | |
106 | |
107 PushScrollClipPropertiesTo(layer); | |
108 | |
109 PaintedScrollbarLayerImpl* scrollbar_layer = | |
110 static_cast<PaintedScrollbarLayerImpl*>(layer); | |
111 | |
112 scrollbar_layer->set_internal_contents_scale_and_bounds( | |
113 internal_contents_scale_, internal_content_bounds_); | |
114 | |
115 scrollbar_layer->SetThumbThickness(thumb_thickness_); | |
116 scrollbar_layer->SetThumbLength(thumb_length_); | |
117 if (orientation() == HORIZONTAL) { | |
118 scrollbar_layer->SetTrackStart( | |
119 track_rect_.x() - location_.x()); | |
120 scrollbar_layer->SetTrackLength(track_rect_.width()); | |
121 } else { | |
122 scrollbar_layer->SetTrackStart( | |
123 track_rect_.y() - location_.y()); | |
124 scrollbar_layer->SetTrackLength(track_rect_.height()); | |
125 } | |
126 | |
127 if (track_resource_.get()) | |
128 scrollbar_layer->set_track_ui_resource_id(track_resource_->id()); | |
129 else | |
130 scrollbar_layer->set_track_ui_resource_id(0); | |
131 if (thumb_resource_.get()) | |
132 scrollbar_layer->set_thumb_ui_resource_id(thumb_resource_->id()); | |
133 else | |
134 scrollbar_layer->set_thumb_ui_resource_id(0); | |
135 | |
136 scrollbar_layer->set_is_overlay_scrollbar(is_overlay_); | |
137 } | |
138 | |
139 ScrollbarLayerInterface* PaintedScrollbarLayer::ToScrollbarLayer() { | |
140 return this; | |
141 } | |
142 | |
143 void PaintedScrollbarLayer::PushScrollClipPropertiesTo(LayerImpl* layer) { | |
144 PaintedScrollbarLayerImpl* scrollbar_layer = | |
145 static_cast<PaintedScrollbarLayerImpl*>(layer); | |
146 | |
147 scrollbar_layer->SetScrollLayerAndClipLayerByIds(scroll_layer_id_, | |
148 clip_layer_id_); | |
149 } | |
150 | |
151 void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) { | |
152 // When the LTH is set to null or has changed, then this layer should remove | |
153 // all of its associated resources. | |
154 if (!host || host != layer_tree_host()) { | |
155 track_resource_ = nullptr; | |
156 thumb_resource_ = nullptr; | |
157 } | |
158 | |
159 Layer::SetLayerTreeHost(host); | |
160 } | |
161 | |
162 gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect( | |
163 const gfx::Rect& layer_rect) const { | |
164 // Don't intersect with the bounds as in LayerRectToContentRect() because | |
165 // layer_rect here might be in coordinates of the containing layer. | |
166 gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect( | |
167 layer_rect, internal_contents_scale_, internal_contents_scale_); | |
168 // We should never return a rect bigger than the content bounds. | |
169 gfx::Size clamped_size = expanded_rect.size(); | |
170 clamped_size.SetToMin(internal_content_bounds_); | |
171 expanded_rect.set_size(clamped_size); | |
172 return expanded_rect; | |
173 } | |
174 | |
175 gfx::Rect PaintedScrollbarLayer::OriginThumbRect() const { | |
176 gfx::Size thumb_size; | |
177 if (orientation() == HORIZONTAL) { | |
178 thumb_size = | |
179 gfx::Size(scrollbar_->ThumbLength(), scrollbar_->ThumbThickness()); | |
180 } else { | |
181 thumb_size = | |
182 gfx::Size(scrollbar_->ThumbThickness(), scrollbar_->ThumbLength()); | |
183 } | |
184 return gfx::Rect(thumb_size); | |
185 } | |
186 | |
187 void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() { | |
188 UpdateProperty(scrollbar_->TrackRect(), &track_rect_); | |
189 UpdateProperty(scrollbar_->Location(), &location_); | |
190 UpdateProperty(scrollbar_->IsOverlay(), &is_overlay_); | |
191 UpdateProperty(scrollbar_->HasThumb(), &has_thumb_); | |
192 if (has_thumb_) { | |
193 UpdateProperty(scrollbar_->ThumbThickness(), &thumb_thickness_); | |
194 UpdateProperty(scrollbar_->ThumbLength(), &thumb_length_); | |
195 } else { | |
196 UpdateProperty(0, &thumb_thickness_); | |
197 UpdateProperty(0, &thumb_length_); | |
198 } | |
199 } | |
200 | |
201 void PaintedScrollbarLayer::UpdateInternalContentScale() { | |
202 float scale = layer_tree_host()->device_scale_factor(); | |
203 if (layer_tree_host() | |
204 ->settings() | |
205 .layer_transforms_should_scale_layer_contents) { | |
206 gfx::Vector2dF transform_scales = | |
207 MathUtil::ComputeTransform2dScaleComponents(draw_transform(), scale); | |
208 scale = std::max(transform_scales.x(), transform_scales.y()); | |
209 } | |
210 bool changed = false; | |
211 changed |= UpdateProperty(ClampScaleToMaxTextureSize(scale), | |
212 &internal_contents_scale_); | |
213 changed |= UpdateProperty( | |
214 gfx::ToCeiledSize(gfx::ScaleSize(bounds(), internal_contents_scale_)), | |
215 &internal_content_bounds_); | |
216 if (changed) { | |
217 // If the content scale or bounds change, repaint. | |
218 SetNeedsDisplay(); | |
219 } | |
220 } | |
221 | |
222 bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue, | |
223 const OcclusionTracker<Layer>* occlusion) { | |
224 { | |
225 base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_, | |
226 true); | |
227 Layer::Update(queue, occlusion); | |
228 UpdateInternalContentScale(); | |
229 } | |
230 | |
231 UpdateThumbAndTrackGeometry(); | |
232 | |
233 gfx::Rect track_layer_rect = gfx::Rect(location_, bounds()); | |
234 gfx::Rect scaled_track_rect = ScrollbarLayerRectToContentRect( | |
235 track_layer_rect); | |
236 | |
237 bool updated = false; | |
238 | |
239 if (track_rect_.IsEmpty() || scaled_track_rect.IsEmpty()) { | |
240 if (track_resource_) { | |
241 track_resource_ = nullptr; | |
242 thumb_resource_ = nullptr; | |
243 SetNeedsPushProperties(); | |
244 updated = true; | |
245 } | |
246 return updated; | |
247 } | |
248 | |
249 if (!has_thumb_ && thumb_resource_) { | |
250 thumb_resource_ = nullptr; | |
251 SetNeedsPushProperties(); | |
252 updated = true; | |
253 } | |
254 | |
255 if (update_rect_.IsEmpty() && track_resource_) | |
256 return updated; | |
257 | |
258 track_resource_ = ScopedUIResource::Create( | |
259 layer_tree_host(), | |
260 RasterizeScrollbarPart(track_layer_rect, scaled_track_rect, TRACK)); | |
261 | |
262 gfx::Rect thumb_layer_rect = OriginThumbRect(); | |
263 gfx::Rect scaled_thumb_rect = | |
264 ScrollbarLayerRectToContentRect(thumb_layer_rect); | |
265 if (has_thumb_ && !scaled_thumb_rect.IsEmpty()) { | |
266 thumb_resource_ = ScopedUIResource::Create( | |
267 layer_tree_host(), | |
268 RasterizeScrollbarPart(thumb_layer_rect, scaled_thumb_rect, THUMB)); | |
269 } | |
270 | |
271 // UI resources changed so push properties is needed. | |
272 SetNeedsPushProperties(); | |
273 updated = true; | |
274 return updated; | |
275 } | |
276 | |
277 UIResourceBitmap PaintedScrollbarLayer::RasterizeScrollbarPart( | |
278 const gfx::Rect& layer_rect, | |
279 const gfx::Rect& content_rect, | |
280 ScrollbarPart part) { | |
281 DCHECK(!content_rect.size().IsEmpty()); | |
282 DCHECK(!layer_rect.size().IsEmpty()); | |
283 | |
284 SkBitmap skbitmap; | |
285 skbitmap.allocN32Pixels(content_rect.width(), content_rect.height()); | |
286 SkCanvas skcanvas(skbitmap); | |
287 | |
288 float scale_x = | |
289 content_rect.width() / static_cast<float>(layer_rect.width()); | |
290 float scale_y = | |
291 content_rect.height() / static_cast<float>(layer_rect.height()); | |
292 | |
293 skcanvas.scale(SkFloatToScalar(scale_x), | |
294 SkFloatToScalar(scale_y)); | |
295 skcanvas.translate(SkFloatToScalar(-layer_rect.x()), | |
296 SkFloatToScalar(-layer_rect.y())); | |
297 | |
298 SkRect layer_skrect = RectToSkRect(layer_rect); | |
299 SkPaint paint; | |
300 paint.setAntiAlias(false); | |
301 paint.setXfermodeMode(SkXfermode::kClear_Mode); | |
302 skcanvas.drawRect(layer_skrect, paint); | |
303 skcanvas.clipRect(layer_skrect); | |
304 | |
305 scrollbar_->PaintPart(&skcanvas, part, layer_rect); | |
306 // Make sure that the pixels are no longer mutable to unavoid unnecessary | |
307 // allocation and copying. | |
308 skbitmap.setImmutable(); | |
309 | |
310 return UIResourceBitmap(skbitmap); | |
311 } | |
312 | |
313 } // namespace cc | |
OLD | NEW |