OLD | NEW |
| (Empty) |
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/scrollbar_layer_impl_base.h" | |
6 | |
7 #include <algorithm> | |
8 #include "cc/trees/layer_tree_impl.h" | |
9 #include "ui/gfx/geometry/rect_conversions.h" | |
10 | |
11 namespace cc { | |
12 | |
13 ScrollbarLayerImplBase::ScrollbarLayerImplBase( | |
14 LayerTreeImpl* tree_impl, | |
15 int id, | |
16 ScrollbarOrientation orientation, | |
17 bool is_left_side_vertical_scrollbar, | |
18 bool is_overlay) | |
19 : LayerImpl(tree_impl, id), | |
20 scroll_layer_(nullptr), | |
21 clip_layer_(nullptr), | |
22 is_overlay_scrollbar_(is_overlay), | |
23 thumb_thickness_scale_factor_(1.f), | |
24 current_pos_(0.f), | |
25 maximum_(0), | |
26 orientation_(orientation), | |
27 is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar), | |
28 vertical_adjust_(0.f), | |
29 visible_to_total_length_ratio_(1.f) { | |
30 } | |
31 | |
32 ScrollbarLayerImplBase::~ScrollbarLayerImplBase() {} | |
33 | |
34 void ScrollbarLayerImplBase::PushPropertiesTo(LayerImpl* layer) { | |
35 float active_opacity = layer->opacity(); | |
36 bool active_hidden = layer->hide_layer_and_subtree(); | |
37 LayerImpl::PushPropertiesTo(layer); | |
38 layer->SetOpacity(active_opacity); | |
39 layer->SetHideLayerAndSubtree(active_hidden); | |
40 DCHECK(layer->ToScrollbarLayer()); | |
41 layer->ToScrollbarLayer()->set_is_overlay_scrollbar(is_overlay_scrollbar_); | |
42 PushScrollClipPropertiesTo(layer); | |
43 } | |
44 | |
45 void ScrollbarLayerImplBase::PushScrollClipPropertiesTo(LayerImpl* layer) { | |
46 DCHECK(layer->ToScrollbarLayer()); | |
47 layer->ToScrollbarLayer()->SetScrollLayerAndClipLayerByIds(ScrollLayerId(), | |
48 ClipLayerId()); | |
49 } | |
50 | |
51 ScrollbarLayerImplBase* ScrollbarLayerImplBase::ToScrollbarLayer() { | |
52 return this; | |
53 } | |
54 | |
55 namespace { | |
56 | |
57 typedef void (LayerImpl::*ScrollbarRegistrationOperation)( | |
58 ScrollbarLayerImplBase*); | |
59 | |
60 void RegisterScrollbarWithLayers(ScrollbarLayerImplBase* scrollbar, | |
61 LayerImpl* container_layer, | |
62 LayerImpl* scroll_layer, | |
63 ScrollbarRegistrationOperation operation) { | |
64 if (!container_layer || !scroll_layer) | |
65 return; | |
66 | |
67 DCHECK(scrollbar); | |
68 | |
69 // Scrollbars must be notifed of changes to their scroll and container layers | |
70 // and all scrollable layers in between. | |
71 for (LayerImpl* current_layer = scroll_layer; | |
72 current_layer && current_layer != container_layer->parent(); | |
73 current_layer = current_layer->parent()) { | |
74 (current_layer->*operation)(scrollbar); | |
75 } | |
76 } | |
77 } // namespace | |
78 | |
79 void ScrollbarLayerImplBase::SetScrollLayerAndClipLayerByIds( | |
80 int scroll_layer_id, | |
81 int clip_layer_id) { | |
82 LayerImpl* scroll_layer = layer_tree_impl()->LayerById(scroll_layer_id); | |
83 LayerImpl* clip_layer = layer_tree_impl()->LayerById(clip_layer_id); | |
84 if (scroll_layer_ == scroll_layer && clip_layer_ == clip_layer) | |
85 return; | |
86 | |
87 RegisterScrollbarWithLayers( | |
88 this, clip_layer_, scroll_layer_, &LayerImpl::RemoveScrollbar); | |
89 scroll_layer_ = scroll_layer; | |
90 clip_layer_ = clip_layer; | |
91 RegisterScrollbarWithLayers( | |
92 this, clip_layer_, scroll_layer_, &LayerImpl::AddScrollbar); | |
93 | |
94 ScrollbarParametersDidChange(false); | |
95 } | |
96 | |
97 gfx::Rect ScrollbarLayerImplBase::ScrollbarLayerRectToContentRect( | |
98 const gfx::RectF& layer_rect) const { | |
99 // Don't intersect with the bounds as in LayerRectToContentRect() because | |
100 // layer_rect here might be in coordinates of the containing layer. | |
101 gfx::RectF content_rect = gfx::ScaleRect(layer_rect, | |
102 contents_scale_x(), | |
103 contents_scale_y()); | |
104 return gfx::ToEnclosingRect(content_rect); | |
105 } | |
106 | |
107 bool ScrollbarLayerImplBase::SetCurrentPos(float current_pos) { | |
108 if (current_pos_ == current_pos) | |
109 return false; | |
110 current_pos_ = current_pos; | |
111 NoteLayerPropertyChanged(); | |
112 return true; | |
113 } | |
114 | |
115 bool ScrollbarLayerImplBase::SetMaximum(int maximum) { | |
116 if (maximum_ == maximum) | |
117 return false; | |
118 maximum_ = maximum; | |
119 NoteLayerPropertyChanged(); | |
120 return true; | |
121 } | |
122 | |
123 bool ScrollbarLayerImplBase::CanScrollOrientation() const { | |
124 if (!scroll_layer_) | |
125 return false; | |
126 return scroll_layer_->user_scrollable(orientation()) && (0 < maximum()); | |
127 } | |
128 | |
129 bool ScrollbarLayerImplBase::SetVerticalAdjust(float vertical_adjust) { | |
130 if (vertical_adjust_ == vertical_adjust) | |
131 return false; | |
132 vertical_adjust_ = vertical_adjust; | |
133 NoteLayerPropertyChanged(); | |
134 return true; | |
135 } | |
136 | |
137 bool ScrollbarLayerImplBase::SetVisibleToTotalLengthRatio(float ratio) { | |
138 if (!IsThumbResizable()) | |
139 return false; | |
140 | |
141 if (visible_to_total_length_ratio_ == ratio) | |
142 return false; | |
143 visible_to_total_length_ratio_ = ratio; | |
144 NoteLayerPropertyChanged(); | |
145 return true; | |
146 } | |
147 | |
148 bool ScrollbarLayerImplBase::SetThumbThicknessScaleFactor(float factor) { | |
149 if (thumb_thickness_scale_factor_ == factor) | |
150 return false; | |
151 thumb_thickness_scale_factor_ = factor; | |
152 NoteLayerPropertyChanged(); | |
153 return true; | |
154 } | |
155 | |
156 gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const { | |
157 // Thumb extent is the length of the thumb in the scrolling direction, thumb | |
158 // thickness is in the perpendicular direction. Here's an example of a | |
159 // horizontal scrollbar - inputs are above the scrollbar, computed values | |
160 // below: | |
161 // | |
162 // |<------------------- track_length_ ------------------->| | |
163 // | |
164 // |--| <-- start_offset | |
165 // | |
166 // +--+----------------------------+------------------+-------+--+ | |
167 // |<|| |##################| ||>| | |
168 // +--+----------------------------+------------------+-------+--+ | |
169 // | |
170 // |<- thumb_length ->| | |
171 // | |
172 // |<------- thumb_offset -------->| | |
173 // | |
174 // For painted, scrollbars, the length is fixed. For solid color scrollbars we | |
175 // have to compute it. The ratio of the thumb's length to the track's length | |
176 // is the same as that of the visible viewport to the total viewport, unless | |
177 // that would make the thumb's length less than its thickness. | |
178 // | |
179 // vertical_adjust_ is used when the layer geometry from the main thread is | |
180 // not in sync with what the user sees. For instance on Android scrolling the | |
181 // top bar controls out of view reveals more of the page content. We want the | |
182 // root layer scrollbars to reflect what the user sees even if we haven't | |
183 // received new layer geometry from the main thread. If the user has scrolled | |
184 // down by 50px and the initial viewport size was 950px the geometry would | |
185 // look something like this: | |
186 // | |
187 // vertical_adjust_ = 50, scroll position 0, visible ratios 99% | |
188 // Layer geometry: Desired thumb positions: | |
189 // +--------------------+-+ +----------------------+ <-- 0px | |
190 // | |v| | #| | |
191 // | |e| | #| | |
192 // | |r| | #| | |
193 // | |t| | #| | |
194 // | |i| | #| | |
195 // | |c| | #| | |
196 // | |a| | #| | |
197 // | |l| | #| | |
198 // | | | | #| | |
199 // | |l| | #| | |
200 // | |a| | #| | |
201 // | |y| | #| | |
202 // | |e| | #| | |
203 // | |r| | #| | |
204 // +--------------------+-+ | #| | |
205 // | horizontal layer | | | #| | |
206 // +--------------------+-+ | #| <-- 950px | |
207 // | | | #| | |
208 // | | |##################### | | |
209 // +----------------------+ +----------------------+ <-- 1000px | |
210 // | |
211 // The layer geometry is set up for a 950px tall viewport, but the user can | |
212 // actually see down to 1000px. Thus we have to move the quad for the | |
213 // horizontal scrollbar down by the vertical_adjust_ factor and lay the | |
214 // vertical thumb out on a track lengthed by the vertical_adjust_ factor. This | |
215 // means the quads may extend outside the layer's bounds. | |
216 | |
217 // With the length known, we can compute the thumb's position. | |
218 float track_length = TrackLength(); | |
219 int thumb_length = ThumbLength(); | |
220 int thumb_thickness = ThumbThickness(); | |
221 | |
222 // With the length known, we can compute the thumb's position. | |
223 float clamped_current_pos = | |
224 std::min(std::max(current_pos_, 0.f), static_cast<float>(maximum_)); | |
225 | |
226 int thumb_offset = TrackStart(); | |
227 if (maximum_ > 0) { | |
228 float ratio = clamped_current_pos / maximum_; | |
229 float max_offset = track_length - thumb_length; | |
230 thumb_offset += static_cast<int>(ratio * max_offset); | |
231 } | |
232 | |
233 float thumb_thickness_adjustment = | |
234 thumb_thickness * (1.f - thumb_thickness_scale_factor_); | |
235 | |
236 gfx::RectF thumb_rect; | |
237 if (orientation_ == HORIZONTAL) { | |
238 thumb_rect = gfx::RectF(thumb_offset, | |
239 vertical_adjust_ + thumb_thickness_adjustment, | |
240 thumb_length, | |
241 thumb_thickness - thumb_thickness_adjustment); | |
242 } else { | |
243 thumb_rect = gfx::RectF( | |
244 is_left_side_vertical_scrollbar_ | |
245 ? bounds().width() - thumb_thickness | |
246 : thumb_thickness_adjustment, | |
247 thumb_offset, | |
248 thumb_thickness - thumb_thickness_adjustment, | |
249 thumb_length); | |
250 } | |
251 | |
252 return ScrollbarLayerRectToContentRect(thumb_rect); | |
253 } | |
254 | |
255 void ScrollbarLayerImplBase::ScrollbarParametersDidChange(bool on_resize) { | |
256 if (!clip_layer_ || !scroll_layer_) | |
257 return; | |
258 | |
259 scroll_layer_->SetScrollbarPosition(this, clip_layer_, on_resize); | |
260 } | |
261 | |
262 } // namespace cc | |
OLD | NEW |