1 // Copyright 2014 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 "third_party/blink/renderer/core/scroll/scrollbar_layer_delegate.h"
6
7 #include "cc/paint/paint_canvas.h"
8 #include "third_party/blink/renderer/core/scroll/scroll_types.h"
9 #include "third_party/blink/renderer/core/scroll/scrollable_area.h"
10 #include "third_party/blink/renderer/core/scroll/scrollbar.h"
11 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
12 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
13 #include "third_party/blink/renderer/platform/graphics/paint/paint_canvas.h"
14 #include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
15 #include "ui/gfx/skia_util.h"
16
17 namespace blink {
18
19 namespace {
20
21 class ScopedScrollbarPainter {
22 public:
ScopedScrollbarPainter(cc::PaintCanvas & canvas,float device_scale_factor)23 ScopedScrollbarPainter(cc::PaintCanvas& canvas, float device_scale_factor)
24 : canvas_(canvas) {
25 builder_.Context().SetDeviceScaleFactor(device_scale_factor);
26 }
~ScopedScrollbarPainter()27 ~ScopedScrollbarPainter() { canvas_.drawPicture(builder_.EndRecording()); }
28
Context()29 GraphicsContext& Context() { return builder_.Context(); }
30
31 private:
32 cc::PaintCanvas& canvas_;
33 PaintRecordBuilder builder_;
34 };
35
36 } // namespace
37
ScrollbarLayerDelegate(blink::Scrollbar & scrollbar,float device_scale_factor)38 ScrollbarLayerDelegate::ScrollbarLayerDelegate(blink::Scrollbar& scrollbar,
39 float device_scale_factor)
40 : scrollbar_(&scrollbar), device_scale_factor_(device_scale_factor) {
41 // Custom scrollbars are either non-composited or use cc::PictureLayers
42 // which don't need ScrollbarLayerDelegate.
43 DCHECK(!scrollbar.IsCustomScrollbar());
44 }
45
46 ScrollbarLayerDelegate::~ScrollbarLayerDelegate() = default;
47
IsSame(const cc::Scrollbar & other) const48 bool ScrollbarLayerDelegate::IsSame(const cc::Scrollbar& other) const {
49 return scrollbar_.Get() ==
50 static_cast<const ScrollbarLayerDelegate&>(other).scrollbar_.Get();
51 }
52
Orientation() const53 cc::ScrollbarOrientation ScrollbarLayerDelegate::Orientation() const {
54 if (scrollbar_->Orientation() == kHorizontalScrollbar)
55 return cc::ScrollbarOrientation::HORIZONTAL;
56 return cc::ScrollbarOrientation::VERTICAL;
57 }
58
IsLeftSideVerticalScrollbar() const59 bool ScrollbarLayerDelegate::IsLeftSideVerticalScrollbar() const {
60 return scrollbar_->IsLeftSideVerticalScrollbar();
61 }
62
HasThumb() const63 bool ScrollbarLayerDelegate::HasThumb() const {
64 return scrollbar_->GetTheme().HasThumb(*scrollbar_);
65 }
66
IsSolidColor() const67 bool ScrollbarLayerDelegate::IsSolidColor() const {
68 return scrollbar_->GetTheme().IsSolidColor();
69 }
70
IsOverlay() const71 bool ScrollbarLayerDelegate::IsOverlay() const {
72 return scrollbar_->IsOverlayScrollbar();
73 }
74
ThumbRect() const75 gfx::Rect ScrollbarLayerDelegate::ThumbRect() const {
76 IntRect track_rect = scrollbar_->GetTheme().ThumbRect(*scrollbar_);
77 track_rect.MoveBy(-scrollbar_->Location());
78 return track_rect;
79 }
80
TrackRect() const81 gfx::Rect ScrollbarLayerDelegate::TrackRect() const {
82 IntRect track_rect = scrollbar_->GetTheme().TrackRect(*scrollbar_);
83 track_rect.MoveBy(-scrollbar_->Location());
84 return track_rect;
85 }
86
SupportsDragSnapBack() const87 bool ScrollbarLayerDelegate::SupportsDragSnapBack() const {
88 return scrollbar_->GetTheme().SupportsDragSnapBack();
89 }
90
JumpOnTrackClick() const91 bool ScrollbarLayerDelegate::JumpOnTrackClick() const {
92 return scrollbar_->GetTheme().JumpOnTrackClick();
93 }
94
BackButtonRect() const95 gfx::Rect ScrollbarLayerDelegate::BackButtonRect() const {
96 IntRect back_button_rect = scrollbar_->GetTheme().BackButtonRect(*scrollbar_);
97 if (!back_button_rect.IsEmpty())
98 back_button_rect.MoveBy(-scrollbar_->Location());
99 return back_button_rect;
100 }
101
ForwardButtonRect() const102 gfx::Rect ScrollbarLayerDelegate::ForwardButtonRect() const {
103 IntRect forward_button_rect =
104 scrollbar_->GetTheme().ForwardButtonRect(*scrollbar_);
105 if (!forward_button_rect.IsEmpty())
106 forward_button_rect.MoveBy(-scrollbar_->Location());
107 return forward_button_rect;
108 }
109
Opacity() const110 float ScrollbarLayerDelegate::Opacity() const {
111 return scrollbar_->GetTheme().Opacity(*scrollbar_);
112 }
113
NeedsRepaintPart(cc::ScrollbarPart part) const114 bool ScrollbarLayerDelegate::NeedsRepaintPart(cc::ScrollbarPart part) const {
115 if (part == cc::ScrollbarPart::THUMB)
116 return scrollbar_->ThumbNeedsRepaint();
117 return scrollbar_->TrackNeedsRepaint();
118 }
119
UsesNinePatchThumbResource() const120 bool ScrollbarLayerDelegate::UsesNinePatchThumbResource() const {
121 return scrollbar_->GetTheme().UsesNinePatchThumbResource();
122 }
123
NinePatchThumbCanvasSize() const124 gfx::Size ScrollbarLayerDelegate::NinePatchThumbCanvasSize() const {
125 DCHECK(scrollbar_->GetTheme().UsesNinePatchThumbResource());
126 return static_cast<gfx::Size>(
127 scrollbar_->GetTheme().NinePatchThumbCanvasSize(*scrollbar_));
128 }
129
NinePatchThumbAperture() const130 gfx::Rect ScrollbarLayerDelegate::NinePatchThumbAperture() const {
131 DCHECK(scrollbar_->GetTheme().UsesNinePatchThumbResource());
132 return scrollbar_->GetTheme().NinePatchThumbAperture(*scrollbar_);
133 }
134
ShouldPaint() const135 bool ScrollbarLayerDelegate::ShouldPaint() const {
136 // TODO(crbug.com/860499): Remove this condition, it should not occur.
137 // Layers may exist and be painted for a |scrollbar_| that has had its
138 // ScrollableArea detached. This seems weird because if the area is detached
139 // the layer should be destroyed but here we are. https://crbug.com/860499.
140 if (!scrollbar_->GetScrollableArea())
141 return false;
142 // When the frame is throttled, the scrollbar will not be painted because
143 // the frame has not had its lifecycle updated. Thus the actual value of
144 // HasTickmarks can't be known and may change once the frame is unthrottled.
145 if (scrollbar_->GetScrollableArea()->IsThrottled())
146 return false;
147 return true;
148 }
149
HasTickmarks() const150 bool ScrollbarLayerDelegate::HasTickmarks() const {
151 return ShouldPaint() && scrollbar_->HasTickmarks();
152 }
153
PaintPart(cc::PaintCanvas * canvas,cc::ScrollbarPart part,const gfx::Rect & rect)154 void ScrollbarLayerDelegate::PaintPart(cc::PaintCanvas* canvas,
155 cc::ScrollbarPart part,
156 const gfx::Rect& rect) {
157 if (!ShouldPaint())
158 return;
159
160 auto& theme = scrollbar_->GetTheme();
161 ScopedScrollbarPainter painter(*canvas, device_scale_factor_);
162 // The canvas coordinate space is relative to the part's origin.
163 switch (part) {
164 case cc::ScrollbarPart::THUMB:
165 theme.PaintThumb(painter.Context(), *scrollbar_, IntRect(rect));
166 scrollbar_->ClearThumbNeedsRepaint();
167 break;
168 case cc::ScrollbarPart::TRACK_BUTTONS_TICKMARKS: {
169 DCHECK_EQ(IntSize(rect.size()), scrollbar_->FrameRect().Size());
170 IntPoint offset(IntPoint(rect.origin()) -
171 scrollbar_->FrameRect().Location());
172 theme.PaintTrackButtonsTickmarks(painter.Context(), *scrollbar_, offset);
173 scrollbar_->ClearTrackNeedsRepaint();
174 break;
175 }
176 default:
177 NOTREACHED();
178 }
179 }
180
181 } // namespace blink
182