Home | History | Annotate | Download | only in layers
      1 // Copyright 2012 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.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "cc/animation/scrollbar_animation_controller.h"
     10 #include "cc/layers/layer.h"
     11 #include "cc/layers/quad_sink.h"
     12 #include "cc/quads/solid_color_draw_quad.h"
     13 #include "cc/quads/texture_draw_quad.h"
     14 #include "cc/trees/layer_tree_impl.h"
     15 #include "cc/trees/layer_tree_settings.h"
     16 #include "ui/gfx/rect_conversions.h"
     17 
     18 namespace cc {
     19 
     20 scoped_ptr<ScrollbarLayerImpl> ScrollbarLayerImpl::Create(
     21     LayerTreeImpl* tree_impl,
     22     int id,
     23     ScrollbarOrientation orientation) {
     24   return make_scoped_ptr(new ScrollbarLayerImpl(tree_impl,
     25                                                 id,
     26                                                 orientation));
     27 }
     28 
     29 ScrollbarLayerImpl::ScrollbarLayerImpl(
     30     LayerTreeImpl* tree_impl,
     31     int id,
     32     ScrollbarOrientation orientation)
     33     : LayerImpl(tree_impl, id),
     34       track_resource_id_(0),
     35       thumb_resource_id_(0),
     36       current_pos_(0.f),
     37       maximum_(0),
     38       thumb_thickness_(0),
     39       thumb_length_(0),
     40       track_start_(0),
     41       track_length_(0),
     42       orientation_(orientation),
     43       vertical_adjust_(0.f),
     44       visible_to_total_length_ratio_(1.f),
     45       scroll_layer_id_(Layer::INVALID_ID),
     46       is_overlay_scrollbar_(false) {}
     47 
     48 ScrollbarLayerImpl::~ScrollbarLayerImpl() {}
     49 
     50 ScrollbarLayerImpl* ScrollbarLayerImpl::ToScrollbarLayer() {
     51   return this;
     52 }
     53 
     54 scoped_ptr<LayerImpl> ScrollbarLayerImpl::CreateLayerImpl(
     55     LayerTreeImpl* tree_impl) {
     56   return ScrollbarLayerImpl::Create(tree_impl,
     57                                     id(),
     58                                     orientation_).PassAs<LayerImpl>();
     59 }
     60 
     61 void ScrollbarLayerImpl::PushPropertiesTo(LayerImpl* layer) {
     62   LayerImpl::PushPropertiesTo(layer);
     63 
     64   ScrollbarLayerImpl* scrollbar_layer = static_cast<ScrollbarLayerImpl*>(layer);
     65 
     66   scrollbar_layer->SetThumbThickness(thumb_thickness_);
     67   scrollbar_layer->SetThumbLength(thumb_length_);
     68   scrollbar_layer->SetTrackStart(track_start_);
     69   scrollbar_layer->SetTrackLength(track_length_);
     70   scrollbar_layer->set_is_overlay_scrollbar(is_overlay_scrollbar_);
     71 
     72   scrollbar_layer->set_track_resource_id(track_resource_id_);
     73   scrollbar_layer->set_thumb_resource_id(thumb_resource_id_);
     74 }
     75 
     76 bool ScrollbarLayerImpl::WillDraw(DrawMode draw_mode,
     77                                   ResourceProvider* resource_provider) {
     78   if (draw_mode == DRAW_MODE_RESOURCELESS_SOFTWARE &&
     79       !layer_tree_impl()->settings().solid_color_scrollbars)
     80     return false;
     81   return LayerImpl::WillDraw(draw_mode, resource_provider);
     82 }
     83 
     84 void ScrollbarLayerImpl::AppendQuads(QuadSink* quad_sink,
     85                                      AppendQuadsData* append_quads_data) {
     86   bool premultipled_alpha = true;
     87   bool flipped = false;
     88   gfx::PointF uv_top_left(0.f, 0.f);
     89   gfx::PointF uv_bottom_right(1.f, 1.f);
     90   gfx::Rect bounds_rect(bounds());
     91   gfx::Rect content_bounds_rect(content_bounds());
     92 
     93   SharedQuadState* shared_quad_state =
     94       quad_sink->UseSharedQuadState(CreateSharedQuadState());
     95   AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
     96 
     97   gfx::Rect thumb_quad_rect = ComputeThumbQuadRect();
     98 
     99   if (layer_tree_impl()->settings().solid_color_scrollbars) {
    100     scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
    101     quad->SetNew(shared_quad_state,
    102                  thumb_quad_rect,
    103                  layer_tree_impl()->settings().solid_color_scrollbar_color,
    104                  false);
    105     quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    106     return;
    107   }
    108 
    109   if (thumb_resource_id_ && !thumb_quad_rect.IsEmpty()) {
    110     gfx::Rect opaque_rect;
    111     const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
    112     scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
    113     quad->SetNew(shared_quad_state,
    114                  thumb_quad_rect,
    115                  opaque_rect,
    116                  thumb_resource_id_,
    117                  premultipled_alpha,
    118                  uv_top_left,
    119                  uv_bottom_right,
    120                  SK_ColorTRANSPARENT,
    121                  opacity,
    122                  flipped);
    123     quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    124   }
    125 
    126   if (!track_resource_id_)
    127     return;
    128 
    129   // Order matters here: since the back track texture is being drawn to the
    130   // entire contents rect, we must append it after the thumb and fore track
    131   // quads. The back track texture contains (and displays) the buttons.
    132   if (!content_bounds_rect.IsEmpty()) {
    133     gfx::Rect quad_rect(content_bounds_rect);
    134     gfx::Rect opaque_rect(contents_opaque() ? quad_rect : gfx::Rect());
    135     const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
    136     scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create();
    137     quad->SetNew(shared_quad_state,
    138                  quad_rect,
    139                  opaque_rect,
    140                  track_resource_id_,
    141                  premultipled_alpha,
    142                  uv_top_left,
    143                  uv_bottom_right,
    144                  SK_ColorTRANSPARENT,
    145                  opacity,
    146                  flipped);
    147     quad_sink->Append(quad.PassAs<DrawQuad>(), append_quads_data);
    148   }
    149 }
    150 
    151 ScrollbarOrientation ScrollbarLayerImpl::Orientation() const {
    152   return orientation_;
    153 }
    154 
    155 float ScrollbarLayerImpl::CurrentPos() const {
    156   return current_pos_;
    157 }
    158 
    159 int ScrollbarLayerImpl::Maximum() const {
    160   return maximum_;
    161 }
    162 
    163 gfx::Rect ScrollbarLayerImpl::ScrollbarLayerRectToContentRect(
    164     gfx::RectF layer_rect) const {
    165   // Don't intersect with the bounds as in layerRectToContentRect() because
    166   // layer_rect here might be in coordinates of the containing layer.
    167   gfx::RectF content_rect = gfx::ScaleRect(layer_rect,
    168                                            contents_scale_x(),
    169                                            contents_scale_y());
    170   return gfx::ToEnclosingRect(content_rect);
    171 }
    172 
    173 void ScrollbarLayerImpl::SetThumbThickness(int thumb_thickness) {
    174   if (thumb_thickness_ == thumb_thickness)
    175     return;
    176   thumb_thickness_ = thumb_thickness;
    177   NoteLayerPropertyChanged();
    178 }
    179 
    180 void ScrollbarLayerImpl::SetThumbLength(int thumb_length) {
    181   if (thumb_length_ == thumb_length)
    182     return;
    183   thumb_length_ = thumb_length;
    184   NoteLayerPropertyChanged();
    185 }
    186 void ScrollbarLayerImpl::SetTrackStart(int track_start) {
    187   if (track_start_ == track_start)
    188     return;
    189   track_start_ = track_start;
    190   NoteLayerPropertyChanged();
    191 }
    192 
    193 void ScrollbarLayerImpl::SetTrackLength(int track_length) {
    194   if (track_length_ == track_length)
    195     return;
    196   track_length_ = track_length;
    197   NoteLayerPropertyChanged();
    198 }
    199 
    200 void ScrollbarLayerImpl::SetVerticalAdjust(float vertical_adjust) {
    201   if (vertical_adjust_ == vertical_adjust)
    202     return;
    203   vertical_adjust_ = vertical_adjust;
    204   NoteLayerPropertyChanged();
    205 }
    206 
    207 void ScrollbarLayerImpl::SetVisibleToTotalLengthRatio(float ratio) {
    208   if (visible_to_total_length_ratio_ == ratio)
    209     return;
    210   visible_to_total_length_ratio_ = ratio;
    211   NoteLayerPropertyChanged();
    212 }
    213 
    214 void ScrollbarLayerImpl::SetCurrentPos(float current_pos) {
    215   if (current_pos_ == current_pos)
    216     return;
    217   current_pos_ = current_pos;
    218   NoteLayerPropertyChanged();
    219 }
    220 
    221 void ScrollbarLayerImpl::SetMaximum(int maximum) {
    222   if (maximum_ == maximum)
    223     return;
    224   maximum_ = maximum;
    225   NoteLayerPropertyChanged();
    226 }
    227 
    228 gfx::Rect ScrollbarLayerImpl::ComputeThumbQuadRect() const {
    229   // Thumb extent is the length of the thumb in the scrolling direction, thumb
    230   // thickness is in the perpendicular direction. Here's an example of a
    231   // horizontal scrollbar - inputs are above the scrollbar, computed values
    232   // below:
    233   //
    234   //    |<------------------- track_length_ ------------------->|
    235   //
    236   // |--| <-- start_offset
    237   //
    238   // +--+----------------------------+------------------+-------+--+
    239   // |<||                            |##################|       ||>|
    240   // +--+----------------------------+------------------+-------+--+
    241   //
    242   //                                 |<- thumb_length ->|
    243   //
    244   // |<------- thumb_offset -------->|
    245   //
    246   // For painted, scrollbars, the length is fixed. For solid color scrollbars we
    247   // have to compute it. The ratio of the thumb's length to the track's length
    248   // is the same as that of the visible viewport to the total viewport, unless
    249   // that would make the thumb's length less than its thickness.
    250   //
    251   // vertical_adjust_ is used when the layer geometry from the main thread is
    252   // not in sync with what the user sees. For instance on Android scrolling the
    253   // top bar controls out of view reveals more of the page content. We want the
    254   // root layer scrollbars to reflect what the user sees even if we haven't
    255   // received new layer geometry from the main thread.  If the user has scrolled
    256   // down by 50px and the initial viewport size was 950px the geometry would
    257   // look something like this:
    258   //
    259   // vertical_adjust_ = 50, scroll position 0, visible ratios 99%
    260   // Layer geometry:             Desired thumb positions:
    261   // +--------------------+-+   +----------------------+   <-- 0px
    262   // |                    |v|   |                     #|
    263   // |                    |e|   |                     #|
    264   // |                    |r|   |                     #|
    265   // |                    |t|   |                     #|
    266   // |                    |i|   |                     #|
    267   // |                    |c|   |                     #|
    268   // |                    |a|   |                     #|
    269   // |                    |l|   |                     #|
    270   // |                    | |   |                     #|
    271   // |                    |l|   |                     #|
    272   // |                    |a|   |                     #|
    273   // |                    |y|   |                     #|
    274   // |                    |e|   |                     #|
    275   // |                    |r|   |                     #|
    276   // +--------------------+-+   |                     #|
    277   // | horizontal  layer  | |   |                     #|
    278   // +--------------------+-+   |                     #|  <-- 950px
    279   // |                      |   |                     #|
    280   // |                      |   |##################### |
    281   // +----------------------+   +----------------------+  <-- 1000px
    282   //
    283   // The layer geometry is set up for a 950px tall viewport, but the user can
    284   // actually see down to 1000px. Thus we have to move the quad for the
    285   // horizontal scrollbar down by the vertical_adjust_ factor and lay the
    286   // vertical thumb out on a track lengthed by the vertical_adjust_ factor. This
    287   // means the quads may extend outside the layer's bounds.
    288 
    289   int thumb_length = thumb_length_;
    290   float track_length = track_length_;
    291   if (orientation_ == VERTICAL)
    292     track_length += vertical_adjust_;
    293 
    294   if (layer_tree_impl()->settings().solid_color_scrollbars) {
    295     thumb_length = std::max(
    296         static_cast<int>(visible_to_total_length_ratio_ * track_length),
    297         thumb_thickness_);
    298   }
    299 
    300   // With the length known, we can compute the thumb's position.
    301   float clamped_current_pos =
    302       std::min(std::max(current_pos_, 0.f), static_cast<float>(maximum_));
    303   float ratio = clamped_current_pos / maximum_;
    304   float max_offset = track_length - thumb_length;
    305   int thumb_offset = static_cast<int>(ratio * max_offset) + track_start_;
    306 
    307   gfx::RectF thumb_rect;
    308   if (orientation_ == HORIZONTAL) {
    309     thumb_rect = gfx::RectF(thumb_offset, vertical_adjust_,
    310                             thumb_length, thumb_thickness_);
    311   } else {
    312     thumb_rect = gfx::RectF(0.f, thumb_offset,
    313                             thumb_thickness_, thumb_length);
    314   }
    315 
    316   return ScrollbarLayerRectToContentRect(thumb_rect);
    317 }
    318 
    319 void ScrollbarLayerImpl::DidLoseOutputSurface() {
    320   track_resource_id_ = 0;
    321   thumb_resource_id_ = 0;
    322 }
    323 
    324 const char* ScrollbarLayerImpl::LayerTypeAsString() const {
    325   return "cc::ScrollbarLayerImpl";
    326 }
    327 
    328 }  // namespace cc
    329