blob: 4248617f5bcc75eab4c20d632871f839b2202770 [file] [log] [blame]
[email protected]80413d72013-08-30 20:25:331// 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/scrollbar_layer_impl_base.h"
6
7#include <algorithm>
[email protected]adeda572014-01-31 00:49:478#include "cc/trees/layer_tree_impl.h"
heejin.r.chungd28506ba2014-10-23 16:36:209#include "ui/gfx/geometry/rect_conversions.h"
[email protected]80413d72013-08-30 20:25:3310
11namespace cc {
12
[email protected]2ea5aba2013-09-11 14:26:5613ScrollbarLayerImplBase::ScrollbarLayerImplBase(
14 LayerTreeImpl* tree_impl,
15 int id,
16 ScrollbarOrientation orientation,
[email protected]adeda572014-01-31 00:49:4717 bool is_left_side_vertical_scrollbar,
18 bool is_overlay)
[email protected]80413d72013-08-30 20:25:3319 : LayerImpl(tree_impl, id),
kulkarni.a4015690f12014-10-10 13:50:0620 scroll_layer_(nullptr),
21 clip_layer_(nullptr),
[email protected]adeda572014-01-31 00:49:4722 is_overlay_scrollbar_(is_overlay),
[email protected]2ea5aba2013-09-11 14:26:5623 thumb_thickness_scale_factor_(1.f),
[email protected]80413d72013-08-30 20:25:3324 current_pos_(0.f),
25 maximum_(0),
26 orientation_(orientation),
[email protected]2ea5aba2013-09-11 14:26:5627 is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar),
[email protected]80413d72013-08-30 20:25:3328 vertical_adjust_(0.f),
kulkarni.a4015690f12014-10-10 13:50:0629 visible_to_total_length_ratio_(1.f) {
30}
[email protected]80413d72013-08-30 20:25:3331
[email protected]adeda572014-01-31 00:49:4732ScrollbarLayerImplBase::~ScrollbarLayerImplBase() {}
33
[email protected]80413d72013-08-30 20:25:3334void ScrollbarLayerImplBase::PushPropertiesTo(LayerImpl* layer) {
[email protected]930ff43b2014-05-02 05:24:0035 float active_opacity = layer->opacity();
[email protected]80413d72013-08-30 20:25:3336 LayerImpl::PushPropertiesTo(layer);
[email protected]930ff43b2014-05-02 05:24:0037 layer->SetOpacity(active_opacity);
[email protected]adeda572014-01-31 00:49:4738 DCHECK(layer->ToScrollbarLayer());
39 layer->ToScrollbarLayer()->set_is_overlay_scrollbar(is_overlay_scrollbar_);
40 PushScrollClipPropertiesTo(layer);
41}
42
43void ScrollbarLayerImplBase::PushScrollClipPropertiesTo(LayerImpl* layer) {
44 DCHECK(layer->ToScrollbarLayer());
[email protected]9942a732014-06-27 03:58:5745 layer->ToScrollbarLayer()->SetScrollLayerAndClipLayerByIds(ScrollLayerId(),
46 ClipLayerId());
[email protected]80413d72013-08-30 20:25:3347}
48
49ScrollbarLayerImplBase* ScrollbarLayerImplBase::ToScrollbarLayer() {
50 return this;
51}
52
[email protected]fe739df2014-04-28 22:25:1853namespace {
54
55typedef void (LayerImpl::*ScrollbarRegistrationOperation)(
56 ScrollbarLayerImplBase*);
57
58void RegisterScrollbarWithLayers(ScrollbarLayerImplBase* scrollbar,
59 LayerImpl* container_layer,
60 LayerImpl* scroll_layer,
61 ScrollbarRegistrationOperation operation) {
62 if (!container_layer || !scroll_layer)
63 return;
64
65 DCHECK(scrollbar);
66
67 // Scrollbars must be notifed of changes to their scroll and container layers
68 // and all scrollable layers in between.
69 for (LayerImpl* current_layer = scroll_layer;
70 current_layer && current_layer != container_layer->parent();
71 current_layer = current_layer->parent()) {
72 // TODO(wjmaclean) We shouldn't need to exempt the scroll_layer from the
73 // scrollable() test below. https://crbug.com/367858.
74 if (current_layer->scrollable() || current_layer == container_layer ||
75 current_layer == scroll_layer)
76 (current_layer->*operation)(scrollbar);
77 }
78}
79} // namespace
80
[email protected]9942a732014-06-27 03:58:5781void ScrollbarLayerImplBase::SetScrollLayerAndClipLayerByIds(
82 int scroll_layer_id,
83 int clip_layer_id) {
84 LayerImpl* scroll_layer = layer_tree_impl()->LayerById(scroll_layer_id);
85 LayerImpl* clip_layer = layer_tree_impl()->LayerById(clip_layer_id);
86 if (scroll_layer_ == scroll_layer && clip_layer_ == clip_layer)
[email protected]adeda572014-01-31 00:49:4787 return;
88
[email protected]fe739df2014-04-28 22:25:1889 RegisterScrollbarWithLayers(
90 this, clip_layer_, scroll_layer_, &LayerImpl::RemoveScrollbar);
[email protected]adeda572014-01-31 00:49:4791 scroll_layer_ = scroll_layer;
[email protected]adeda572014-01-31 00:49:4792 clip_layer_ = clip_layer;
[email protected]fe739df2014-04-28 22:25:1893 RegisterScrollbarWithLayers(
94 this, clip_layer_, scroll_layer_, &LayerImpl::AddScrollbar);
[email protected]9942a732014-06-27 03:58:5795
sataya.m07f11a82014-10-07 14:29:1896 ScrollbarParametersDidChange(false);
[email protected]adeda572014-01-31 00:49:4797}
98
[email protected]80413d72013-08-30 20:25:3399gfx::Rect ScrollbarLayerImplBase::ScrollbarLayerRectToContentRect(
[email protected]0023fc72014-01-10 20:05:06100 const gfx::RectF& layer_rect) const {
[email protected]80413d72013-08-30 20:25:33101 // Don't intersect with the bounds as in LayerRectToContentRect() because
102 // layer_rect here might be in coordinates of the containing layer.
103 gfx::RectF content_rect = gfx::ScaleRect(layer_rect,
104 contents_scale_x(),
105 contents_scale_y());
106 return gfx::ToEnclosingRect(content_rect);
107}
108
sataya.m68d7d9b42014-09-22 16:01:59109bool ScrollbarLayerImplBase::SetCurrentPos(float current_pos) {
[email protected]80413d72013-08-30 20:25:33110 if (current_pos_ == current_pos)
sataya.m68d7d9b42014-09-22 16:01:59111 return false;
[email protected]80413d72013-08-30 20:25:33112 current_pos_ = current_pos;
113 NoteLayerPropertyChanged();
sataya.m68d7d9b42014-09-22 16:01:59114 return true;
[email protected]80413d72013-08-30 20:25:33115}
116
sataya.m68d7d9b42014-09-22 16:01:59117bool ScrollbarLayerImplBase::SetMaximum(int maximum) {
[email protected]80413d72013-08-30 20:25:33118 if (maximum_ == maximum)
sataya.m68d7d9b42014-09-22 16:01:59119 return false;
[email protected]80413d72013-08-30 20:25:33120 maximum_ = maximum;
121 NoteLayerPropertyChanged();
sataya.m68d7d9b42014-09-22 16:01:59122 return true;
[email protected]80413d72013-08-30 20:25:33123}
124
timav87a47f52014-10-16 01:09:56125bool ScrollbarLayerImplBase::CanScrollOrientation() const {
timav3ca696932014-10-15 02:19:04126 if (!scroll_layer_)
127 return false;
128 return scroll_layer_->user_scrollable(orientation()) && (0 < maximum());
129}
130
sataya.m68d7d9b42014-09-22 16:01:59131bool ScrollbarLayerImplBase::SetVerticalAdjust(float vertical_adjust) {
[email protected]80413d72013-08-30 20:25:33132 if (vertical_adjust_ == vertical_adjust)
sataya.m68d7d9b42014-09-22 16:01:59133 return false;
[email protected]80413d72013-08-30 20:25:33134 vertical_adjust_ = vertical_adjust;
135 NoteLayerPropertyChanged();
sataya.m68d7d9b42014-09-22 16:01:59136 return true;
[email protected]80413d72013-08-30 20:25:33137}
138
sataya.m68d7d9b42014-09-22 16:01:59139bool ScrollbarLayerImplBase::SetVisibleToTotalLengthRatio(float ratio) {
[email protected]41bee9f02014-01-09 01:11:35140 if (!IsThumbResizable())
sataya.m68d7d9b42014-09-22 16:01:59141 return false;
[email protected]41bee9f02014-01-09 01:11:35142
[email protected]80413d72013-08-30 20:25:33143 if (visible_to_total_length_ratio_ == ratio)
sataya.m68d7d9b42014-09-22 16:01:59144 return false;
[email protected]80413d72013-08-30 20:25:33145 visible_to_total_length_ratio_ = ratio;
146 NoteLayerPropertyChanged();
sataya.m68d7d9b42014-09-22 16:01:59147 return true;
[email protected]80413d72013-08-30 20:25:33148}
149
sataya.m68d7d9b42014-09-22 16:01:59150bool ScrollbarLayerImplBase::SetThumbThicknessScaleFactor(float factor) {
[email protected]534236b2013-10-25 21:19:20151 if (thumb_thickness_scale_factor_ == factor)
sataya.m68d7d9b42014-09-22 16:01:59152 return false;
[email protected]534236b2013-10-25 21:19:20153 thumb_thickness_scale_factor_ = factor;
154 NoteLayerPropertyChanged();
sataya.m68d7d9b42014-09-22 16:01:59155 return true;
[email protected]534236b2013-10-25 21:19:20156}
157
[email protected]80413d72013-08-30 20:25:33158gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const {
159 // Thumb extent is the length of the thumb in the scrolling direction, thumb
160 // thickness is in the perpendicular direction. Here's an example of a
161 // horizontal scrollbar - inputs are above the scrollbar, computed values
162 // below:
163 //
164 // |<------------------- track_length_ ------------------->|
165 //
166 // |--| <-- start_offset
167 //
168 // +--+----------------------------+------------------+-------+--+
169 // |<|| |##################| ||>|
170 // +--+----------------------------+------------------+-------+--+
171 //
172 // |<- thumb_length ->|
173 //
174 // |<------- thumb_offset -------->|
175 //
176 // For painted, scrollbars, the length is fixed. For solid color scrollbars we
177 // have to compute it. The ratio of the thumb's length to the track's length
178 // is the same as that of the visible viewport to the total viewport, unless
179 // that would make the thumb's length less than its thickness.
180 //
181 // vertical_adjust_ is used when the layer geometry from the main thread is
182 // not in sync with what the user sees. For instance on Android scrolling the
183 // top bar controls out of view reveals more of the page content. We want the
184 // root layer scrollbars to reflect what the user sees even if we haven't
185 // received new layer geometry from the main thread. If the user has scrolled
186 // down by 50px and the initial viewport size was 950px the geometry would
187 // look something like this:
188 //
189 // vertical_adjust_ = 50, scroll position 0, visible ratios 99%
190 // Layer geometry: Desired thumb positions:
191 // +--------------------+-+ +----------------------+ <-- 0px
192 // | |v| | #|
193 // | |e| | #|
194 // | |r| | #|
195 // | |t| | #|
196 // | |i| | #|
197 // | |c| | #|
198 // | |a| | #|
199 // | |l| | #|
200 // | | | | #|
201 // | |l| | #|
202 // | |a| | #|
203 // | |y| | #|
204 // | |e| | #|
205 // | |r| | #|
206 // +--------------------+-+ | #|
207 // | horizontal layer | | | #|
208 // +--------------------+-+ | #| <-- 950px
209 // | | | #|
210 // | | |##################### |
211 // +----------------------+ +----------------------+ <-- 1000px
212 //
213 // The layer geometry is set up for a 950px tall viewport, but the user can
214 // actually see down to 1000px. Thus we have to move the quad for the
215 // horizontal scrollbar down by the vertical_adjust_ factor and lay the
216 // vertical thumb out on a track lengthed by the vertical_adjust_ factor. This
217 // means the quads may extend outside the layer's bounds.
218
219 // With the length known, we can compute the thumb's position.
220 float track_length = TrackLength();
221 int thumb_length = ThumbLength();
222 int thumb_thickness = ThumbThickness();
223
224 // With the length known, we can compute the thumb's position.
225 float clamped_current_pos =
226 std::min(std::max(current_pos_, 0.f), static_cast<float>(maximum_));
[email protected]443898f52014-07-22 21:16:18227
228 int thumb_offset = TrackStart();
229 if (maximum_ > 0) {
230 float ratio = clamped_current_pos / maximum_;
231 float max_offset = track_length - thumb_length;
232 thumb_offset += static_cast<int>(ratio * max_offset);
233 }
[email protected]80413d72013-08-30 20:25:33234
[email protected]2ea5aba2013-09-11 14:26:56235 float thumb_thickness_adjustment =
236 thumb_thickness * (1.f - thumb_thickness_scale_factor_);
237
[email protected]80413d72013-08-30 20:25:33238 gfx::RectF thumb_rect;
[email protected]2ea5aba2013-09-11 14:26:56239 if (orientation_ == HORIZONTAL) {
240 thumb_rect = gfx::RectF(thumb_offset,
241 vertical_adjust_ + thumb_thickness_adjustment,
242 thumb_length,
243 thumb_thickness - thumb_thickness_adjustment);
[email protected]80413d72013-08-30 20:25:33244 } else {
[email protected]2ea5aba2013-09-11 14:26:56245 thumb_rect = gfx::RectF(
246 is_left_side_vertical_scrollbar_
247 ? bounds().width() - thumb_thickness
248 : thumb_thickness_adjustment,
249 thumb_offset,
250 thumb_thickness - thumb_thickness_adjustment,
251 thumb_length);
[email protected]80413d72013-08-30 20:25:33252 }
253
254 return ScrollbarLayerRectToContentRect(thumb_rect);
255}
256
sataya.m07f11a82014-10-07 14:29:18257void ScrollbarLayerImplBase::ScrollbarParametersDidChange(bool on_resize) {
[email protected]adeda572014-01-31 00:49:47258 if (!clip_layer_ || !scroll_layer_)
259 return;
260
sataya.m07f11a82014-10-07 14:29:18261 scroll_layer_->SetScrollbarPosition(this, clip_layer_, on_resize);
[email protected]adeda572014-01-31 00:49:47262}
263
[email protected]80413d72013-08-30 20:25:33264} // namespace cc