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.
5 #include "ui/views/painter.h"
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/point.h"
17 #include "ui/gfx/rect.h"
23 class GradientPainter
: public Painter
{
25 GradientPainter(bool horizontal
,
29 : horizontal_(horizontal
),
31 pos_
.reset(new SkScalar
[count_
]);
32 colors_
.reset(new SkColor
[count_
]);
34 for (size_t i
= 0; i
< count_
; ++i
) {
36 colors_
[i
] = colors
[i
];
40 virtual ~GradientPainter() {}
42 // Overridden from Painter:
43 virtual void Paint(gfx::Canvas
* canvas
, const gfx::Size
& size
) OVERRIDE
{
48 p
[1].iset(size
.width(), 0);
50 p
[1].iset(0, size
.height());
52 skia::RefPtr
<SkShader
> s
= skia::AdoptRef(SkGradientShader::CreateLinear(
53 p
, colors_
.get(), pos_
.get(), count_
, SkShader::kClamp_TileMode
, NULL
));
54 paint
.setStyle(SkPaint::kFill_Style
);
55 paint
.setShader(s
.get());
56 // Need to unref shader, otherwise never deleted.
58 canvas
->sk_canvas()->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
59 SkIntToScalar(size
.width()),
60 SkIntToScalar(size
.height()), paint
);
64 // If |horizontal_| is true then the gradiant is painted horizontally.
66 // The gradient colors.
67 scoped_array
<SkColor
> colors_
;
68 // The relative positions of the corresponding gradient colors.
69 scoped_array
<SkScalar
> pos_
;
70 // The number of elements in |colors_| and |pos_|.
73 DISALLOW_COPY_AND_ASSIGN(GradientPainter
);
76 // ImagePainter stores and paints nine images as a scalable grid.
77 class VIEWS_EXPORT ImagePainter
: public Painter
{
79 // Construct an ImagePainter with the specified image resource ids.
80 // See CreateImageGridPainter()'s comment regarding image ID count and order.
81 explicit ImagePainter(const int image_ids
[]);
82 // Construct an ImagePainter with the specified image and insets.
83 ImagePainter(const gfx::ImageSkia
& image
, const gfx::Insets
& insets
);
85 virtual ~ImagePainter();
87 // Returns true if the images are empty.
90 // Overridden from Painter:
91 virtual void Paint(gfx::Canvas
* canvas
, const gfx::Size
& size
) OVERRIDE
;
94 // Images must share widths by column and heights by row as depicted below.
95 // Coordinates along the X and Y axes are used for construction and painting.
97 // y0__|____|____|____|
98 // y1__|_i0_|_i1_|_i2_|
99 // y2__|_i3_|_i4_|_i5_|
100 // y3__|_i6_|_i7_|_i8_|
101 gfx::ImageSkia images_
[9];
103 DISALLOW_COPY_AND_ASSIGN(ImagePainter
);
106 ImagePainter::ImagePainter(const int image_ids
[]) {
107 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
108 for (size_t i
= 0; i
< 9; ++i
)
109 images_
[i
] = *rb
.GetImageSkiaNamed(image_ids
[i
]);
112 ImagePainter::ImagePainter(const gfx::ImageSkia
& image
,
113 const gfx::Insets
& insets
) {
114 DCHECK_GE(image
.width(), insets
.width());
115 DCHECK_GE(image
.height(), insets
.height());
117 // Extract subsets of the original image to match the |images_| format.
119 { 0, insets
.left(), image
.width() - insets
.right(), image
.width() };
121 { 0, insets
.top(), image
.height() - insets
.bottom(), image
.height() };
123 for (size_t j
= 0; j
< 3; ++j
) {
124 for (size_t i
= 0; i
< 3; ++i
) {
125 images_
[i
+ j
* 3] = gfx::ImageSkiaOperations::ExtractSubset(image
,
126 gfx::Rect(x
[i
], y
[j
], x
[i
+ 1] - x
[i
], y
[j
+ 1] - y
[j
]));
131 ImagePainter::~ImagePainter() {
134 bool ImagePainter::IsEmpty() const {
135 return images_
[0].isNull();
138 void ImagePainter::Paint(gfx::Canvas
* canvas
, const gfx::Size
& size
) {
142 // Paint image subsets in accordance with the |images_| format.
143 const gfx::Rect
rect(size
);
144 const int x
[] = { rect
.x(), rect
.x() + images_
[0].width(),
145 rect
.right() - images_
[2].width(), rect
.right() };
146 const int y
[] = { rect
.y(), rect
.y() + images_
[0].height(),
147 rect
.bottom() - images_
[6].height(), rect
.bottom() };
149 canvas
->DrawImageInt(images_
[0], x
[0], y
[0]);
150 canvas
->TileImageInt(images_
[1], x
[1], y
[0], x
[2] - x
[1], y
[1] - y
[0]);
151 canvas
->DrawImageInt(images_
[2], x
[2], y
[0]);
152 canvas
->TileImageInt(images_
[3], x
[0], y
[1], x
[1] - x
[0], y
[2] - y
[1]);
153 canvas
->DrawImageInt(
154 images_
[4], 0, 0, images_
[4].width(), images_
[4].height(),
155 x
[1], y
[1], x
[2] - x
[1], y
[2] - y
[1], false);
156 canvas
->TileImageInt(images_
[5], x
[2], y
[1], x
[3] - x
[2], y
[2] - y
[1]);
157 canvas
->DrawImageInt(images_
[6], 0, y
[2]);
158 canvas
->TileImageInt(images_
[7], x
[1], y
[2], x
[2] - x
[1], y
[3] - y
[2]);
159 canvas
->DrawImageInt(images_
[8], x
[2], y
[2]);
165 void Painter::PaintPainterAt(gfx::Canvas
* canvas
,
167 const gfx::Rect
& rect
) {
168 DCHECK(canvas
&& painter
);
170 canvas
->Translate(rect
.OffsetFromOrigin());
171 painter
->Paint(canvas
, rect
.size());
176 Painter
* Painter::CreateHorizontalGradient(SkColor c1
, SkColor c2
) {
180 SkScalar pos
[] = {0, 1};
181 return new GradientPainter(true, colors
, pos
, 2);
185 Painter
* Painter::CreateVerticalGradient(SkColor c1
, SkColor c2
) {
189 SkScalar pos
[] = {0, 1};
190 return new GradientPainter(false, colors
, pos
, 2);
194 Painter
* Painter::CreateVerticalMultiColorGradient(SkColor
* colors
,
197 return new GradientPainter(false, colors
, pos
, count
);
201 Painter
* Painter::CreateImagePainter(const gfx::ImageSkia
& image
,
202 const gfx::Insets
& insets
) {
203 return new ImagePainter(image
, insets
);
207 Painter
* Painter::CreateImageGridPainter(const int image_ids
[]) {
208 return new ImagePainter(image_ids
);
211 HorizontalPainter::HorizontalPainter(const int image_resource_names
[]) {
212 ui::ResourceBundle
& rb
= ui::ResourceBundle::GetSharedInstance();
213 for (int i
= 0; i
< 3; ++i
)
214 images_
[i
] = rb
.GetImageNamed(image_resource_names
[i
]).ToImageSkia();
215 height_
= images_
[LEFT
]->height();
216 DCHECK(images_
[LEFT
]->height() == images_
[RIGHT
]->height() &&
217 images_
[LEFT
]->height() == images_
[CENTER
]->height());
220 void HorizontalPainter::Paint(gfx::Canvas
* canvas
, const gfx::Size
& size
) {
221 if (size
.width() < (images_
[LEFT
]->width() + images_
[CENTER
]->width() +
222 images_
[RIGHT
]->width())) {
226 canvas
->DrawImageInt(*images_
[LEFT
], 0, 0);
227 canvas
->DrawImageInt(*images_
[RIGHT
],
228 size
.width() - images_
[RIGHT
]->width(), 0);
229 canvas
->TileImageInt(*images_
[CENTER
], images_
[LEFT
]->width(), 0,
230 size
.width() - images_
[LEFT
]->width() - images_
[RIGHT
]->width(), height_
);