| 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 |