- add sources.
[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(
37     scoped_ptr<Scrollbar> scrollbar,
38     int scroll_layer_id)
39     : scrollbar_(scrollbar.Pass()),
40       scroll_layer_id_(scroll_layer_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::SetScrollLayerId(int id) {
56   if (id == scroll_layer_id_)
57     return;
58
59   scroll_layer_id_ = id;
60   SetNeedsFullTreeSync();
61 }
62
63 bool PaintedScrollbarLayer::OpacityCanAnimateOnImplThread() const {
64   return scrollbar_->IsOverlay();
65 }
66
67 ScrollbarOrientation PaintedScrollbarLayer::orientation() const {
68   return scrollbar_->Orientation();
69 }
70
71 int PaintedScrollbarLayer::MaxTextureSize() {
72   DCHECK(layer_tree_host());
73   return layer_tree_host()->GetRendererCapabilities().max_texture_size;
74 }
75
76 float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) {
77   // If the scaled content_bounds() is bigger than the max texture size of the
78   // device, we need to clamp it by rescaling, since content_bounds() is used
79   // below to set the texture size.
80   gfx::Size scaled_bounds = ComputeContentBoundsForScale(scale, scale);
81   if (scaled_bounds.width() > MaxTextureSize() ||
82       scaled_bounds.height() > MaxTextureSize()) {
83     if (scaled_bounds.width() > scaled_bounds.height())
84       return (MaxTextureSize() - 1) / static_cast<float>(bounds().width());
85     else
86       return (MaxTextureSize() - 1) / static_cast<float>(bounds().height());
87   }
88   return scale;
89 }
90
91 void PaintedScrollbarLayer::CalculateContentsScale(
92     float ideal_contents_scale,
93     float device_scale_factor,
94     float page_scale_factor,
95     bool animating_transform_to_screen,
96     float* contents_scale_x,
97     float* contents_scale_y,
98     gfx::Size* content_bounds) {
99   ContentsScalingLayer::CalculateContentsScale(
100       ClampScaleToMaxTextureSize(ideal_contents_scale),
101       device_scale_factor,
102       page_scale_factor,
103       animating_transform_to_screen,
104       contents_scale_x,
105       contents_scale_y,
106       content_bounds);
107 }
108
109 void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
110   ContentsScalingLayer::PushPropertiesTo(layer);
111
112   PaintedScrollbarLayerImpl* scrollbar_layer =
113       static_cast<PaintedScrollbarLayerImpl*>(layer);
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   if (thumb_resource_.get())
130     scrollbar_layer->set_thumb_ui_resource_id(thumb_resource_->id());
131
132   scrollbar_layer->set_is_overlay_scrollbar(is_overlay_);
133 }
134
135 ScrollbarLayerInterface* PaintedScrollbarLayer::ToScrollbarLayer() {
136   return this;
137 }
138
139 void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
140   // When the LTH is set to null or has changed, then this layer should remove
141   // all of its associated resources.
142   if (!host || host != layer_tree_host()) {
143     track_resource_.reset();
144     thumb_resource_.reset();
145   }
146
147   ContentsScalingLayer::SetLayerTreeHost(host);
148 }
149
150 gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect(
151     gfx::Rect layer_rect) const {
152   // Don't intersect with the bounds as in LayerRectToContentRect() because
153   // layer_rect here might be in coordinates of the containing layer.
154   gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect(
155       layer_rect, contents_scale_y(), contents_scale_y());
156   // We should never return a rect bigger than the content_bounds().
157   gfx::Size clamped_size = expanded_rect.size();
158   clamped_size.SetToMin(content_bounds());
159   expanded_rect.set_size(clamped_size);
160   return expanded_rect;
161 }
162
163 gfx::Rect PaintedScrollbarLayer::OriginThumbRect() const {
164   gfx::Size thumb_size;
165   if (orientation() == HORIZONTAL) {
166     thumb_size =
167         gfx::Size(scrollbar_->ThumbLength(), scrollbar_->ThumbThickness());
168   } else {
169     thumb_size =
170         gfx::Size(scrollbar_->ThumbThickness(), scrollbar_->ThumbLength());
171   }
172   return ScrollbarLayerRectToContentRect(gfx::Rect(thumb_size));
173 }
174
175 void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() {
176   UpdateProperty(scrollbar_->TrackRect(), &track_rect_);
177   UpdateProperty(scrollbar_->Location(), &location_);
178   UpdateProperty(scrollbar_->IsOverlay(), &is_overlay_);
179   UpdateProperty(scrollbar_->HasThumb(), &has_thumb_);
180   if (has_thumb_) {
181     UpdateProperty(scrollbar_->ThumbThickness(), &thumb_thickness_);
182     UpdateProperty(scrollbar_->ThumbLength(), &thumb_length_);
183   }
184 }
185
186 bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
187                                    const OcclusionTracker* occlusion) {
188   UpdateThumbAndTrackGeometry();
189
190   gfx::Rect scaled_track_rect = ScrollbarLayerRectToContentRect(
191       gfx::Rect(location_, bounds()));
192
193   if (track_rect_.IsEmpty() || scaled_track_rect.IsEmpty())
194     return false;
195
196   {
197     base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
198                                                   true);
199     ContentsScalingLayer::Update(queue, occlusion);
200   }
201
202   if (update_rect_.IsEmpty() && track_resource_)
203     return false;
204
205   track_resource_ = ScopedUIResource::Create(
206       layer_tree_host(), RasterizeScrollbarPart(scaled_track_rect, TRACK));
207
208   gfx::Rect thumb_rect = OriginThumbRect();
209   if (has_thumb_ && !thumb_rect.IsEmpty()) {
210     thumb_resource_ = ScopedUIResource::Create(
211         layer_tree_host(), RasterizeScrollbarPart(thumb_rect, THUMB));
212   }
213
214   // UI resources changed so push properties is needed.
215   SetNeedsPushProperties();
216   return true;
217 }
218
219 UIResourceBitmap PaintedScrollbarLayer::RasterizeScrollbarPart(
220     gfx::Rect rect,
221     ScrollbarPart part) {
222   DCHECK(!rect.size().IsEmpty());
223
224   SkBitmap skbitmap;
225   skbitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
226   skbitmap.allocPixels();
227
228   SkCanvas skcanvas(skbitmap);
229   skcanvas.translate(SkFloatToScalar(-rect.x()), SkFloatToScalar(-rect.y()));
230   skcanvas.scale(SkFloatToScalar(contents_scale_x()),
231                  SkFloatToScalar(contents_scale_y()));
232
233   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
234       rect, 1.f / contents_scale_x(), 1.f / contents_scale_y());
235   SkRect layer_skrect = RectToSkRect(layer_rect);
236   SkPaint paint;
237   paint.setAntiAlias(false);
238   paint.setXfermodeMode(SkXfermode::kClear_Mode);
239   skcanvas.drawRect(layer_skrect, paint);
240   skcanvas.clipRect(layer_skrect);
241
242   scrollbar_->PaintPart(&skcanvas, part, layer_rect);
243   // Make sure that the pixels are no longer mutable to unavoid unnecessary
244   // allocation and copying.
245   skbitmap.setImmutable();
246
247   return UIResourceBitmap(skbitmap);
248 }
249
250 }  // namespace cc