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 "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "third_party/skia/include/effects/SkGradientShader.h"
10 #include "ui/base/resource/resource_bundle.h"
11 #include "ui/gfx/canvas.h"
12 #include "ui/gfx/image/image.h"
13 #include "ui/gfx/image/image_skia.h"
14 #include "ui/gfx/image/image_skia_operations.h"
15 #include "ui/gfx/insets.h"
16 #include "ui/gfx/nine_image_painter.h"
17 #include "ui/gfx/point.h"
18 #include "ui/gfx/rect.h"
19 #include "ui/views/view.h"
20
21 namespace views {
22
23 namespace {
24
25 // DashedFocusPainter ----------------------------------------------------------
26
27 class DashedFocusPainter : public Painter {
28 public:
29 explicit DashedFocusPainter(const gfx::Insets& insets);
30 virtual ~DashedFocusPainter();
31
32 // Painter:
33 virtual gfx::Size GetMinimumSize() const OVERRIDE;
34 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE;
35
36 private:
37 const gfx::Insets insets_;
38
39 DISALLOW_COPY_AND_ASSIGN(DashedFocusPainter);
40 };
41
DashedFocusPainter(const gfx::Insets & insets)42 DashedFocusPainter::DashedFocusPainter(const gfx::Insets& insets)
43 : insets_(insets) {
44 }
45
~DashedFocusPainter()46 DashedFocusPainter::~DashedFocusPainter() {
47 }
48
GetMinimumSize() const49 gfx::Size DashedFocusPainter::GetMinimumSize() const {
50 return gfx::Size();
51 }
52
Paint(gfx::Canvas * canvas,const gfx::Size & size)53 void DashedFocusPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
54 gfx::Rect rect(size);
55 rect.Inset(insets_);
56 canvas->DrawFocusRect(rect);
57 }
58
59 // SolidFocusPainter -----------------------------------------------------------
60
61 class SolidFocusPainter : public Painter {
62 public:
63 SolidFocusPainter(SkColor color, const gfx::Insets& insets);
64 virtual ~SolidFocusPainter();
65
66 // Painter:
67 virtual gfx::Size GetMinimumSize() const OVERRIDE;
68 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE;
69
70 private:
71 const SkColor color_;
72 const gfx::Insets insets_;
73
74 DISALLOW_COPY_AND_ASSIGN(SolidFocusPainter);
75 };
76
SolidFocusPainter(SkColor color,const gfx::Insets & insets)77 SolidFocusPainter::SolidFocusPainter(SkColor color,
78 const gfx::Insets& insets)
79 : color_(color),
80 insets_(insets) {
81 }
82
~SolidFocusPainter()83 SolidFocusPainter::~SolidFocusPainter() {
84 }
85
GetMinimumSize() const86 gfx::Size SolidFocusPainter::GetMinimumSize() const {
87 return gfx::Size();
88 }
89
Paint(gfx::Canvas * canvas,const gfx::Size & size)90 void SolidFocusPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
91 gfx::Rect rect(size);
92 rect.Inset(insets_);
93 canvas->DrawSolidFocusRect(rect, color_);
94 }
95
96 // GradientPainter ------------------------------------------------------------
97
98 class GradientPainter : public Painter {
99 public:
100 GradientPainter(bool horizontal,
101 SkColor* colors,
102 SkScalar* pos,
103 size_t count);
104 virtual ~GradientPainter();
105
106 // Painter:
107 virtual gfx::Size GetMinimumSize() const OVERRIDE;
108 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE;
109
110 private:
111 // If |horizontal_| is true then the gradient is painted horizontally.
112 bool horizontal_;
113 // The gradient colors.
114 scoped_ptr<SkColor[]> colors_;
115 // The relative positions of the corresponding gradient colors.
116 scoped_ptr<SkScalar[]> pos_;
117 // The number of elements in |colors_| and |pos_|.
118 size_t count_;
119
120 DISALLOW_COPY_AND_ASSIGN(GradientPainter);
121 };
122
GradientPainter(bool horizontal,SkColor * colors,SkScalar * pos,size_t count)123 GradientPainter::GradientPainter(bool horizontal,
124 SkColor* colors,
125 SkScalar* pos,
126 size_t count)
127 : horizontal_(horizontal),
128 colors_(new SkColor[count]),
129 pos_(new SkScalar[count]),
130 count_(count) {
131 for (size_t i = 0; i < count_; ++i) {
132 pos_[i] = pos[i];
133 colors_[i] = colors[i];
134 }
135 }
136
~GradientPainter()137 GradientPainter::~GradientPainter() {
138 }
139
GetMinimumSize() const140 gfx::Size GradientPainter::GetMinimumSize() const {
141 return gfx::Size();
142 }
143
Paint(gfx::Canvas * canvas,const gfx::Size & size)144 void GradientPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
145 SkPaint paint;
146 SkPoint p[2];
147 p[0].iset(0, 0);
148 if (horizontal_)
149 p[1].iset(size.width(), 0);
150 else
151 p[1].iset(0, size.height());
152
153 skia::RefPtr<SkShader> s = skia::AdoptRef(SkGradientShader::CreateLinear(
154 p, colors_.get(), pos_.get(), count_, SkShader::kClamp_TileMode));
155 paint.setStyle(SkPaint::kFill_Style);
156 paint.setShader(s.get());
157
158 canvas->sk_canvas()->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
159 SkIntToScalar(size.width()),
160 SkIntToScalar(size.height()), paint);
161 }
162
163 // ImagePainter ---------------------------------------------------------------
164
165 // ImagePainter stores and paints nine images as a scalable grid.
166 class ImagePainter : public Painter {
167 public:
168 // Constructs an ImagePainter with the specified image resource ids.
169 // See CreateImageGridPainter()'s comment regarding image ID count and order.
170 explicit ImagePainter(const int image_ids[]);
171
172 // Constructs an ImagePainter with the specified image and insets.
173 ImagePainter(const gfx::ImageSkia& image, const gfx::Insets& insets);
174
175 virtual ~ImagePainter();
176
177 // Painter:
178 virtual gfx::Size GetMinimumSize() const OVERRIDE;
179 virtual void Paint(gfx::Canvas* canvas, const gfx::Size& size) OVERRIDE;
180
181 private:
182 scoped_ptr<gfx::NineImagePainter> nine_painter_;
183
184 DISALLOW_COPY_AND_ASSIGN(ImagePainter);
185 };
186
ImagePainter(const int image_ids[])187 ImagePainter::ImagePainter(const int image_ids[])
188 : nine_painter_(ui::CreateNineImagePainter(image_ids)) {
189 }
190
ImagePainter(const gfx::ImageSkia & image,const gfx::Insets & insets)191 ImagePainter::ImagePainter(const gfx::ImageSkia& image,
192 const gfx::Insets& insets)
193 : nine_painter_(new gfx::NineImagePainter(image, insets)) {
194 }
195
~ImagePainter()196 ImagePainter::~ImagePainter() {
197 }
198
GetMinimumSize() const199 gfx::Size ImagePainter::GetMinimumSize() const {
200 return nine_painter_->GetMinimumSize();
201 }
202
Paint(gfx::Canvas * canvas,const gfx::Size & size)203 void ImagePainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
204 nine_painter_->Paint(canvas, gfx::Rect(size));
205 }
206
207 } // namespace
208
209
210 // Painter --------------------------------------------------------------------
211
Painter()212 Painter::Painter() {
213 }
214
~Painter()215 Painter::~Painter() {
216 }
217
218 // static
PaintPainterAt(gfx::Canvas * canvas,Painter * painter,const gfx::Rect & rect)219 void Painter::PaintPainterAt(gfx::Canvas* canvas,
220 Painter* painter,
221 const gfx::Rect& rect) {
222 DCHECK(canvas && painter);
223 canvas->Save();
224 canvas->Translate(rect.OffsetFromOrigin());
225 painter->Paint(canvas, rect.size());
226 canvas->Restore();
227 }
228
229 // static
PaintFocusPainter(View * view,gfx::Canvas * canvas,Painter * focus_painter)230 void Painter::PaintFocusPainter(View* view,
231 gfx::Canvas* canvas,
232 Painter* focus_painter) {
233 if (focus_painter && view->HasFocus())
234 PaintPainterAt(canvas, focus_painter, view->GetLocalBounds());
235 }
236
237 // static
CreateHorizontalGradient(SkColor c1,SkColor c2)238 Painter* Painter::CreateHorizontalGradient(SkColor c1, SkColor c2) {
239 SkColor colors[2];
240 colors[0] = c1;
241 colors[1] = c2;
242 SkScalar pos[] = {0, 1};
243 return new GradientPainter(true, colors, pos, 2);
244 }
245
246 // static
CreateVerticalGradient(SkColor c1,SkColor c2)247 Painter* Painter::CreateVerticalGradient(SkColor c1, SkColor c2) {
248 SkColor colors[2];
249 colors[0] = c1;
250 colors[1] = c2;
251 SkScalar pos[] = {0, 1};
252 return new GradientPainter(false, colors, pos, 2);
253 }
254
255 // static
CreateVerticalMultiColorGradient(SkColor * colors,SkScalar * pos,size_t count)256 Painter* Painter::CreateVerticalMultiColorGradient(SkColor* colors,
257 SkScalar* pos,
258 size_t count) {
259 return new GradientPainter(false, colors, pos, count);
260 }
261
262 // static
CreateImagePainter(const gfx::ImageSkia & image,const gfx::Insets & insets)263 Painter* Painter::CreateImagePainter(const gfx::ImageSkia& image,
264 const gfx::Insets& insets) {
265 return new ImagePainter(image, insets);
266 }
267
268 // static
CreateImageGridPainter(const int image_ids[])269 Painter* Painter::CreateImageGridPainter(const int image_ids[]) {
270 return new ImagePainter(image_ids);
271 }
272
273 // static
CreateDashedFocusPainter()274 scoped_ptr<Painter> Painter::CreateDashedFocusPainter() {
275 return scoped_ptr<Painter>(new DashedFocusPainter(gfx::Insets())).Pass();
276 }
277
278 // static
CreateDashedFocusPainterWithInsets(const gfx::Insets & insets)279 scoped_ptr<Painter> Painter::CreateDashedFocusPainterWithInsets(
280 const gfx::Insets& insets) {
281 return scoped_ptr<Painter>(new DashedFocusPainter(insets)).Pass();
282 }
283
284 // static
CreateSolidFocusPainter(SkColor color,const gfx::Insets & insets)285 scoped_ptr<Painter> Painter::CreateSolidFocusPainter(
286 SkColor color,
287 const gfx::Insets& insets) {
288 return scoped_ptr<Painter>(new SolidFocusPainter(color, insets)).Pass();
289 }
290
291 // HorizontalPainter ----------------------------------------------------------
292
HorizontalPainter(const int image_resource_names[])293 HorizontalPainter::HorizontalPainter(const int image_resource_names[]) {
294 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
295 for (int i = 0; i < 3; ++i)
296 images_[i] = rb.GetImageNamed(image_resource_names[i]).ToImageSkia();
297 DCHECK_EQ(images_[LEFT]->height(), images_[CENTER]->height());
298 DCHECK_EQ(images_[LEFT]->height(), images_[RIGHT]->height());
299 }
300
~HorizontalPainter()301 HorizontalPainter::~HorizontalPainter() {
302 }
303
GetMinimumSize() const304 gfx::Size HorizontalPainter::GetMinimumSize() const {
305 return gfx::Size(
306 images_[LEFT]->width() + images_[CENTER]->width() +
307 images_[RIGHT]->width(), images_[LEFT]->height());
308 }
309
Paint(gfx::Canvas * canvas,const gfx::Size & size)310 void HorizontalPainter::Paint(gfx::Canvas* canvas, const gfx::Size& size) {
311 if (size.width() < GetMinimumSize().width())
312 return; // No room to paint.
313
314 canvas->DrawImageInt(*images_[LEFT], 0, 0);
315 canvas->DrawImageInt(*images_[RIGHT], size.width() - images_[RIGHT]->width(),
316 0);
317 canvas->TileImageInt(
318 *images_[CENTER], images_[LEFT]->width(), 0,
319 size.width() - images_[LEFT]->width() - images_[RIGHT]->width(),
320 images_[LEFT]->height());
321 }
322
323 } // namespace views
324