2 // Copyright 2012 The Chromium Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
6 #include "cc/layers/scrollbar_layer.h"
8 #include "base/auto_reset.h"
9 #include "base/basictypes.h"
10 #include "base/debug/trace_event.h"
11 #include "cc/layers/scrollbar_layer_impl.h"
12 #include "cc/resources/caching_bitmap_content_layer_updater.h"
13 #include "cc/resources/layer_painter.h"
14 #include "cc/resources/prioritized_resource.h"
15 #include "cc/resources/resource_update_queue.h"
16 #include "cc/trees/layer_tree_host.h"
17 #include "third_party/WebKit/Source/Platform/chromium/public/WebRect.h"
18 #include "ui/gfx/rect_conversions.h"
22 scoped_ptr
<LayerImpl
> ScrollbarLayer::CreateLayerImpl(
23 LayerTreeImpl
* tree_impl
) {
24 return ScrollbarLayerImpl::Create(
27 ScrollbarGeometryFixedThumb::Create(make_scoped_ptr(geometry_
->clone())))
31 scoped_refptr
<ScrollbarLayer
> ScrollbarLayer::Create(
32 scoped_ptr
<WebKit::WebScrollbar
> scrollbar
,
33 scoped_ptr
<ScrollbarThemePainter
> painter
,
34 scoped_ptr
<WebKit::WebScrollbarThemeGeometry
> geometry
,
35 int scroll_layer_id
) {
36 return make_scoped_refptr(new ScrollbarLayer(scrollbar
.Pass(),
42 ScrollbarLayer::ScrollbarLayer(
43 scoped_ptr
<WebKit::WebScrollbar
> scrollbar
,
44 scoped_ptr
<ScrollbarThemePainter
> painter
,
45 scoped_ptr
<WebKit::WebScrollbarThemeGeometry
> geometry
,
47 : scrollbar_(scrollbar
.Pass()),
48 painter_(painter
.Pass()),
49 geometry_(geometry
.Pass()),
50 scroll_layer_id_(scroll_layer_id
),
51 texture_format_(GL_INVALID_ENUM
) {
52 if (!scrollbar_
->isOverlay())
53 SetShouldScrollOnMainThread(true);
56 ScrollbarLayer::~ScrollbarLayer() {}
58 void ScrollbarLayer::SetScrollLayerId(int id
) {
59 if (id
== scroll_layer_id_
)
62 scroll_layer_id_
= id
;
63 SetNeedsFullTreeSync();
66 bool ScrollbarLayer::OpacityCanAnimateOnImplThread() const {
67 return scrollbar_
->isOverlay();
70 WebKit::WebScrollbar::Orientation
ScrollbarLayer::Orientation() const {
71 return scrollbar_
->orientation();
74 int ScrollbarLayer::MaxTextureSize() {
75 DCHECK(layer_tree_host());
76 return layer_tree_host()->GetRendererCapabilities().max_texture_size
;
79 float ScrollbarLayer::ClampScaleToMaxTextureSize(float scale
) {
80 if (layer_tree_host()->settings().solid_color_scrollbars
)
83 // If the scaled content_bounds() is bigger than the max texture size of the
84 // device, we need to clamp it by rescaling, since content_bounds() is used
85 // below to set the texture size.
86 gfx::Size scaled_bounds
= ComputeContentBoundsForScale(scale
, scale
);
87 if (scaled_bounds
.width() > MaxTextureSize() ||
88 scaled_bounds
.height() > MaxTextureSize()) {
89 if (scaled_bounds
.width() > scaled_bounds
.height())
90 return (MaxTextureSize() - 1) / static_cast<float>(bounds().width());
92 return (MaxTextureSize() - 1) / static_cast<float>(bounds().height());
97 void ScrollbarLayer::CalculateContentsScale(float ideal_contents_scale
,
98 float device_scale_factor
,
99 float page_scale_factor
,
100 bool animating_transform_to_screen
,
101 float* contents_scale_x
,
102 float* contents_scale_y
,
103 gfx::Size
* content_bounds
) {
104 ContentsScalingLayer::CalculateContentsScale(
105 ClampScaleToMaxTextureSize(ideal_contents_scale
),
108 animating_transform_to_screen
,
114 void ScrollbarLayer::PushPropertiesTo(LayerImpl
* layer
) {
115 ContentsScalingLayer::PushPropertiesTo(layer
);
117 ScrollbarLayerImpl
* scrollbar_layer
= static_cast<ScrollbarLayerImpl
*>(layer
);
119 scrollbar_layer
->SetScrollbarData(scrollbar_
.get());
120 scrollbar_layer
->SetThumbSize(thumb_size_
);
122 if (back_track_
&& back_track_
->texture()->have_backing_texture()) {
123 scrollbar_layer
->set_back_track_resource_id(
124 back_track_
->texture()->resource_id());
126 scrollbar_layer
->set_back_track_resource_id(0);
129 if (fore_track_
&& fore_track_
->texture()->have_backing_texture()) {
130 scrollbar_layer
->set_fore_track_resource_id(
131 fore_track_
->texture()->resource_id());
133 scrollbar_layer
->set_fore_track_resource_id(0);
136 if (thumb_
&& thumb_
->texture()->have_backing_texture())
137 scrollbar_layer
->set_thumb_resource_id(thumb_
->texture()->resource_id());
139 scrollbar_layer
->set_thumb_resource_id(0);
142 ScrollbarLayer
* ScrollbarLayer::ToScrollbarLayer() {
146 class ScrollbarBackgroundPainter
: public LayerPainter
{
148 static scoped_ptr
<ScrollbarBackgroundPainter
> Create(
149 WebKit::WebScrollbar
* scrollbar
,
150 ScrollbarThemePainter
*painter
,
151 WebKit::WebScrollbarThemeGeometry
* geometry
,
152 WebKit::WebScrollbar::ScrollbarPart trackPart
) {
153 return make_scoped_ptr(new ScrollbarBackgroundPainter(scrollbar
,
159 virtual void Paint(SkCanvas
* canvas
,
160 gfx::Rect content_rect
,
161 gfx::RectF
* opaque
) OVERRIDE
{
162 // The following is a simplification of ScrollbarThemeComposite::paint.
163 painter_
->PaintScrollbarBackground(canvas
, content_rect
);
165 if (geometry_
->hasButtons(scrollbar_
)) {
166 gfx::Rect back_button_start_paint_rect
=
167 geometry_
->backButtonStartRect(scrollbar_
);
168 painter_
->PaintBackButtonStart(canvas
, back_button_start_paint_rect
);
170 gfx::Rect back_button_end_paint_rect
=
171 geometry_
->backButtonEndRect(scrollbar_
);
172 painter_
->PaintBackButtonEnd(canvas
, back_button_end_paint_rect
);
174 gfx::Rect forward_button_start_paint_rect
=
175 geometry_
->forwardButtonStartRect(scrollbar_
);
176 painter_
->PaintForwardButtonStart(canvas
,
177 forward_button_start_paint_rect
);
179 gfx::Rect forward_button_end_paint_rect
=
180 geometry_
->forwardButtonEndRect(scrollbar_
);
181 painter_
->PaintForwardButtonEnd(canvas
, forward_button_end_paint_rect
);
184 gfx::Rect track_paint_rect
= geometry_
->trackRect(scrollbar_
);
185 painter_
->PaintTrackBackground(canvas
, track_paint_rect
);
187 bool thumb_present
= geometry_
->hasThumb(scrollbar_
);
189 if (track_part_
== WebKit::WebScrollbar::ForwardTrackPart
)
190 painter_
->PaintForwardTrackPart(canvas
, track_paint_rect
);
192 painter_
->PaintBackTrackPart(canvas
, track_paint_rect
);
195 painter_
->PaintTickmarks(canvas
, track_paint_rect
);
199 ScrollbarBackgroundPainter(WebKit::WebScrollbar
* scrollbar
,
200 ScrollbarThemePainter
*painter
,
201 WebKit::WebScrollbarThemeGeometry
* geometry
,
202 WebKit::WebScrollbar::ScrollbarPart trackPart
)
203 : scrollbar_(scrollbar
),
206 track_part_(trackPart
) {}
208 WebKit::WebScrollbar
* scrollbar_
;
209 ScrollbarThemePainter
* painter_
;
210 WebKit::WebScrollbarThemeGeometry
* geometry_
;
211 WebKit::WebScrollbar::ScrollbarPart track_part_
;
213 DISALLOW_COPY_AND_ASSIGN(ScrollbarBackgroundPainter
);
216 class ScrollbarThumbPainter
: public LayerPainter
{
218 static scoped_ptr
<ScrollbarThumbPainter
> Create(
219 WebKit::WebScrollbar
* scrollbar
,
220 ScrollbarThemePainter
* painter
,
221 WebKit::WebScrollbarThemeGeometry
* geometry
) {
222 return make_scoped_ptr(new ScrollbarThumbPainter(scrollbar
,
227 virtual void Paint(SkCanvas
* canvas
,
228 gfx::Rect content_rect
,
229 gfx::RectF
* opaque
) OVERRIDE
{
230 // Consider the thumb to be at the origin when painting.
231 gfx::Rect thumb_rect
= geometry_
->thumbRect(scrollbar_
);
232 painter_
->PaintThumb(canvas
, gfx::Rect(thumb_rect
.size()));
236 ScrollbarThumbPainter(WebKit::WebScrollbar
* scrollbar
,
237 ScrollbarThemePainter
* painter
,
238 WebKit::WebScrollbarThemeGeometry
* geometry
)
239 : scrollbar_(scrollbar
),
241 geometry_(geometry
) {}
243 WebKit::WebScrollbar
* scrollbar_
;
244 ScrollbarThemePainter
* painter_
;
245 WebKit::WebScrollbarThemeGeometry
* geometry_
;
247 DISALLOW_COPY_AND_ASSIGN(ScrollbarThumbPainter
);
250 void ScrollbarLayer::SetLayerTreeHost(LayerTreeHost
* host
) {
251 if (!host
|| host
!= layer_tree_host()) {
252 back_track_updater_
= NULL
;
254 thumb_updater_
= NULL
;
258 ContentsScalingLayer::SetLayerTreeHost(host
);
261 void ScrollbarLayer::CreateUpdaterIfNeeded() {
262 if (layer_tree_host()->settings().solid_color_scrollbars
)
266 layer_tree_host()->GetRendererCapabilities().best_texture_format
;
268 if (!back_track_updater_
) {
269 back_track_updater_
= CachingBitmapContentLayerUpdater::Create(
270 ScrollbarBackgroundPainter::Create(
274 WebKit::WebScrollbar::BackTrackPart
).PassAs
<LayerPainter
>(),
275 rendering_stats_instrumentation(),
279 back_track_
= back_track_updater_
->CreateResource(
280 layer_tree_host()->contents_texture_manager());
283 // Only create two-part track if we think the two parts could be different in
285 if (scrollbar_
->isCustomScrollbar()) {
286 if (!fore_track_updater_
) {
287 fore_track_updater_
= CachingBitmapContentLayerUpdater::Create(
288 ScrollbarBackgroundPainter::Create(
292 WebKit::WebScrollbar::ForwardTrackPart
).PassAs
<LayerPainter
>(),
293 rendering_stats_instrumentation(),
297 fore_track_
= fore_track_updater_
->CreateResource(
298 layer_tree_host()->contents_texture_manager());
302 if (!thumb_updater_
) {
303 thumb_updater_
= CachingBitmapContentLayerUpdater::Create(
304 ScrollbarThumbPainter::Create(scrollbar_
.get(),
306 geometry_
.get()).PassAs
<LayerPainter
>(),
307 rendering_stats_instrumentation(),
311 thumb_
= thumb_updater_
->CreateResource(
312 layer_tree_host()->contents_texture_manager());
316 void ScrollbarLayer::UpdatePart(CachingBitmapContentLayerUpdater
* painter
,
317 LayerUpdater::Resource
* resource
,
319 ResourceUpdateQueue
* queue
,
320 RenderingStats
* stats
) {
321 if (layer_tree_host()->settings().solid_color_scrollbars
)
324 // Skip painting and uploading if there are no invalidations and
325 // we already have valid texture data.
326 if (resource
->texture()->have_backing_texture() &&
327 resource
->texture()->size() == rect
.size() &&
331 // We should always have enough memory for UI.
332 DCHECK(resource
->texture()->can_acquire_backing_texture());
333 if (!resource
->texture()->can_acquire_backing_texture())
336 // Paint and upload the entire part.
337 gfx::Rect painted_opaque_rect
;
338 painter
->PrepareToUpdate(rect
,
342 &painted_opaque_rect
,
344 if (!painter
->pixels_did_change() &&
345 resource
->texture()->have_backing_texture()) {
346 TRACE_EVENT_INSTANT0("cc",
347 "ScrollbarLayer::UpdatePart no texture upload needed",
348 TRACE_EVENT_SCOPE_THREAD
);
352 bool partial_updates_allowed
=
353 layer_tree_host()->settings().max_partial_texture_updates
> 0;
354 if (!partial_updates_allowed
)
355 resource
->texture()->ReturnBackingTexture();
357 gfx::Vector2d
dest_offset(0, 0);
358 resource
->Update(queue
, rect
, dest_offset
, partial_updates_allowed
, stats
);
361 gfx::Rect
ScrollbarLayer::ScrollbarLayerRectToContentRect(
362 gfx::Rect layer_rect
) const {
363 // Don't intersect with the bounds as in LayerRectToContentRect() because
364 // layer_rect here might be in coordinates of the containing layer.
365 gfx::Rect expanded_rect
= gfx::ScaleToEnclosingRect(
366 layer_rect
, contents_scale_y(), contents_scale_y());
367 // We should never return a rect bigger than the content_bounds().
368 gfx::Size clamped_size
= expanded_rect
.size();
369 clamped_size
.ClampToMax(content_bounds());
370 expanded_rect
.set_size(clamped_size
);
371 return expanded_rect
;
374 void ScrollbarLayer::SetTexturePriorities(
375 const PriorityCalculator
& priority_calc
) {
376 if (layer_tree_host()->settings().solid_color_scrollbars
)
379 if (content_bounds().IsEmpty())
381 DCHECK_LE(content_bounds().width(), MaxTextureSize());
382 DCHECK_LE(content_bounds().height(), MaxTextureSize());
384 CreateUpdaterIfNeeded();
386 bool draws_to_root
= !render_target()->parent();
388 back_track_
->texture()->SetDimensions(content_bounds(), texture_format_
);
389 back_track_
->texture()->set_request_priority(
390 PriorityCalculator::UIPriority(draws_to_root
));
393 fore_track_
->texture()->SetDimensions(content_bounds(), texture_format_
);
394 fore_track_
->texture()->set_request_priority(
395 PriorityCalculator::UIPriority(draws_to_root
));
398 gfx::Rect thumb_layer_rect
= geometry_
->thumbRect(scrollbar_
.get());
399 gfx::Size thumb_size
=
400 ScrollbarLayerRectToContentRect(thumb_layer_rect
).size();
401 thumb_
->texture()->SetDimensions(thumb_size
, texture_format_
);
402 thumb_
->texture()->set_request_priority(
403 PriorityCalculator::UIPriority(draws_to_root
));
407 void ScrollbarLayer::Update(ResourceUpdateQueue
* queue
,
408 const OcclusionTracker
* occlusion
,
409 RenderingStats
* stats
) {
411 base::AutoReset
<bool> ignore_set_needs_commit(&ignore_set_needs_commit_
,
413 ContentsScalingLayer::Update(queue
, occlusion
, stats
);
416 dirty_rect_
.Union(update_rect_
);
417 if (content_bounds().IsEmpty())
419 if (visible_content_rect().IsEmpty())
422 CreateUpdaterIfNeeded();
424 gfx::Rect content_rect
= ScrollbarLayerRectToContentRect(
425 gfx::Rect(scrollbar_
->location(), bounds()));
426 UpdatePart(back_track_updater_
.get(),
431 if (fore_track_
&& fore_track_updater_
) {
432 UpdatePart(fore_track_updater_
.get(),
439 // Consider the thumb to be at the origin when painting.
440 gfx::Rect thumb_rect
= geometry_
->thumbRect(scrollbar_
.get());
441 thumb_size_
= thumb_rect
.size();
442 gfx::Rect origin_thumb_rect
=
443 ScrollbarLayerRectToContentRect(gfx::Rect(thumb_rect
.size()));
444 if (!origin_thumb_rect
.IsEmpty()) {
445 UpdatePart(thumb_updater_
.get(),
452 dirty_rect_
= gfx::RectF();