| OLD | NEW |
| (Empty) |
| 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 <algorithm> | |
| 8 | |
| 9 #include "base/auto_reset.h" | |
| 10 #include "base/basictypes.h" | |
| 11 #include "base/trace_event/trace_event.h" | |
| 12 #include "cc/base/math_util.h" | |
| 13 #include "cc/layers/painted_scrollbar_layer_impl.h" | |
| 14 #include "cc/resources/ui_resource_bitmap.h" | |
| 15 #include "cc/trees/layer_tree_host.h" | |
| 16 #include "cc/trees/layer_tree_impl.h" | |
| 17 #include "skia/ext/platform_canvas.h" | |
| 18 #include "skia/ext/refptr.h" | |
| 19 #include "third_party/skia/include/core/SkBitmap.h" | |
| 20 #include "third_party/skia/include/core/SkCanvas.h" | |
| 21 #include "third_party/skia/include/core/SkSize.h" | |
| 22 #include "ui/gfx/geometry/size_conversions.h" | |
| 23 #include "ui/gfx/skia_util.h" | |
| 24 | |
| 25 namespace cc { | |
| 26 | |
| 27 scoped_ptr<LayerImpl> PaintedScrollbarLayer::CreateLayerImpl( | |
| 28 LayerTreeImpl* tree_impl) { | |
| 29 return PaintedScrollbarLayerImpl::Create( | |
| 30 tree_impl, id(), scrollbar_->Orientation()); | |
| 31 } | |
| 32 | |
| 33 scoped_refptr<PaintedScrollbarLayer> PaintedScrollbarLayer::Create( | |
| 34 scoped_ptr<Scrollbar> scrollbar, | |
| 35 int scroll_layer_id) { | |
| 36 return make_scoped_refptr( | |
| 37 new PaintedScrollbarLayer(scrollbar.Pass(), scroll_layer_id)); | |
| 38 } | |
| 39 | |
| 40 PaintedScrollbarLayer::PaintedScrollbarLayer(scoped_ptr<Scrollbar> scrollbar, | |
| 41 int scroll_layer_id) | |
| 42 : scrollbar_(scrollbar.Pass()), | |
| 43 scroll_layer_id_(scroll_layer_id), | |
| 44 clip_layer_id_(Layer::INVALID_ID), | |
| 45 internal_contents_scale_(0.f), | |
| 46 thumb_thickness_(scrollbar_->ThumbThickness()), | |
| 47 thumb_length_(scrollbar_->ThumbLength()), | |
| 48 is_overlay_(scrollbar_->IsOverlay()), | |
| 49 has_thumb_(scrollbar_->HasThumb()) { | |
| 50 if (!scrollbar_->IsOverlay()) | |
| 51 SetShouldScrollOnMainThread(true); | |
| 52 } | |
| 53 | |
| 54 PaintedScrollbarLayer::~PaintedScrollbarLayer() {} | |
| 55 | |
| 56 int PaintedScrollbarLayer::ScrollLayerId() const { | |
| 57 return scroll_layer_id_; | |
| 58 } | |
| 59 | |
| 60 void PaintedScrollbarLayer::SetScrollLayer(int layer_id) { | |
| 61 if (layer_id == scroll_layer_id_) | |
| 62 return; | |
| 63 | |
| 64 scroll_layer_id_ = layer_id; | |
| 65 SetNeedsFullTreeSync(); | |
| 66 } | |
| 67 | |
| 68 void PaintedScrollbarLayer::SetClipLayer(int layer_id) { | |
| 69 if (layer_id == clip_layer_id_) | |
| 70 return; | |
| 71 | |
| 72 clip_layer_id_ = layer_id; | |
| 73 SetNeedsFullTreeSync(); | |
| 74 } | |
| 75 | |
| 76 bool PaintedScrollbarLayer::OpacityCanAnimateOnImplThread() const { | |
| 77 return scrollbar_->IsOverlay(); | |
| 78 } | |
| 79 | |
| 80 ScrollbarOrientation PaintedScrollbarLayer::orientation() const { | |
| 81 return scrollbar_->Orientation(); | |
| 82 } | |
| 83 | |
| 84 int PaintedScrollbarLayer::MaxTextureSize() { | |
| 85 DCHECK(layer_tree_host()); | |
| 86 return layer_tree_host()->GetRendererCapabilities().max_texture_size; | |
| 87 } | |
| 88 | |
| 89 float PaintedScrollbarLayer::ClampScaleToMaxTextureSize(float scale) { | |
| 90 // If the scaled bounds() is bigger than the max texture size of the | |
| 91 // device, we need to clamp it by rescaling, since this is used | |
| 92 // below to set the texture size. | |
| 93 gfx::Size scaled_bounds = gfx::ToCeiledSize(gfx::ScaleSize(bounds(), scale)); | |
| 94 if (scaled_bounds.width() > MaxTextureSize() || | |
| 95 scaled_bounds.height() > MaxTextureSize()) { | |
| 96 if (scaled_bounds.width() > scaled_bounds.height()) | |
| 97 return (MaxTextureSize() - 1) / static_cast<float>(bounds().width()); | |
| 98 else | |
| 99 return (MaxTextureSize() - 1) / static_cast<float>(bounds().height()); | |
| 100 } | |
| 101 return scale; | |
| 102 } | |
| 103 | |
| 104 void PaintedScrollbarLayer::PushPropertiesTo(LayerImpl* layer) { | |
| 105 Layer::PushPropertiesTo(layer); | |
| 106 | |
| 107 PushScrollClipPropertiesTo(layer); | |
| 108 | |
| 109 PaintedScrollbarLayerImpl* scrollbar_layer = | |
| 110 static_cast<PaintedScrollbarLayerImpl*>(layer); | |
| 111 | |
| 112 scrollbar_layer->set_internal_contents_scale_and_bounds( | |
| 113 internal_contents_scale_, internal_content_bounds_); | |
| 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 else | |
| 130 scrollbar_layer->set_track_ui_resource_id(0); | |
| 131 if (thumb_resource_.get()) | |
| 132 scrollbar_layer->set_thumb_ui_resource_id(thumb_resource_->id()); | |
| 133 else | |
| 134 scrollbar_layer->set_thumb_ui_resource_id(0); | |
| 135 | |
| 136 scrollbar_layer->set_is_overlay_scrollbar(is_overlay_); | |
| 137 } | |
| 138 | |
| 139 ScrollbarLayerInterface* PaintedScrollbarLayer::ToScrollbarLayer() { | |
| 140 return this; | |
| 141 } | |
| 142 | |
| 143 void PaintedScrollbarLayer::PushScrollClipPropertiesTo(LayerImpl* layer) { | |
| 144 PaintedScrollbarLayerImpl* scrollbar_layer = | |
| 145 static_cast<PaintedScrollbarLayerImpl*>(layer); | |
| 146 | |
| 147 scrollbar_layer->SetScrollLayerAndClipLayerByIds(scroll_layer_id_, | |
| 148 clip_layer_id_); | |
| 149 } | |
| 150 | |
| 151 void 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_ = nullptr; | |
| 156 thumb_resource_ = nullptr; | |
| 157 } | |
| 158 | |
| 159 Layer::SetLayerTreeHost(host); | |
| 160 } | |
| 161 | |
| 162 gfx::Rect PaintedScrollbarLayer::ScrollbarLayerRectToContentRect( | |
| 163 const 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, internal_contents_scale_, internal_contents_scale_); | |
| 168 // We should never return a rect bigger than the content bounds. | |
| 169 gfx::Size clamped_size = expanded_rect.size(); | |
| 170 clamped_size.SetToMin(internal_content_bounds_); | |
| 171 expanded_rect.set_size(clamped_size); | |
| 172 return expanded_rect; | |
| 173 } | |
| 174 | |
| 175 gfx::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 gfx::Rect(thumb_size); | |
| 185 } | |
| 186 | |
| 187 void PaintedScrollbarLayer::UpdateThumbAndTrackGeometry() { | |
| 188 UpdateProperty(scrollbar_->TrackRect(), &track_rect_); | |
| 189 UpdateProperty(scrollbar_->Location(), &location_); | |
| 190 UpdateProperty(scrollbar_->IsOverlay(), &is_overlay_); | |
| 191 UpdateProperty(scrollbar_->HasThumb(), &has_thumb_); | |
| 192 if (has_thumb_) { | |
| 193 UpdateProperty(scrollbar_->ThumbThickness(), &thumb_thickness_); | |
| 194 UpdateProperty(scrollbar_->ThumbLength(), &thumb_length_); | |
| 195 } else { | |
| 196 UpdateProperty(0, &thumb_thickness_); | |
| 197 UpdateProperty(0, &thumb_length_); | |
| 198 } | |
| 199 } | |
| 200 | |
| 201 void PaintedScrollbarLayer::UpdateInternalContentScale() { | |
| 202 float scale = layer_tree_host()->device_scale_factor(); | |
| 203 if (layer_tree_host() | |
| 204 ->settings() | |
| 205 .layer_transforms_should_scale_layer_contents) { | |
| 206 gfx::Vector2dF transform_scales = | |
| 207 MathUtil::ComputeTransform2dScaleComponents(draw_transform(), scale); | |
| 208 scale = std::max(transform_scales.x(), transform_scales.y()); | |
| 209 } | |
| 210 bool changed = false; | |
| 211 changed |= UpdateProperty(ClampScaleToMaxTextureSize(scale), | |
| 212 &internal_contents_scale_); | |
| 213 changed |= UpdateProperty( | |
| 214 gfx::ToCeiledSize(gfx::ScaleSize(bounds(), internal_contents_scale_)), | |
| 215 &internal_content_bounds_); | |
| 216 if (changed) { | |
| 217 // If the content scale or bounds change, repaint. | |
| 218 SetNeedsDisplay(); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 bool PaintedScrollbarLayer::Update(ResourceUpdateQueue* queue, | |
| 223 const OcclusionTracker<Layer>* occlusion) { | |
| 224 { | |
| 225 base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_, | |
| 226 true); | |
| 227 Layer::Update(queue, occlusion); | |
| 228 UpdateInternalContentScale(); | |
| 229 } | |
| 230 | |
| 231 UpdateThumbAndTrackGeometry(); | |
| 232 | |
| 233 gfx::Rect track_layer_rect = gfx::Rect(location_, bounds()); | |
| 234 gfx::Rect scaled_track_rect = ScrollbarLayerRectToContentRect( | |
| 235 track_layer_rect); | |
| 236 | |
| 237 bool updated = false; | |
| 238 | |
| 239 if (track_rect_.IsEmpty() || scaled_track_rect.IsEmpty()) { | |
| 240 if (track_resource_) { | |
| 241 track_resource_ = nullptr; | |
| 242 thumb_resource_ = nullptr; | |
| 243 SetNeedsPushProperties(); | |
| 244 updated = true; | |
| 245 } | |
| 246 return updated; | |
| 247 } | |
| 248 | |
| 249 if (!has_thumb_ && thumb_resource_) { | |
| 250 thumb_resource_ = nullptr; | |
| 251 SetNeedsPushProperties(); | |
| 252 updated = true; | |
| 253 } | |
| 254 | |
| 255 if (update_rect_.IsEmpty() && track_resource_) | |
| 256 return updated; | |
| 257 | |
| 258 track_resource_ = ScopedUIResource::Create( | |
| 259 layer_tree_host(), | |
| 260 RasterizeScrollbarPart(track_layer_rect, scaled_track_rect, TRACK)); | |
| 261 | |
| 262 gfx::Rect thumb_layer_rect = OriginThumbRect(); | |
| 263 gfx::Rect scaled_thumb_rect = | |
| 264 ScrollbarLayerRectToContentRect(thumb_layer_rect); | |
| 265 if (has_thumb_ && !scaled_thumb_rect.IsEmpty()) { | |
| 266 thumb_resource_ = ScopedUIResource::Create( | |
| 267 layer_tree_host(), | |
| 268 RasterizeScrollbarPart(thumb_layer_rect, scaled_thumb_rect, THUMB)); | |
| 269 } | |
| 270 | |
| 271 // UI resources changed so push properties is needed. | |
| 272 SetNeedsPushProperties(); | |
| 273 updated = true; | |
| 274 return updated; | |
| 275 } | |
| 276 | |
| 277 UIResourceBitmap PaintedScrollbarLayer::RasterizeScrollbarPart( | |
| 278 const gfx::Rect& layer_rect, | |
| 279 const gfx::Rect& content_rect, | |
| 280 ScrollbarPart part) { | |
| 281 DCHECK(!content_rect.size().IsEmpty()); | |
| 282 DCHECK(!layer_rect.size().IsEmpty()); | |
| 283 | |
| 284 SkBitmap skbitmap; | |
| 285 skbitmap.allocN32Pixels(content_rect.width(), content_rect.height()); | |
| 286 SkCanvas skcanvas(skbitmap); | |
| 287 | |
| 288 float scale_x = | |
| 289 content_rect.width() / static_cast<float>(layer_rect.width()); | |
| 290 float scale_y = | |
| 291 content_rect.height() / static_cast<float>(layer_rect.height()); | |
| 292 | |
| 293 skcanvas.scale(SkFloatToScalar(scale_x), | |
| 294 SkFloatToScalar(scale_y)); | |
| 295 skcanvas.translate(SkFloatToScalar(-layer_rect.x()), | |
| 296 SkFloatToScalar(-layer_rect.y())); | |
| 297 | |
| 298 SkRect layer_skrect = RectToSkRect(layer_rect); | |
| 299 SkPaint paint; | |
| 300 paint.setAntiAlias(false); | |
| 301 paint.setXfermodeMode(SkXfermode::kClear_Mode); | |
| 302 skcanvas.drawRect(layer_skrect, paint); | |
| 303 skcanvas.clipRect(layer_skrect); | |
| 304 | |
| 305 scrollbar_->PaintPart(&skcanvas, part, layer_rect); | |
| 306 // Make sure that the pixels are no longer mutable to unavoid unnecessary | |
| 307 // allocation and copying. | |
| 308 skbitmap.setImmutable(); | |
| 309 | |
| 310 return UIResourceBitmap(skbitmap); | |
| 311 } | |
| 312 | |
| 313 } // namespace cc | |
| OLD | NEW |