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.
5 #include "cc/layers/painted_scrollbar_layer.h"
7 #include "base/auto_reset.h"
8 #include "base/basictypes.h"
9 #include "base/debug/trace_event.h"
10 #include "cc/layers/painted_scrollbar_layer_impl.h"
11 #include "cc/resources/ui_resource_bitmap.h"
12 #include "cc/trees/layer_tree_host.h"
13 #include "cc/trees/layer_tree_impl.h"
14 #include "skia/ext/platform_canvas.h"
15 #include "skia/ext/refptr.h"
16 #include "third_party/skia/include/core/SkBitmap.h"
17 #include "third_party/skia/include/core/SkCanvas.h"
18 #include "third_party/skia/include/core/SkSize.h"
19 #include "ui/gfx/skia_util.h"
23 scoped_ptr
<LayerImpl
> PaintedScrollbarLayer::CreateLayerImpl(
24 LayerTreeImpl
* tree_impl
) {
25 return PaintedScrollbarLayerImpl::Create(
26 tree_impl
, id(), scrollbar_
->Orientation()).PassAs
<LayerImpl
>();
29 scoped_refptr
<PaintedScrollbarLayer
> PaintedScrollbarLayer::Create(
30 scoped_ptr
<Scrollbar
> scrollbar
,
31 int scroll_layer_id
) {
32 return make_scoped_refptr(
33 new PaintedScrollbarLayer(scrollbar
.Pass(), scroll_layer_id
));
36 PaintedScrollbarLayer::PaintedScrollbarLayer(scoped_ptr
<Scrollbar
> scrollbar
,
38 : scrollbar_(scrollbar
.Pass()),
39 scroll_layer_id_(scroll_layer_id
),
40 clip_layer_id_(Layer::INVALID_ID
),
41 thumb_thickness_(scrollbar_
->ThumbThickness()),
42 thumb_length_(scrollbar_
->ThumbLength()),
43 is_overlay_(scrollbar_
->IsOverlay()),
44 has_thumb_(scrollbar_
->HasThumb()) {
45 if (!scrollbar_
->IsOverlay())
46 SetShouldScrollOnMainThread(true);
49 PaintedScrollbarLayer::~PaintedScrollbarLayer() {}
51 int PaintedScrollbarLayer::ScrollLayerId() const {
52 return scroll_layer_id_
;
55 void PaintedScrollbarLayer::SetScrollLayer(int layer_id
) {
56 if (layer_id
== scroll_layer_id_
)
59 scroll_layer_id_
= layer_id
;
60 SetNeedsFullTreeSync();
63 void PaintedScrollbarLayer::SetClipLayer(int layer_id
) {
64 if (layer_id
== clip_layer_id_
)
67 clip_layer_id_
= layer_id
;
68 SetNeedsFullTreeSync();
71 bool PaintedScrollbarLayer::OpacityCanAnimateOnImplThread() const {
72 return scrollbar_
->IsOverlay();
75 ScrollbarOrientation
PaintedScrollbarLayer::orientation() const {
76 return scrollbar_
->Orientation();
79 int PaintedScrollbarLayer::MaxTextureSize() {
80 DCHECK(layer_tree_host());
81 return layer_tree_host()->GetRendererCapabilities().max_texture_size
;
84 float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale
) {
85 // If the scaled content_bounds() is bigger than the max texture size of the
86 // device, we need to clamp it by rescaling, since content_bounds() is used
87 // below to set the texture size.
88 gfx::Size scaled_bounds
= ComputeContentBoundsForScale(scale
, scale
);
89 if (scaled_bounds
.width() > MaxTextureSize() ||
90 scaled_bounds
.height() > MaxTextureSize()) {
91 if (scaled_bounds
.width() > scaled_bounds
.height())
92 return (MaxTextureSize() - 1) / static_cast<float>(bounds().width());
94 return (MaxTextureSize() - 1) / static_cast<float>(bounds().height());
99 void PaintedScrollbarLayer::CalculateContentsScale(
100 float ideal_contents_scale
,
101 float device_scale_factor
,
102 float page_scale_factor
,
103 float maximum_animation_contents_scale
,
104 bool animating_transform_to_screen
,
105 float* contents_scale_x
,
106 float* contents_scale_y
,
107 gfx::Size
* content_bounds
) {
108 ContentsScalingLayer::CalculateContentsScale(
109 ClampScaleToMaxTextureSize(ideal_contents_scale
),
112 maximum_animation_contents_scale
,
113 animating_transform_to_screen
,
119 void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl
* layer
) {
120 ContentsScalingLayer::PushPropertiesTo(layer
);
122 PushScrollClipPropertiesTo(layer
);
124 PaintedScrollbarLayerImpl
* scrollbar_layer
=
125 static_cast<PaintedScrollbarLayerImpl
*>(layer
);
127 scrollbar_layer
->SetThumbThickness(thumb_thickness_
);
128 scrollbar_layer
->SetThumbLength(thumb_length_
);
129 if (orientation() == HORIZONTAL
) {
130 scrollbar_layer
->SetTrackStart(
131 track_rect_
.x() - location_
.x());
132 scrollbar_layer
->SetTrackLength(track_rect_
.width());
134 scrollbar_layer
->SetTrackStart(
135 track_rect_
.y() - location_
.y());
136 scrollbar_layer
->SetTrackLength(track_rect_
.height());
139 if (track_resource_
.get())
140 scrollbar_layer
->set_track_ui_resource_id(track_resource_
->id());
141 if (thumb_resource_
.get())
142 scrollbar_layer
->set_thumb_ui_resource_id(thumb_resource_
->id());
144 scrollbar_layer
->set_is_overlay_scrollbar(is_overlay_
);
147 ScrollbarLayerInterface
* PaintedScrollbarLayer::ToScrollbarLayer() {
151 void PaintedScrollbarLayer::PushScrollClipPropertiesTo(LayerImpl
* layer
) {
152 PaintedScrollbarLayerImpl
* scrollbar_layer
=
153 static_cast<PaintedScrollbarLayerImpl
*>(layer
);
155 scrollbar_layer
->SetScrollLayerAndClipLayerByIds(scroll_layer_id_
,
159 void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost
* host
) {
160 // When the LTH is set to null or has changed, then this layer should remove
161 // all of its associated resources.
162 if (!host
|| host
!= layer_tree_host()) {
163 track_resource_
.reset();
164 thumb_resource_
.reset();
167 ContentsScalingLayer::SetLayerTreeHost(host
);
170 gfx::Rect
PaintedScrollbarLayer::ScrollbarLayerRectToContentRect(
171 const gfx::Rect
& layer_rect
) const {
172 // Don't intersect with the bounds as in LayerRectToContentRect() because
173 // layer_rect here might be in coordinates of the containing layer.
174 gfx::Rect expanded_rect
= gfx::ScaleToEnclosingRect(
175 layer_rect
, contents_scale_x(), contents_scale_y());
176 // We should never return a rect bigger than the content_bounds().
177 gfx::Size clamped_size
= expanded_rect
.size();
178 clamped_size
.SetToMin(content_bounds());
179 expanded_rect
.set_size(clamped_size
);
180 return expanded_rect
;
183 gfx::Rect
PaintedScrollbarLayer::OriginThumbRect() const {
184 gfx::Size thumb_size
;
185 if (orientation() == HORIZONTAL
) {
187 gfx::Size(scrollbar_
->ThumbLength(), scrollbar_
->ThumbThickness());
190 gfx::Size(scrollbar_
->ThumbThickness(), scrollbar_
->ThumbLength());
192 return gfx::Rect(thumb_size
);
195 void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() {
196 UpdateProperty(scrollbar_
->TrackRect(), &track_rect_
);
197 UpdateProperty(scrollbar_
->Location(), &location_
);
198 UpdateProperty(scrollbar_
->IsOverlay(), &is_overlay_
);
199 UpdateProperty(scrollbar_
->HasThumb(), &has_thumb_
);
201 UpdateProperty(scrollbar_
->ThumbThickness(), &thumb_thickness_
);
202 UpdateProperty(scrollbar_
->ThumbLength(), &thumb_length_
);
206 bool PaintedScrollbarLayer::Update(ResourceUpdateQueue
* queue
,
207 const OcclusionTracker
<Layer
>* occlusion
) {
208 UpdateThumbAndTrackGeometry();
210 gfx::Rect track_layer_rect
= gfx::Rect(location_
, bounds());
211 gfx::Rect scaled_track_rect
= ScrollbarLayerRectToContentRect(
214 if (track_rect_
.IsEmpty() || scaled_track_rect
.IsEmpty())
218 base::AutoReset
<bool> ignore_set_needs_commit(&ignore_set_needs_commit_
,
220 ContentsScalingLayer::Update(queue
, occlusion
);
223 if (update_rect_
.IsEmpty() && track_resource_
)
226 track_resource_
= ScopedUIResource::Create(
228 RasterizeScrollbarPart(track_layer_rect
, scaled_track_rect
, TRACK
));
230 gfx::Rect thumb_layer_rect
= OriginThumbRect();
231 gfx::Rect scaled_thumb_rect
=
232 ScrollbarLayerRectToContentRect(thumb_layer_rect
);
233 if (has_thumb_
&& !scaled_thumb_rect
.IsEmpty()) {
234 thumb_resource_
= ScopedUIResource::Create(
236 RasterizeScrollbarPart(thumb_layer_rect
, scaled_thumb_rect
, THUMB
));
239 // UI resources changed so push properties is needed.
240 SetNeedsPushProperties();
244 UIResourceBitmap
PaintedScrollbarLayer::RasterizeScrollbarPart(
245 const gfx::Rect
& layer_rect
,
246 const gfx::Rect
& content_rect
,
247 ScrollbarPart part
) {
248 DCHECK(!content_rect
.size().IsEmpty());
249 DCHECK(!layer_rect
.size().IsEmpty());
252 skbitmap
.allocN32Pixels(content_rect
.width(), content_rect
.height());
253 SkCanvas
skcanvas(skbitmap
);
256 content_rect
.width() / static_cast<float>(layer_rect
.width());
258 content_rect
.height() / static_cast<float>(layer_rect
.height());
260 skcanvas
.scale(SkFloatToScalar(scale_x
),
261 SkFloatToScalar(scale_y
));
262 skcanvas
.translate(SkFloatToScalar(-layer_rect
.x()),
263 SkFloatToScalar(-layer_rect
.y()));
265 SkRect layer_skrect
= RectToSkRect(layer_rect
);
267 paint
.setAntiAlias(false);
268 paint
.setXfermodeMode(SkXfermode::kClear_Mode
);
269 skcanvas
.drawRect(layer_skrect
, paint
);
270 skcanvas
.clipRect(layer_skrect
);
272 scrollbar_
->PaintPart(&skcanvas
, part
, layer_rect
);
273 // Make sure that the pixels are no longer mutable to unavoid unnecessary
274 // allocation and copying.
275 skbitmap
.setImmutable();
277 return UIResourceBitmap(skbitmap
);