1 // Copyright (c) 2012 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 "ui/views/painter.h"
6 
7 #include <utility>
8 
9 #include "base/logging.h"
10 #include "ui/compositor/layer.h"
11 #include "ui/compositor/layer_delegate.h"
12 #include "ui/compositor/layer_owner.h"
13 #include "ui/compositor/paint_recorder.h"
14 #include "ui/gfx/canvas.h"
15 #include "ui/gfx/geometry/insets.h"
16 #include "ui/gfx/geometry/insets_f.h"
17 #include "ui/gfx/geometry/rect_f.h"
18 #include "ui/gfx/geometry/size.h"
19 #include "ui/gfx/nine_image_painter.h"
20 #include "ui/gfx/scoped_canvas.h"
21 #include "ui/views/view.h"
22 
23 namespace views {
24 
25 namespace {
26 
27 // SolidRoundRectPainter -------------------------------------------------------
28 
29 // Creates a round rect painter with a 1 pixel border. The border paints on top
30 // of the background.
31 class SolidRoundRectPainter : public Painter {
32  public:
33   SolidRoundRectPainter(SkColor bg_color,
34                         SkColor stroke_color,
35                         float radius,
36                         const gfx::Insets& insets,
37                         SkBlendMode blend_mode,
38                         bool antialias);
39   ~SolidRoundRectPainter() override;
40 
41   // Painter:
42   gfx::Size GetMinimumSize() const override;
43   void Paint(gfx::Canvas* canvas, const gfx::Size& size) override;
44 
45  private:
46   const SkColor bg_color_;
47   const SkColor stroke_color_;
48   const float radius_;
49   const gfx::Insets insets_;
50   const SkBlendMode blend_mode_;
51   const bool antialias_;
52 
53   DISALLOW_COPY_AND_ASSIGN(SolidRoundRectPainter);
54 };
55 
SolidRoundRectPainter(SkColor bg_color,SkColor stroke_color,float radius,const gfx::Insets & insets,SkBlendMode blend_mode,bool antialias)56 SolidRoundRectPainter::SolidRoundRectPainter(SkColor bg_color,
57                                              SkColor stroke_color,
58                                              float radius,
59                                              const gfx::Insets& insets,
60                                              SkBlendMode blend_mode,
61                                              bool antialias)
62     : bg_color_(bg_color),
63       stroke_color_(stroke_color),
64       radius_(radius),
65       insets_(insets),
66       blend_mode_(blend_mode),
67       antialias_(antialias) {}
68 
69 SolidRoundRectPainter::~SolidRoundRectPainter() = default;
70 
GetMinimumSize() const71 gfx::Size SolidRoundRectPainter::GetMinimumSize() const {
72   return gfx::Size();
73 }
74 
Paint(gfx::Canvas * canvas,const gfx::Size & size)75 void SolidRoundRectPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
76   gfx::ScopedCanvas scoped_canvas(canvas);
77   const float scale = canvas->UndoDeviceScaleFactor();
78 
79   gfx::Rect inset_rect(size);
80   inset_rect.Inset(insets_);
81   gfx::RectF fill_rect(gfx::ScaleToEnclosingRect(inset_rect, scale));
82   gfx::RectF stroke_rect = fill_rect;
83   float scaled_radius = radius_ * scale;
84 
85   cc::PaintFlags flags;
86   flags.setBlendMode(blend_mode_);
87   if (antialias_)
88     flags.setAntiAlias(true);
89   flags.setStyle(cc::PaintFlags::kFill_Style);
90   flags.setColor(bg_color_);
91   canvas->DrawRoundRect(fill_rect, scaled_radius, flags);
92 
93   if (stroke_color_ != SK_ColorTRANSPARENT) {
94     constexpr float kStrokeWidth = 1.0f;
95     stroke_rect.Inset(gfx::InsetsF(kStrokeWidth / 2));
96     scaled_radius -= kStrokeWidth / 2;
97     flags.setStyle(cc::PaintFlags::kStroke_Style);
98     flags.setStrokeWidth(kStrokeWidth);
99     flags.setColor(stroke_color_);
100     canvas->DrawRoundRect(stroke_rect, scaled_radius, flags);
101   }
102 }
103 
104 // SolidFocusPainter -----------------------------------------------------------
105 
106 class SolidFocusPainter : public Painter {
107  public:
108   SolidFocusPainter(SkColor color, int thickness, const gfx::InsetsF& insets);
109   ~SolidFocusPainter() override;
110 
111   // Painter:
112   gfx::Size GetMinimumSize() const override;
113   void Paint(gfx::Canvas* canvas, const gfx::Size& size) override;
114 
115  private:
116   const SkColor color_;
117   const int thickness_;
118   const gfx::InsetsF insets_;
119 
120   DISALLOW_COPY_AND_ASSIGN(SolidFocusPainter);
121 };
122 
SolidFocusPainter(SkColor color,int thickness,const gfx::InsetsF & insets)123 SolidFocusPainter::SolidFocusPainter(SkColor color,
124                                      int thickness,
125                                      const gfx::InsetsF& insets)
126     : color_(color), thickness_(thickness), insets_(insets) {}
127 
128 SolidFocusPainter::~SolidFocusPainter() = default;
129 
GetMinimumSize() const130 gfx::Size SolidFocusPainter::GetMinimumSize() const {
131   return gfx::Size();
132 }
133 
Paint(gfx::Canvas * canvas,const gfx::Size & size)134 void SolidFocusPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
135   gfx::RectF rect((gfx::Rect(size)));
136   rect.Inset(insets_);
137   canvas->DrawSolidFocusRect(rect, color_, thickness_);
138 }
139 
140 // ImagePainter ---------------------------------------------------------------
141 
142 // ImagePainter stores and paints nine images as a scalable grid.
143 class ImagePainter : public Painter {
144  public:
145   // Constructs an ImagePainter with the specified image resource ids.
146   // See CreateImageGridPainter()'s comment regarding image ID count and order.
147   explicit ImagePainter(const int image_ids[]);
148 
149   // Constructs an ImagePainter with the specified image and insets.
150   ImagePainter(const gfx::ImageSkia& image, const gfx::Insets& insets);
151 
152   ~ImagePainter() override;
153 
154   // Painter:
155   gfx::Size GetMinimumSize() const override;
156   void Paint(gfx::Canvas* canvas, const gfx::Size& size) override;
157 
158  private:
159   std::unique_ptr<gfx::NineImagePainter> nine_painter_;
160 
161   DISALLOW_COPY_AND_ASSIGN(ImagePainter);
162 };
163 
ImagePainter(const int image_ids[])164 ImagePainter::ImagePainter(const int image_ids[])
165     : nine_painter_(ui::CreateNineImagePainter(image_ids)) {}
166 
ImagePainter(const gfx::ImageSkia & image,const gfx::Insets & insets)167 ImagePainter::ImagePainter(const gfx::ImageSkia& image,
168                            const gfx::Insets& insets)
169     : nine_painter_(new gfx::NineImagePainter(image, insets)) {}
170 
171 ImagePainter::~ImagePainter() = default;
172 
GetMinimumSize() const173 gfx::Size ImagePainter::GetMinimumSize() const {
174   return nine_painter_->GetMinimumSize();
175 }
176 
Paint(gfx::Canvas * canvas,const gfx::Size & size)177 void ImagePainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
178   nine_painter_->Paint(canvas, gfx::Rect(size));
179 }
180 
181 class PaintedLayer : public ui::LayerOwner, public ui::LayerDelegate {
182  public:
183   explicit PaintedLayer(std::unique_ptr<Painter> painter);
184   ~PaintedLayer() override;
185 
186   // LayerDelegate:
187   void OnPaintLayer(const ui::PaintContext& context) override;
188   void OnDeviceScaleFactorChanged(float old_device_scale_factor,
189                                   float new_device_scale_factor) override;
190 
191  private:
192   std::unique_ptr<Painter> painter_;
193 
194   DISALLOW_COPY_AND_ASSIGN(PaintedLayer);
195 };
196 
PaintedLayer(std::unique_ptr<Painter> painter)197 PaintedLayer::PaintedLayer(std::unique_ptr<Painter> painter)
198     : painter_(std::move(painter)) {
199   SetLayer(std::make_unique<ui::Layer>(ui::LAYER_TEXTURED));
200   layer()->set_delegate(this);
201 }
202 
203 PaintedLayer::~PaintedLayer() = default;
204 
OnPaintLayer(const ui::PaintContext & context)205 void PaintedLayer::OnPaintLayer(const ui::PaintContext& context) {
206   ui::PaintRecorder recorder(context, layer()->size());
207   painter_->Paint(recorder.canvas(), layer()->size());
208 }
209 
OnDeviceScaleFactorChanged(float old_device_scale_factor,float new_device_scale_factor)210 void PaintedLayer::OnDeviceScaleFactorChanged(float old_device_scale_factor,
211                                               float new_device_scale_factor) {}
212 
213 }  // namespace
214 
215 // Painter --------------------------------------------------------------------
216 
217 Painter::Painter() = default;
218 
219 Painter::~Painter() = default;
220 
221 // static
PaintPainterAt(gfx::Canvas * canvas,Painter * painter,const gfx::Rect & rect)222 void Painter::PaintPainterAt(gfx::Canvas* canvas,
223                              Painter* painter,
224                              const gfx::Rect& rect) {
225   DCHECK(canvas);
226   DCHECK(painter);
227   canvas->Save();
228   canvas->Translate(rect.OffsetFromOrigin());
229   painter->Paint(canvas, rect.size());
230   canvas->Restore();
231 }
232 
233 // static
PaintFocusPainter(View * view,gfx::Canvas * canvas,Painter * focus_painter)234 void Painter::PaintFocusPainter(View* view,
235                                 gfx::Canvas* canvas,
236                                 Painter* focus_painter) {
237   if (focus_painter && view->HasFocus())
238     PaintPainterAt(canvas, focus_painter, view->GetLocalBounds());
239 }
240 
241 // static
CreateSolidRoundRectPainter(SkColor color,float radius,const gfx::Insets & insets,SkBlendMode blend_mode,bool antialias)242 std::unique_ptr<Painter> Painter::CreateSolidRoundRectPainter(
243     SkColor color,
244     float radius,
245     const gfx::Insets& insets,
246     SkBlendMode blend_mode,
247     bool antialias) {
248   return std::make_unique<SolidRoundRectPainter>(
249       color, SK_ColorTRANSPARENT, radius, insets, blend_mode, antialias);
250 }
251 
252 // static
CreateRoundRectWith1PxBorderPainter(SkColor bg_color,SkColor stroke_color,float radius,SkBlendMode blend_mode,bool antialias)253 std::unique_ptr<Painter> Painter::CreateRoundRectWith1PxBorderPainter(
254     SkColor bg_color,
255     SkColor stroke_color,
256     float radius,
257     SkBlendMode blend_mode,
258     bool antialias) {
259   return std::make_unique<SolidRoundRectPainter>(
260       bg_color, stroke_color, radius, gfx::Insets(), blend_mode, antialias);
261 }
262 
263 // static
CreateImagePainter(const gfx::ImageSkia & image,const gfx::Insets & insets)264 std::unique_ptr<Painter> Painter::CreateImagePainter(
265     const gfx::ImageSkia& image,
266     const gfx::Insets& insets) {
267   return std::make_unique<ImagePainter>(image, insets);
268 }
269 
270 // static
CreateImageGridPainter(const int image_ids[])271 std::unique_ptr<Painter> Painter::CreateImageGridPainter(
272     const int image_ids[]) {
273   return std::make_unique<ImagePainter>(image_ids);
274 }
275 
276 // static
CreateSolidFocusPainter(SkColor color,const gfx::Insets & insets)277 std::unique_ptr<Painter> Painter::CreateSolidFocusPainter(
278     SkColor color,
279     const gfx::Insets& insets) {
280   // Before Canvas::DrawSolidFocusRect correctly inset the rect's bounds based
281   // on the thickness, callers had to add 1 to the bottom and right insets.
282   // Subtract that here so it works the same way with the new
283   // Canvas::DrawSolidFocusRect.
284   const gfx::Insets corrected_insets = insets - gfx::Insets(0, 0, 1, 1);
285   return std::make_unique<SolidFocusPainter>(color, 1, corrected_insets);
286 }
287 
288 // static
CreateSolidFocusPainter(SkColor color,int thickness,const gfx::InsetsF & insets)289 std::unique_ptr<Painter> Painter::CreateSolidFocusPainter(
290     SkColor color,
291     int thickness,
292     const gfx::InsetsF& insets) {
293   return std::make_unique<SolidFocusPainter>(color, thickness, insets);
294 }
295 
296 // static
CreatePaintedLayer(std::unique_ptr<Painter> painter)297 std::unique_ptr<ui::LayerOwner> Painter::CreatePaintedLayer(
298     std::unique_ptr<Painter> painter) {
299   return std::make_unique<PaintedLayer>(std::move(painter));
300 }
301 
302 }  // namespace views
303