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