Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / cc / layers / painted_scrollbar_layer.cc
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 "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"
20
21 namespace cc {
22
23 scoped_ptr<LayerImpl> PaintedScrollbarLayer::CreateLayerImpl(
24     LayerTreeImpl* tree_impl) {
25   return PaintedScrollbarLayerImpl::Create(
26       tree_impl, id(), scrollbar_->Orientation()).PassAs<LayerImpl>();
27 }
28
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));
34 }
35
36 PaintedScrollbarLayer::PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar,
37                                              int scroll_layer_id)
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);
47 }
48
49 PaintedScrollbarLayer::~PaintedScrollbarLayer() {}
50
51 int PaintedScrollbarLayer::ScrollLayerId() const {
52   return scroll_layer_id_;
53 }
54
55 void PaintedScrollbarLayer::SetScrollLayer(int layer_id) {
56   if (layer_id == scroll_layer_id_)
57     return;
58
59   scroll_layer_id_ = layer_id;
60   SetNeedsFullTreeSync();
61 }
62
63 void PaintedScrollbarLayer::SetClipLayer(int layer_id) {
64   if (layer_id == clip_layer_id_)
65     return;
66
67   clip_layer_id_ = layer_id;
68   SetNeedsFullTreeSync();
69 }
70
71 bool PaintedScrollbarLayer::OpacityCanAnimateOnImplThread() const {
72   return scrollbar_->IsOverlay();
73 }
74
75 ScrollbarOrientation PaintedScrollbarLayer::orientation() const {
76   return scrollbar_->Orientation();
77 }
78
79 int PaintedScrollbarLayer::MaxTextureSize() {
80   DCHECK(layer_tree_host());
81   return layer_tree_host()->GetRendererCapabilities().max_texture_size;
82 }
83
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());
93     else
94       return (MaxTextureSize() - 1) / static_cast<float>(bounds().height());
95   }
96   return scale;
97 }
98
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),
110       device_scale_factor,
111       page_scale_factor,
112       maximum_animation_contents_scale,
113       animating_transform_to_screen,
114       contents_scale_x,
115       contents_scale_y,
116       content_bounds);
117 }
118
119 void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
120   ContentsScalingLayer::PushPropertiesTo(layer);
121
122   PushScrollClipPropertiesTo(layer);
123
124   PaintedScrollbarLayerImpl* scrollbar_layer =
125       static_cast<PaintedScrollbarLayerImpl*>(layer);
126
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());
133   } else {
134     scrollbar_layer->SetTrackStart(
135         track_rect_.y() - location_.y());
136     scrollbar_layer->SetTrackLength(track_rect_.height());
137   }
138
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());
143
144   scrollbar_layer->set_is_overlay_scrollbar(is_overlay_);
145 }
146
147 ScrollbarLayerInterface* PaintedScrollbarLayer::ToScrollbarLayer() {
148   return this;
149 }
150
151 void PaintedScrollbarLayer::PushScrollClipPropertiesTo(LayerImpl* layer) {
152   PaintedScrollbarLayerImpl* scrollbar_layer =
153       static_cast<PaintedScrollbarLayerImpl*>(layer);
154
155   scrollbar_layer->SetScrollLayerById(scroll_layer_id_);
156   scrollbar_layer->SetClipLayerById(clip_layer_id_);
157 }
158
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();
165   }
166
167   ContentsScalingLayer::SetLayerTreeHost(host);
168 }
169
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;
181 }
182
183 gfx::Rect PaintedScrollbarLayer::OriginThumbRect() const {
184   gfx::Size thumb_size;
185   if (orientation() == HORIZONTAL) {
186     thumb_size =
187         gfx::Size(scrollbar_->ThumbLength(), scrollbar_->ThumbThickness());
188   } else {
189     thumb_size =
190         gfx::Size(scrollbar_->ThumbThickness(), scrollbar_->ThumbLength());
191   }
192   return gfx::Rect(thumb_size);
193 }
194
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_);
200   if (has_thumb_) {
201     UpdateProperty(scrollbar_->ThumbThickness(), &thumb_thickness_);
202     UpdateProperty(scrollbar_->ThumbLength(), &thumb_length_);
203   }
204 }
205
206 bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
207                                    const OcclusionTracker<Layer>* occlusion) {
208   UpdateThumbAndTrackGeometry();
209
210   gfx::Rect track_layer_rect = gfx::Rect(location_, bounds());
211   gfx::Rect scaled_track_rect = ScrollbarLayerRectToContentRect(
212       track_layer_rect);
213
214   if (track_rect_.IsEmpty() || scaled_track_rect.IsEmpty())
215     return false;
216
217   {
218     base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
219                                                   true);
220     ContentsScalingLayer::Update(queue, occlusion);
221   }
222
223   if (update_rect_.IsEmpty() && track_resource_)
224     return false;
225
226   track_resource_ = ScopedUIResource::Create(
227       layer_tree_host(),
228       RasterizeScrollbarPart(track_layer_rect, scaled_track_rect, TRACK));
229
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(
235         layer_tree_host(),
236         RasterizeScrollbarPart(thumb_layer_rect, scaled_thumb_rect, THUMB));
237   }
238
239   // UI resources changed so push properties is needed.
240   SetNeedsPushProperties();
241   return true;
242 }
243
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());
250
251   SkBitmap skbitmap;
252   skbitmap.allocN32Pixels(content_rect.width(), content_rect.height());
253   SkCanvas skcanvas(skbitmap);
254
255   float scale_x =
256       content_rect.width() / static_cast<float>(layer_rect.width());
257   float scale_y =
258       content_rect.height() / static_cast<float>(layer_rect.height());
259
260   skcanvas.scale(SkFloatToScalar(scale_x),
261                  SkFloatToScalar(scale_y));
262   skcanvas.translate(SkFloatToScalar(-layer_rect.x()),
263                      SkFloatToScalar(-layer_rect.y()));
264
265   SkRect layer_skrect = RectToSkRect(layer_rect);
266   SkPaint paint;
267   paint.setAntiAlias(false);
268   paint.setXfermodeMode(SkXfermode::kClear_Mode);
269   skcanvas.drawRect(layer_skrect, paint);
270   skcanvas.clipRect(layer_skrect);
271
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();
276
277   return UIResourceBitmap(skbitmap);
278 }
279
280 }  // namespace cc