blob: 9a810458b8e664a77864023297a3375cb8ba9c0f [file] [log] [blame]
Avi Drissman3e1a26c2022-09-15 20:26:031// Copyright 2015 The Chromium Authors
sky18d069d2015-03-13 22:41:372// 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/gfx/nine_image_painter.h"
6
danakj4bfbb342015-10-29 23:38:257#include "base/base64.h"
Tom Sepez207184ff2024-02-01 16:58:008#include "base/strings/strcat.h"
sky18d069d2015-03-13 22:41:379#include "testing/gtest/include/gtest/gtest.h"
qiankun.miaoa1757032015-04-03 08:02:1310#include "ui/gfx/canvas.h"
danakj4bfbb342015-10-29 23:38:2511#include "ui/gfx/codec/png_codec.h"
sky18d069d2015-03-13 22:41:3712#include "ui/gfx/geometry/insets.h"
13#include "ui/gfx/geometry/rect.h"
danakj4bfbb342015-10-29 23:38:2514#include "ui/gfx/geometry/vector2d.h"
15#include "ui/gfx/geometry/vector2d_conversions.h"
qiankun.miaoa1757032015-04-03 08:02:1316#include "ui/gfx/image/image_skia.h"
David Sanders03ee601f2022-02-22 02:23:0017#include "ui/gfx/image/image_skia_rep.h"
Henrique Ferreiro285ba452023-12-04 14:24:1918#include "ui/gfx/image/image_unittest_util.h"
sky18d069d2015-03-13 22:41:3719
20namespace gfx {
21
danakj4bfbb342015-10-29 23:38:2522static std::string GetPNGDataUrl(const SkBitmap& bitmap) {
Avi Drissmane7f1efd2024-10-17 07:17:5223 std::optional<std::vector<uint8_t>> png_data =
24 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap,
25 /*discard_transparency=*/false);
26 return base::StrCat(
27 {"data:image/png;base64,",
28 base::Base64Encode(png_data.value_or(std::vector<uint8_t>()))});
danakj4bfbb342015-10-29 23:38:2529}
30
31void ExpectRedWithGreenRect(const SkBitmap& bitmap,
32 const Rect& outer_rect,
33 const Rect& green_rect) {
34 for (int y = outer_rect.y(); y < outer_rect.bottom(); y++) {
35 SCOPED_TRACE(y);
36 for (int x = outer_rect.x(); x < outer_rect.right(); x++) {
37 SCOPED_TRACE(x);
38 if (green_rect.Contains(x, y)) {
39 ASSERT_EQ(SK_ColorGREEN, bitmap.getColor(x, y))
40 << "Output image:\n" << GetPNGDataUrl(bitmap);
41 } else {
42 ASSERT_EQ(SK_ColorRED, bitmap.getColor(x, y)) << "Output image:\n"
43 << GetPNGDataUrl(bitmap);
44 }
45 }
46 }
47}
48
sky18d069d2015-03-13 22:41:3749TEST(NineImagePainterTest, GetSubsetRegions) {
50 SkBitmap src;
51 src.allocN32Pixels(40, 50);
52 const ImageSkia image_skia(ImageSkiaRep(src, 1.0));
Xianzhu Wangda5e8302022-03-29 13:43:3753 const auto insets = gfx::Insets::TLBR(1, 2, 3, 4);
sky18d069d2015-03-13 22:41:3754 std::vector<Rect> rects;
55 NineImagePainter::GetSubsetRegions(image_skia, insets, &rects);
56 ASSERT_EQ(9u, rects.size());
57 EXPECT_EQ(gfx::Rect(0, 0, 2, 1), rects[0]);
58 EXPECT_EQ(gfx::Rect(2, 0, 34, 1), rects[1]);
59 EXPECT_EQ(gfx::Rect(36, 0, 4, 1), rects[2]);
60 EXPECT_EQ(gfx::Rect(0, 1, 2, 46), rects[3]);
61 EXPECT_EQ(gfx::Rect(2, 1, 34, 46), rects[4]);
62 EXPECT_EQ(gfx::Rect(36, 1, 4, 46), rects[5]);
63 EXPECT_EQ(gfx::Rect(0, 47, 2, 3), rects[6]);
64 EXPECT_EQ(gfx::Rect(2, 47, 34, 3), rects[7]);
65 EXPECT_EQ(gfx::Rect(36, 47, 4, 3), rects[8]);
66}
67
danakj4bfbb342015-10-29 23:38:2568TEST(NineImagePainterTest, PaintHighDPI) {
Henrique Ferreiro285ba452023-12-04 14:24:1969 SkBitmap src = gfx::test::CreateBitmap(/*size=*/100, SK_ColorRED);
qiankun.miaoa1757032015-04-03 08:02:1370 src.eraseArea(SkIRect::MakeXYWH(10, 10, 80, 80), SK_ColorGREEN);
71
danakj4bfbb342015-10-29 23:38:2572 float image_scale = 2.f;
73
danakjd18e8892020-12-17 17:42:0174 gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale);
Xianzhu Wangda5e8302022-03-29 13:43:3775 gfx::Insets insets(10);
qiankun.miaoa1757032015-04-03 08:02:1376 gfx::NineImagePainter painter(image, insets);
77
qiankun.miaoa1757032015-04-03 08:02:1378 bool is_opaque = true;
danakj4bfbb342015-10-29 23:38:2579 gfx::Canvas canvas(gfx::Size(100, 100), image_scale, is_opaque);
qiankun.miaoa1757032015-04-03 08:02:1380
danakj4bfbb342015-10-29 23:38:2581 gfx::Vector2d offset(20, 10);
82 canvas.Translate(offset);
83
84 gfx::Rect bounds(0, 0, 50, 50);
qiankun.miaoa1757032015-04-03 08:02:1385 painter.Paint(&canvas, bounds);
86
vmpstr4f767492017-03-22 21:24:0887 SkBitmap result = canvas.GetBitmap();
qiankun.miaoa1757032015-04-03 08:02:1388
danakj4bfbb342015-10-29 23:38:2589 gfx::Vector2d paint_offset =
90 gfx::ToFlooredVector2d(gfx::ScaleVector2d(offset, image_scale));
91 gfx::Rect green_rect = gfx::Rect(10, 10, 80, 80) + paint_offset;
92 gfx::Rect outer_rect = gfx::Rect(100, 100) + paint_offset;
93 ExpectRedWithGreenRect(result, outer_rect, green_rect);
qiankun.miaoa1757032015-04-03 08:02:1394}
95
skobesbc49adcb2015-09-28 23:30:1796TEST(NineImagePainterTest, PaintStaysInBounds) {
97 // In this test the bounds rect is 1x1 but each image is 2x2.
98 // The NineImagePainter should not paint outside the bounds.
skobes453d3392015-10-30 22:42:3299 // The border images should be cropped, but still painted.
skobesbc49adcb2015-09-28 23:30:17100
Henrique Ferreiro285ba452023-12-04 14:24:19101 SkBitmap src = gfx::test::CreateBitmap(/*size=*/6, SK_ColorGREEN);
skobes453d3392015-10-30 22:42:32102 src.erase(SK_ColorRED, SkIRect::MakeXYWH(2, 2, 2, 2));
skobesbc49adcb2015-09-28 23:30:17103
danakjd18e8892020-12-17 17:42:01104 gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(src);
Xianzhu Wangda5e8302022-03-29 13:43:37105 gfx::Insets insets(2);
skobesbc49adcb2015-09-28 23:30:17106 gfx::NineImagePainter painter(image, insets);
107
108 int image_scale = 1;
109 bool is_opaque = true;
110 gfx::Canvas canvas(gfx::Size(3, 3), image_scale, is_opaque);
111 canvas.DrawColor(SK_ColorBLACK);
112
113 gfx::Rect bounds(1, 1, 1, 1);
114 painter.Paint(&canvas, bounds);
115
vmpstr4f767492017-03-22 21:24:08116 SkBitmap result = canvas.GetBitmap();
skobesbc49adcb2015-09-28 23:30:17117
skobes453d3392015-10-30 22:42:32118 EXPECT_EQ(SK_ColorGREEN, result.getColor(1, 1));
skobesbc49adcb2015-09-28 23:30:17119
120 EXPECT_EQ(SK_ColorBLACK, result.getColor(0, 0));
121 EXPECT_EQ(SK_ColorBLACK, result.getColor(0, 1));
122 EXPECT_EQ(SK_ColorBLACK, result.getColor(0, 2));
123 EXPECT_EQ(SK_ColorBLACK, result.getColor(1, 0));
124 EXPECT_EQ(SK_ColorBLACK, result.getColor(1, 2));
125 EXPECT_EQ(SK_ColorBLACK, result.getColor(2, 0));
126 EXPECT_EQ(SK_ColorBLACK, result.getColor(2, 1));
127 EXPECT_EQ(SK_ColorBLACK, result.getColor(2, 2));
128}
129
weili586d6ab2015-10-13 07:07:31130TEST(NineImagePainterTest, PaintWithBoundOffset) {
Henrique Ferreiro285ba452023-12-04 14:24:19131 SkBitmap src = gfx::test::CreateBitmap(/*size=*/10, SK_ColorRED);
weili586d6ab2015-10-13 07:07:31132 src.eraseArea(SkIRect::MakeXYWH(1, 1, 8, 8), SK_ColorGREEN);
133
danakjd18e8892020-12-17 17:42:01134 gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(src);
Xianzhu Wangda5e8302022-03-29 13:43:37135 gfx::Insets insets(1);
weili586d6ab2015-10-13 07:07:31136 gfx::NineImagePainter painter(image, insets);
137
138 bool is_opaque = true;
139 gfx::Canvas canvas(gfx::Size(10, 10), 1, is_opaque);
140
141 gfx::Rect bounds(1, 1, 10, 10);
142 painter.Paint(&canvas, bounds);
143
vmpstr4f767492017-03-22 21:24:08144 SkBitmap result = canvas.GetBitmap();
weili586d6ab2015-10-13 07:07:31145
146 SkIRect green_rect = SkIRect::MakeLTRB(2, 2, 10, 10);
147 for (int y = 1; y < 10; y++) {
148 for (int x = 1; x < 10; x++) {
149 if (green_rect.contains(x, y)) {
150 ASSERT_EQ(SK_ColorGREEN, result.getColor(x, y));
151 } else {
152 ASSERT_EQ(SK_ColorRED, result.getColor(x, y));
153 }
154 }
155 }
156}
157
danakj4bfbb342015-10-29 23:38:25158TEST(NineImagePainterTest, PaintWithScale) {
Henrique Ferreiro285ba452023-12-04 14:24:19159 SkBitmap src = gfx::test::CreateBitmap(/*size=*/100, SK_ColorRED);
weili586d6ab2015-10-13 07:07:31160 src.eraseArea(SkIRect::MakeXYWH(10, 10, 80, 80), SK_ColorGREEN);
161
danakj4bfbb342015-10-29 23:38:25162 float image_scale = 2.f;
163
danakjd18e8892020-12-17 17:42:01164 gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale);
Xianzhu Wangda5e8302022-03-29 13:43:37165 gfx::Insets insets(10);
weili586d6ab2015-10-13 07:07:31166 gfx::NineImagePainter painter(image, insets);
167
weili586d6ab2015-10-13 07:07:31168 bool is_opaque = true;
169 gfx::Canvas canvas(gfx::Size(400, 400), image_scale, is_opaque);
weili586d6ab2015-10-13 07:07:31170
danakj4bfbb342015-10-29 23:38:25171 gfx::Vector2d offset(20, 10);
172 canvas.Translate(offset);
173 canvas.Scale(2, 1);
174
175 gfx::Rect bounds(0, 0, 50, 50);
weili586d6ab2015-10-13 07:07:31176 painter.Paint(&canvas, bounds);
177
vmpstr4f767492017-03-22 21:24:08178 SkBitmap result = canvas.GetBitmap();
weili586d6ab2015-10-13 07:07:31179
danakj4bfbb342015-10-29 23:38:25180 gfx::Vector2d paint_offset =
181 gfx::ToFlooredVector2d(gfx::ScaleVector2d(offset, image_scale));
182 gfx::Rect green_rect = gfx::Rect(20, 10, 160, 80) + paint_offset;
183 gfx::Rect outer_rect = gfx::Rect(200, 100) + paint_offset;
184 ExpectRedWithGreenRect(result, outer_rect, green_rect);
185}
186
187TEST(NineImagePainterTest, PaintWithNegativeScale) {
Henrique Ferreiro285ba452023-12-04 14:24:19188 SkBitmap src = gfx::test::CreateBitmap(/*size=*/100, SK_ColorRED);
danakj4bfbb342015-10-29 23:38:25189 src.eraseArea(SkIRect::MakeXYWH(10, 10, 80, 80), SK_ColorGREEN);
190
191 float image_scale = 2.f;
192
danakjd18e8892020-12-17 17:42:01193 gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale);
Xianzhu Wangda5e8302022-03-29 13:43:37194 gfx::Insets insets(10);
danakj4bfbb342015-10-29 23:38:25195 gfx::NineImagePainter painter(image, insets);
196
197 bool is_opaque = true;
198 gfx::Canvas canvas(gfx::Size(400, 400), image_scale, is_opaque);
199 canvas.Translate(gfx::Vector2d(70, 60));
200 canvas.Scale(-1, -1);
201
202 gfx::Rect bounds(0, 0, 50, 50);
203 painter.Paint(&canvas, bounds);
204
vmpstr4f767492017-03-22 21:24:08205 SkBitmap result = canvas.GetBitmap();
danakj4bfbb342015-10-29 23:38:25206
207 // The painting space is 50x50 and the scale of -1,-1 means an offset of 50,50
208 // would put the output in the top left corner. Since the offset is 70,60 it
209 // moves by 20,10. Since the output is 2x DPI it will become offset by 40,20.
210 gfx::Vector2d paint_offset(40, 20);
211 gfx::Rect green_rect = gfx::Rect(10, 10, 80, 80) + paint_offset;
212 gfx::Rect outer_rect = gfx::Rect(100, 100) + paint_offset;
213 ExpectRedWithGreenRect(result, outer_rect, green_rect);
weili586d6ab2015-10-13 07:07:31214}
215
sky18d069d2015-03-13 22:41:37216} // namespace gfx