Home | History | Annotate | Download | only in layers
      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/layers/layer.h"
      9 #include "ui/gfx/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     : LayerImpl(tree_impl, id),
     19       scroll_layer_id_(Layer::INVALID_ID),
     20       is_overlay_scrollbar_(false),
     21       thumb_thickness_scale_factor_(1.f),
     22       current_pos_(0.f),
     23       maximum_(0),
     24       orientation_(orientation),
     25       is_left_side_vertical_scrollbar_(is_left_side_vertical_scrollbar),
     26       vertical_adjust_(0.f),
     27       visible_to_total_length_ratio_(1.f) {}
     28 
     29 void ScrollbarLayerImplBase::PushPropertiesTo(LayerImpl* layer) {
     30   LayerImpl::PushPropertiesTo(layer);
     31 }
     32 
     33 ScrollbarLayerImplBase* ScrollbarLayerImplBase::ToScrollbarLayer() {
     34   return this;
     35 }
     36 
     37 gfx::Rect ScrollbarLayerImplBase::ScrollbarLayerRectToContentRect(
     38     gfx::RectF layer_rect) const {
     39   // Don't intersect with the bounds as in LayerRectToContentRect() because
     40   // layer_rect here might be in coordinates of the containing layer.
     41   gfx::RectF content_rect = gfx::ScaleRect(layer_rect,
     42       contents_scale_x(),
     43       contents_scale_y());
     44   return gfx::ToEnclosingRect(content_rect);
     45 }
     46 
     47 void ScrollbarLayerImplBase::SetCurrentPos(float current_pos) {
     48   if (current_pos_ == current_pos)
     49     return;
     50   current_pos_ = current_pos;
     51   NoteLayerPropertyChanged();
     52 }
     53 
     54 void ScrollbarLayerImplBase::SetMaximum(int maximum) {
     55   if (maximum_ == maximum)
     56     return;
     57   maximum_ = maximum;
     58   NoteLayerPropertyChanged();
     59 }
     60 
     61 void ScrollbarLayerImplBase::SetVerticalAdjust(float vertical_adjust) {
     62   if (vertical_adjust_ == vertical_adjust)
     63     return;
     64   vertical_adjust_ = vertical_adjust;
     65   NoteLayerPropertyChanged();
     66 }
     67 
     68 void ScrollbarLayerImplBase::SetVisibleToTotalLengthRatio(float ratio) {
     69   if (visible_to_total_length_ratio_ == ratio)
     70     return;
     71   visible_to_total_length_ratio_ = ratio;
     72   NoteLayerPropertyChanged();
     73 }
     74 
     75 void ScrollbarLayerImplBase::SetThumbThicknessScaleFactor(float factor) {
     76   if (thumb_thickness_scale_factor_ == factor)
     77     return;
     78   thumb_thickness_scale_factor_ = factor;
     79   NoteLayerPropertyChanged();
     80 }
     81 
     82 gfx::Rect ScrollbarLayerImplBase::ComputeThumbQuadRect() const {
     83   // Thumb extent is the length of the thumb in the scrolling direction, thumb
     84   // thickness is in the perpendicular direction. Here's an example of a
     85   // horizontal scrollbar - inputs are above the scrollbar, computed values
     86   // below:
     87   //
     88   //    |<------------------- track_length_ ------------------->|
     89   //
     90   // |--| <-- start_offset
     91   //
     92   // +--+----------------------------+------------------+-------+--+
     93   // |<||                            |##################|       ||>|
     94   // +--+----------------------------+------------------+-------+--+
     95   //
     96   //                                 |<- thumb_length ->|
     97   //
     98   // |<------- thumb_offset -------->|
     99   //
    100   // For painted, scrollbars, the length is fixed. For solid color scrollbars we
    101   // have to compute it. The ratio of the thumb's length to the track's length
    102   // is the same as that of the visible viewport to the total viewport, unless
    103   // that would make the thumb's length less than its thickness.
    104   //
    105   // vertical_adjust_ is used when the layer geometry from the main thread is
    106   // not in sync with what the user sees. For instance on Android scrolling the
    107   // top bar controls out of view reveals more of the page content. We want the
    108   // root layer scrollbars to reflect what the user sees even if we haven't
    109   // received new layer geometry from the main thread.  If the user has scrolled
    110   // down by 50px and the initial viewport size was 950px the geometry would
    111   // look something like this:
    112   //
    113   // vertical_adjust_ = 50, scroll position 0, visible ratios 99%
    114   // Layer geometry:             Desired thumb positions:
    115   // +--------------------+-+   +----------------------+   <-- 0px
    116   // |                    |v|   |                     #|
    117   // |                    |e|   |                     #|
    118   // |                    |r|   |                     #|
    119   // |                    |t|   |                     #|
    120   // |                    |i|   |                     #|
    121   // |                    |c|   |                     #|
    122   // |                    |a|   |                     #|
    123   // |                    |l|   |                     #|
    124   // |                    | |   |                     #|
    125   // |                    |l|   |                     #|
    126   // |                    |a|   |                     #|
    127   // |                    |y|   |                     #|
    128   // |                    |e|   |                     #|
    129   // |                    |r|   |                     #|
    130   // +--------------------+-+   |                     #|
    131   // | horizontal  layer  | |   |                     #|
    132   // +--------------------+-+   |                     #|  <-- 950px
    133   // |                      |   |                     #|
    134   // |                      |   |##################### |
    135   // +----------------------+   +----------------------+  <-- 1000px
    136   //
    137   // The layer geometry is set up for a 950px tall viewport, but the user can
    138   // actually see down to 1000px. Thus we have to move the quad for the
    139   // horizontal scrollbar down by the vertical_adjust_ factor and lay the
    140   // vertical thumb out on a track lengthed by the vertical_adjust_ factor. This
    141   // means the quads may extend outside the layer's bounds.
    142 
    143   // With the length known, we can compute the thumb's position.
    144   float track_length = TrackLength();
    145   int thumb_length = ThumbLength();
    146   int thumb_thickness = ThumbThickness();
    147 
    148   // With the length known, we can compute the thumb's position.
    149   float clamped_current_pos =
    150       std::min(std::max(current_pos_, 0.f), static_cast<float>(maximum_));
    151   float ratio = clamped_current_pos / maximum_;
    152   float max_offset = track_length - thumb_length;
    153   int thumb_offset = static_cast<int>(ratio * max_offset) + TrackStart();
    154 
    155   float thumb_thickness_adjustment =
    156       thumb_thickness * (1.f - thumb_thickness_scale_factor_);
    157 
    158   gfx::RectF thumb_rect;
    159   if (orientation_ == HORIZONTAL) {
    160     thumb_rect = gfx::RectF(thumb_offset,
    161                             vertical_adjust_ + thumb_thickness_adjustment,
    162                             thumb_length,
    163                             thumb_thickness - thumb_thickness_adjustment);
    164   } else {
    165     thumb_rect = gfx::RectF(
    166         is_left_side_vertical_scrollbar_
    167             ? bounds().width() - thumb_thickness
    168             : thumb_thickness_adjustment,
    169         thumb_offset,
    170         thumb_thickness - thumb_thickness_adjustment,
    171         thumb_length);
    172   }
    173 
    174   return ScrollbarLayerRectToContentRect(thumb_rect);
    175 }
    176 
    177 }  // namespace cc
    178