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