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