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/painted_scrollbar_layer.h"
      6 
      7 #include "base/auto_reset.h"
      8 #include "base/basictypes.h"
      9 #include "base/debug/trace_event.h"
     10 #include "cc/layers/painted_scrollbar_layer_impl.h"
     11 #include "cc/resources/ui_resource_bitmap.h"
     12 #include "cc/trees/layer_tree_host.h"
     13 #include "cc/trees/layer_tree_impl.h"
     14 #include "skia/ext/platform_canvas.h"
     15 #include "skia/ext/refptr.h"
     16 #include "third_party/skia/include/core/SkBitmap.h"
     17 #include "third_party/skia/include/core/SkCanvas.h"
     18 #include "third_party/skia/include/core/SkSize.h"
     19 #include "ui/gfx/skia_util.h"
     20 
     21 namespace cc {
     22 
     23 scoped_ptr<LayerImpl> PaintedScrollbarLayer::CreateLayerImpl(
     24     LayerTreeImpl* tree_impl) {
     25   return PaintedScrollbarLayerImpl::Create(
     26       tree_impl, id(), scrollbar_->Orientation()).PassAs<LayerImpl>();
     27 }
     28 
     29 scoped_refptr<PaintedScrollbarLayer> PaintedScrollbarLayer::Create(
     30     scoped_ptr<Scrollbar> scrollbar,
     31     int scroll_layer_id) {
     32   return make_scoped_refptr(
     33       new PaintedScrollbarLayer(scrollbar.Pass(), scroll_layer_id));
     34 }
     35 
     36 PaintedScrollbarLayer::PaintedScrollbarLayer(
     37     scoped_ptr<Scrollbar> scrollbar,
     38     int scroll_layer_id)
     39     : scrollbar_(scrollbar.Pass()),
     40       scroll_layer_id_(scroll_layer_id),
     41       thumb_thickness_(scrollbar_->ThumbThickness()),
     42       thumb_length_(scrollbar_->ThumbLength()),
     43       is_overlay_(scrollbar_->IsOverlay()),
     44       has_thumb_(scrollbar_->HasThumb()) {
     45   if (!scrollbar_->IsOverlay())
     46     SetShouldScrollOnMainThread(true);
     47 }
     48 
     49 PaintedScrollbarLayer::~PaintedScrollbarLayer() {}
     50 
     51 int PaintedScrollbarLayer::ScrollLayerId() const {
     52   return scroll_layer_id_;
     53 }
     54 
     55 void PaintedScrollbarLayer::SetScrollLayerId(int id) {
     56   if (id == scroll_layer_id_)
     57     return;
     58 
     59   scroll_layer_id_ = id;
     60   SetNeedsFullTreeSync();
     61 }
     62 
     63 bool PaintedScrollbarLayer::OpacityCanAnimateOnImplThread() const {
     64   return scrollbar_->IsOverlay();
     65 }
     66 
     67 ScrollbarOrientation PaintedScrollbarLayer::orientation() const {
     68   return scrollbar_->Orientation();
     69 }
     70 
     71 int PaintedScrollbarLayer::MaxTextureSize() {
     72   DCHECK(layer_tree_host());
     73   return layer_tree_host()->GetRendererCapabilities().max_texture_size;
     74 }
     75 
     76 float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) {
     77   // If the scaled content_bounds() is bigger than the max texture size of the
     78   // device, we need to clamp it by rescaling, since content_bounds() is used
     79   // below to set the texture size.
     80   gfx::Size scaled_bounds = ComputeContentBoundsForScale(scale, scale);
     81   if (scaled_bounds.width() > MaxTextureSize() ||
     82       scaled_bounds.height() > MaxTextureSize()) {
     83     if (scaled_bounds.width() > scaled_bounds.height())
     84       return (MaxTextureSize() - 1) / static_cast<float>(bounds().width());
     85     else
     86       return (MaxTextureSize() - 1) / static_cast<float>(bounds().height());
     87   }
     88   return scale;
     89 }
     90 
     91 void PaintedScrollbarLayer::CalculateContentsScale(
     92     float ideal_contents_scale,
     93     float device_scale_factor,
     94     float page_scale_factor,
     95     bool animating_transform_to_screen,
     96     float* contents_scale_x,
     97     float* contents_scale_y,
     98     gfx::Size* content_bounds) {
     99   ContentsScalingLayer::CalculateContentsScale(
    100       ClampScaleToMaxTextureSize(ideal_contents_scale),
    101       device_scale_factor,
    102       page_scale_factor,
    103       animating_transform_to_screen,
    104       contents_scale_x,
    105       contents_scale_y,
    106       content_bounds);
    107 }
    108 
    109 void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
    110   ContentsScalingLayer::PushPropertiesTo(layer);
    111 
    112   PaintedScrollbarLayerImpl* scrollbar_layer =
    113       static_cast<PaintedScrollbarLayerImpl*>(layer);
    114 
    115   scrollbar_layer->SetThumbThickness(thumb_thickness_);
    116   scrollbar_layer->SetThumbLength(thumb_length_);
    117   if (orientation() == HORIZONTAL) {
    118     scrollbar_layer->SetTrackStart(
    119         track_rect_.x() - location_.x());
    120     scrollbar_layer->SetTrackLength(track_rect_.width());
    121   } else {
    122     scrollbar_layer->SetTrackStart(
    123         track_rect_.y() - location_.y());
    124     scrollbar_layer->SetTrackLength(track_rect_.height());
    125   }
    126 
    127   if (track_resource_.get())
    128     scrollbar_layer->set_track_ui_resource_id(track_resource_->id());
    129   if (thumb_resource_.get())
    130     scrollbar_layer->set_thumb_ui_resource_id(thumb_resource_->id());
    131 
    132   scrollbar_layer->set_is_overlay_scrollbar(is_overlay_);
    133 }
    134 
    135 ScrollbarLayerInterface* PaintedScrollbarLayer::ToScrollbarLayer() {
    136   return this;
    137 }
    138 
    139 void PaintedScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
    140   // When the LTH is set to null or has changed, then this layer should remove
    141   // all of its associated resources.
    142   if (!host || host != layer_tree_host()) {
    143     track_resource_.reset();
    144     thumb_resource_.reset();
    145   }
    146 
    147   ContentsScalingLayer::SetLayerTreeHost(host);
    148 }
    149 
    150 gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect(
    151     gfx::Rect layer_rect) const {
    152   // Don't intersect with the bounds as in LayerRectToContentRect() because
    153   // layer_rect here might be in coordinates of the containing layer.
    154   gfx::Rect expanded_rect = gfx::ScaleToEnclosingRect(
    155       layer_rect, contents_scale_y(), contents_scale_y());
    156   // We should never return a rect bigger than the content_bounds().
    157   gfx::Size clamped_size = expanded_rect.size();
    158   clamped_size.SetToMin(content_bounds());
    159   expanded_rect.set_size(clamped_size);
    160   return expanded_rect;
    161 }
    162 
    163 gfx::Rect PaintedScrollbarLayer::OriginThumbRect() const {
    164   gfx::Size thumb_size;
    165   if (orientation() == HORIZONTAL) {
    166     thumb_size =
    167         gfx::Size(scrollbar_->ThumbLength(), scrollbar_->ThumbThickness());
    168   } else {
    169     thumb_size =
    170         gfx::Size(scrollbar_->ThumbThickness(), scrollbar_->ThumbLength());
    171   }
    172   return ScrollbarLayerRectToContentRect(gfx::Rect(thumb_size));
    173 }
    174 
    175 void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() {
    176   UpdateProperty(scrollbar_->TrackRect(), &track_rect_);
    177   UpdateProperty(scrollbar_->Location(), &location_);
    178   UpdateProperty(scrollbar_->IsOverlay(), &is_overlay_);
    179   UpdateProperty(scrollbar_->HasThumb(), &has_thumb_);
    180   if (has_thumb_) {
    181     UpdateProperty(scrollbar_->ThumbThickness(), &thumb_thickness_);
    182     UpdateProperty(scrollbar_->ThumbLength(), &thumb_length_);
    183   }
    184 }
    185 
    186 bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue,
    187                                    const OcclusionTracker* occlusion) {
    188   UpdateThumbAndTrackGeometry();
    189 
    190   gfx::Rect scaled_track_rect = ScrollbarLayerRectToContentRect(
    191       gfx::Rect(location_, bounds()));
    192 
    193   if (track_rect_.IsEmpty() || scaled_track_rect.IsEmpty())
    194     return false;
    195 
    196   {
    197     base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
    198                                                   true);
    199     ContentsScalingLayer::Update(queue, occlusion);
    200   }
    201 
    202   if (update_rect_.IsEmpty() && track_resource_)
    203     return false;
    204 
    205   track_resource_ = ScopedUIResource::Create(
    206       layer_tree_host(), RasterizeScrollbarPart(scaled_track_rect, TRACK));
    207 
    208   gfx::Rect thumb_rect = OriginThumbRect();
    209   if (has_thumb_ && !thumb_rect.IsEmpty()) {
    210     thumb_resource_ = ScopedUIResource::Create(
    211         layer_tree_host(), RasterizeScrollbarPart(thumb_rect, THUMB));
    212   }
    213 
    214   // UI resources changed so push properties is needed.
    215   SetNeedsPushProperties();
    216   return true;
    217 }
    218 
    219 UIResourceBitmap PaintedScrollbarLayer::RasterizeScrollbarPart(
    220     gfx::Rect rect,
    221     ScrollbarPart part) {
    222   DCHECK(!rect.size().IsEmpty());
    223 
    224   SkBitmap skbitmap;
    225   skbitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height());
    226   skbitmap.allocPixels();
    227 
    228   SkCanvas skcanvas(skbitmap);
    229   skcanvas.translate(SkFloatToScalar(-rect.x()), SkFloatToScalar(-rect.y()));
    230   skcanvas.scale(SkFloatToScalar(contents_scale_x()),
    231                  SkFloatToScalar(contents_scale_y()));
    232 
    233   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
    234       rect, 1.f / contents_scale_x(), 1.f / contents_scale_y());
    235   SkRect layer_skrect = RectToSkRect(layer_rect);
    236   SkPaint paint;
    237   paint.setAntiAlias(false);
    238   paint.setXfermodeMode(SkXfermode::kClear_Mode);
    239   skcanvas.drawRect(layer_skrect, paint);
    240   skcanvas.clipRect(layer_skrect);
    241 
    242   scrollbar_->PaintPart(&skcanvas, part, layer_rect);
    243   // Make sure that the pixels are no longer mutable to unavoid unnecessary
    244   // allocation and copying.
    245   skbitmap.setImmutable();
    246 
    247   return UIResourceBitmap(skbitmap);
    248 }
    249 
    250 }  // namespace cc
    251