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.
5 #include "ui/gfx/nine_image_painter.h"
9 #include "third_party/skia/include/core/SkPaint.h"
10 #include "third_party/skia/include/core/SkRect.h"
11 #include "third_party/skia/include/core/SkScalar.h"
12 #include "ui/gfx/canvas.h"
13 #include "ui/gfx/geometry/rect_conversions.h"
14 #include "ui/gfx/geometry/safe_integer_conversions.h"
15 #include "ui/gfx/image/image_skia_operations.h"
16 #include "ui/gfx/insets.h"
17 #include "ui/gfx/rect.h"
18 #include "ui/gfx/scoped_canvas.h"
19 #include "ui/gfx/skia_util.h"
25 // The following functions width and height of the image in pixels for the
26 // scale factor in the Canvas.
27 int ImageWidthInPixels(const ImageSkia
& i
, Canvas
* c
) {
28 return i
.GetRepresentation(c
->image_scale()).pixel_width();
31 int ImageHeightInPixels(const ImageSkia
& i
, Canvas
* c
) {
32 return i
.GetRepresentation(c
->image_scale()).pixel_height();
35 // Stretches the given image over the specified canvas area.
42 const SkPaint
& paint
) {
43 c
->DrawImageIntInPixel(i
, 0, 0, ImageWidthInPixels(i
, c
),
44 ImageHeightInPixels(i
, c
), x
, y
, w
, h
, false, paint
);
49 NineImagePainter::NineImagePainter(const std::vector
<ImageSkia
>& images
) {
50 DCHECK_EQ(arraysize(images_
), images
.size());
51 for (size_t i
= 0; i
< arraysize(images_
); ++i
)
52 images_
[i
] = images
[i
];
55 NineImagePainter::NineImagePainter(const ImageSkia
& image
,
56 const Insets
& insets
) {
57 DCHECK_GE(image
.width(), insets
.width());
58 DCHECK_GE(image
.height(), insets
.height());
60 // Extract subsets of the original image to match the |images_| format.
62 { 0, insets
.left(), image
.width() - insets
.right(), image
.width() };
64 { 0, insets
.top(), image
.height() - insets
.bottom(), image
.height() };
66 for (size_t j
= 0; j
< 3; ++j
) {
67 for (size_t i
= 0; i
< 3; ++i
) {
68 images_
[i
+ j
* 3] = ImageSkiaOperations::ExtractSubset(image
,
69 Rect(x
[i
], y
[j
], x
[i
+ 1] - x
[i
], y
[j
+ 1] - y
[j
]));
74 NineImagePainter::~NineImagePainter() {
77 bool NineImagePainter::IsEmpty() const {
78 return images_
[0].isNull();
81 Size
NineImagePainter::GetMinimumSize() const {
82 return IsEmpty() ? Size() : Size(
83 images_
[0].width() + images_
[1].width() + images_
[2].width(),
84 images_
[0].height() + images_
[3].height() + images_
[6].height());
87 void NineImagePainter::Paint(Canvas
* canvas
, const Rect
& bounds
) {
88 // When no alpha value is specified, use default value of 100% opacity.
89 Paint(canvas
, bounds
, std::numeric_limits
<uint8
>::max());
92 void NineImagePainter::Paint(Canvas
* canvas
,
98 ScopedCanvas
scoped_canvas(canvas
);
99 canvas
->Translate(bounds
.OffsetFromOrigin());
102 paint
.setAlpha(alpha
);
104 // Get the current transform from the canvas and apply it to the logical
105 // bounds passed in. This will give us the pixel bounds which can be used
106 // to draw the images at the correct locations.
107 // We should not scale the bounds by the canvas->image_scale() as that can be
108 // different from the real scale in the canvas transform.
109 SkMatrix matrix
= canvas
->sk_canvas()->getTotalMatrix();
111 matrix
.mapRect(&scaled_rect
, RectToSkRect(bounds
));
113 int scaled_width
= gfx::ToCeiledInt(SkScalarToFloat(scaled_rect
.width()));
114 int scaled_height
= gfx::ToCeiledInt(SkScalarToFloat(scaled_rect
.height()));
116 // In case the corners and edges don't all have the same width/height, we draw
117 // the center first, and extend it out in all directions to the edges of the
118 // images with the smallest widths/heights. This way there will be no
119 // unpainted areas, though some corners or edges might overlap the center.
120 int i0w
= ImageWidthInPixels(images_
[0], canvas
);
121 int i2w
= ImageWidthInPixels(images_
[2], canvas
);
122 int i3w
= ImageWidthInPixels(images_
[3], canvas
);
123 int i5w
= ImageWidthInPixels(images_
[5], canvas
);
124 int i6w
= ImageWidthInPixels(images_
[6], canvas
);
125 int i8w
= ImageWidthInPixels(images_
[8], canvas
);
127 int i4x
= std::min(std::min(i0w
, i3w
), i6w
);
128 int i4w
= scaled_width
- i4x
- std::min(std::min(i2w
, i5w
), i8w
);
130 int i0h
= ImageHeightInPixels(images_
[0], canvas
);
131 int i1h
= ImageHeightInPixels(images_
[1], canvas
);
132 int i2h
= ImageHeightInPixels(images_
[2], canvas
);
133 int i6h
= ImageHeightInPixels(images_
[6], canvas
);
134 int i7h
= ImageHeightInPixels(images_
[7], canvas
);
135 int i8h
= ImageHeightInPixels(images_
[8], canvas
);
137 int i4y
= std::min(std::min(i0h
, i1h
), i2h
);
138 int i4h
= scaled_height
- i4y
- std::min(std::min(i6h
, i7h
), i8h
);
139 if (!images_
[4].isNull())
140 Fill(canvas
, images_
[4], i4x
, i4y
, i4w
, i4h
, paint
);
141 canvas
->DrawImageIntInPixel(images_
[0], 0, 0, i0w
, i0h
,
142 0, 0, i0w
, i0h
, false, paint
);
143 Fill(canvas
, images_
[1], i0w
, 0, scaled_width
- i0w
- i2w
, i1h
, paint
);
144 canvas
->DrawImageIntInPixel(images_
[2], 0, 0, i2w
, i2h
, scaled_width
- i2w
,
145 0, i2w
, i2h
, false, paint
);
146 Fill(canvas
, images_
[3], 0, i0h
, i3w
, scaled_height
- i0h
- i6h
, paint
);
147 Fill(canvas
, images_
[5], scaled_width
- i5w
, i2h
, i5w
,
148 scaled_height
- i2h
- i8h
, paint
);
149 canvas
->DrawImageIntInPixel(images_
[6], 0, 0, i6w
, i6h
, 0,
150 scaled_height
- i6h
, i6w
, i6h
, false, paint
);
151 Fill(canvas
, images_
[7], i6w
, scaled_height
- i7h
, scaled_width
- i6w
- i8w
,
153 canvas
->DrawImageIntInPixel(images_
[8], 0, 0, i8w
, i8h
, scaled_width
- i8w
,
154 scaled_height
- i8h
, i8w
, i8h
, false, paint
);