1 /*
2 * Copyright 2025 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 #include "tests/Test.h"
8
9 #include "include/core/SkCanvas.h"
10 #include "include/core/SkColorSpace.h"
11 #include "include/core/SkImageInfo.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkPixmap.h"
14 #include "include/core/SkSurface.h"
15 #include "src/core/SkBlitter.h"
16 #include "src/core/SkCoreBlitters.h"
17 #include "src/core/SkMask.h"
18
19 #include <memory>
20
all_pixels_same_color(uint32_t * buffer,size_t len)21 static bool all_pixels_same_color(uint32_t* buffer, size_t len) {
22 for (size_t i = 1; i < len; ++i) {
23 if (buffer[0] != buffer[i]) {
24 return false;
25 }
26 }
27 return true;
28 }
29
30 using BlitterFactory = std::unique_ptr<SkBlitter> (*)(const SkPixmap&, const SkPaint&);
31
compare_mask_and_antiH(skiatest::Reporter * reporter,SkColor backgroundColor,SkColor paintColor,BlitterFactory makeBlitter)32 static void compare_mask_and_antiH(skiatest::Reporter* reporter,
33 SkColor backgroundColor,
34 SkColor paintColor,
35 BlitterFactory makeBlitter) {
36 // 19 is big enough to exercise any multi-lane code (e.g. SIMD/NEON)
37 // and have some remainder to exercise single-pixel code.
38 constexpr size_t kPixelsToBlit = 19;
39 static_assert(kPixelsToBlit % 4 != 0);
40 static_assert(kPixelsToBlit % 8 != 0);
41 static_assert(kPixelsToBlit % 16 != 0);
42
43 // Space for a kPixelsToBlit by 1 pixel image of 8888 color
44 SkColor buffer1[kPixelsToBlit * 1];
45 SkColor buffer2[kPixelsToBlit * 1];
46 auto ii = SkImageInfo::Make(
47 {kPixelsToBlit, 1},
48 SkColorInfo(kN32_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB()));
49
50 SkPixmap device1(ii, buffer1, ii.minRowBytes());
51 auto surface1 = SkSurfaces::WrapPixels(device1);
52 SkASSERT(surface1);
53
54 SkPixmap device2(ii, buffer2, ii.minRowBytes());
55 auto surface2 = SkSurfaces::WrapPixels(device2);
56 SkASSERT(surface2);
57
58 SkPaint paint;
59 paint.setColor(paintColor);
60
61 auto blitter1 = makeBlitter(device1, paint);
62 SkASSERT(blitter1);
63 auto blitter2 = makeBlitter(device2, paint);
64 SkASSERT(blitter2);
65
66 SkAlpha antiAlias[1];
67 // The blitAntiH needs a buffer where the first value is the number of pixels
68 // to blit and then at least that many 0s so we don't read off the end of the
69 // buffer to figure out we need to stop.
70 int16_t runs[kPixelsToBlit+1] = {kPixelsToBlit};
71
72 uint8_t maskImage[kPixelsToBlit];
73 auto maskBounds = SkIRect::MakeXYWH(0, 0, kPixelsToBlit, 1);
74 for (int alpha = 0; alpha <= 255; ++alpha) {
75 antiAlias[0] = static_cast<SkAlpha>(alpha);
76 std::fill_n(maskImage, kPixelsToBlit, static_cast<SkAlpha>(alpha));
77
78 SkMask mask(maskImage, maskBounds, kPixelsToBlit, SkMask::kA8_Format);
79
80 surface1->getCanvas()->clear(backgroundColor);
81 blitter1->blitAntiH(0, 0, antiAlias, runs);
82
83 surface2->getCanvas()->clear(backgroundColor);
84 blitter2->blitMask(mask, mask.fBounds);
85
86 if (!all_pixels_same_color(buffer1, std::size(buffer1))) {
87 REPORT_FAILURE(reporter,
88 "blitAntiH was not the same for all pixels",
89 SkStringPrintf("background=%08x, paint=%08x, alpha=%d",
90 backgroundColor,
91 paintColor,
92 alpha));
93 return;
94 }
95 if (!all_pixels_same_color(buffer2, std::size(buffer2))) {
96 REPORT_FAILURE(reporter,
97 "blitMask was not the same for all pixels",
98 SkStringPrintf("background=%08x, paint=%08x, alpha=%d",
99 backgroundColor,
100 paintColor,
101 alpha));
102 return;
103 }
104
105 SkColor antiHColor = buffer1[0];
106 SkColor maskColor = buffer2[0];
107
108 REPORTER_ASSERT(reporter,
109 antiHColor == maskColor,
110 "background=%08x, paint=%08x, alpha=%d, "
111 "blitAntiH=%08x, blitMask=%08x, "
112 "diff=%02x %02x %02x %02x",
113 backgroundColor, paintColor, alpha,
114 antiHColor, maskColor,
115 abs((int)(SkColorGetA(antiHColor) - SkColorGetA(maskColor))),
116 abs((int)(SkColorGetR(antiHColor) - SkColorGetR(maskColor))),
117 abs((int)(SkColorGetG(antiHColor) - SkColorGetG(maskColor))),
118 abs((int)(SkColorGetB(antiHColor) - SkColorGetB(maskColor))));
119 }
120 }
121
DEF_TEST(SkARGB32OpaqueBlitter_MaskAndAntiHDrawTheSame,r)122 DEF_TEST(SkARGB32OpaqueBlitter_MaskAndAntiHDrawTheSame, r) {
123 SkColor backgroundColors[] = {
124 SK_ColorWHITE, SK_ColorBLACK, SK_ColorGRAY,
125 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
126 SK_ColorYELLOW, SK_ColorCYAN, SK_ColorMAGENTA,
127 // arbitrary opaque color with uneven channels
128 SkColorSetARGB(255, 255 / 4, 255 / 3, 255 / 2),
129 };
130 SkColor paintColors[] = {
131 SK_ColorWHITE, SK_ColorBLACK, SK_ColorGRAY,
132 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
133 SK_ColorYELLOW, SK_ColorCYAN, SK_ColorMAGENTA,
134 SkColorSetARGB(255, 255 / 4, 255 / 3, 255 / 2),
135 };
136
137 for (SkColor backgroundColor : backgroundColors) {
138 for (SkColor paintColor : paintColors) {
139 compare_mask_and_antiH(r,
140 backgroundColor,
141 paintColor,
142 [](const SkPixmap& device, const SkPaint& paint) -> std::unique_ptr<SkBlitter> {
143 return std::make_unique<SkARGB32_Opaque_Blitter>(device, paint);
144 });
145 }
146 }
147 }
148
DEF_TEST(SkARGB32BlackBlitter_MaskAndAntiHDrawTheSame,r)149 DEF_TEST(SkARGB32BlackBlitter_MaskAndAntiHDrawTheSame, r) {
150 SkColor backgroundColors[] = {
151 SK_ColorWHITE, SK_ColorBLACK, SK_ColorGRAY,
152 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
153 SK_ColorYELLOW, SK_ColorCYAN, SK_ColorMAGENTA,
154 // arbitrary opaque color with uneven channels
155 SkColorSetARGB(255, 255 / 4, 255 / 3, 255 / 2),
156 };
157
158 for (SkColor backgroundColor : backgroundColors) {
159 compare_mask_and_antiH(r,
160 backgroundColor,
161 SK_ColorBLACK,
162 [](const SkPixmap& device, const SkPaint& paint) -> std::unique_ptr<SkBlitter> {
163 return std::make_unique<SkARGB32_Black_Blitter>(device, paint);
164 });
165 }
166 }
167
DEF_TEST(SkARGB32Blitter_MaskAndAntiHDrawTheSame,r)168 DEF_TEST(SkARGB32Blitter_MaskAndAntiHDrawTheSame, r) {
169 SkColor backgroundColors[] = {
170 SK_ColorWHITE, SK_ColorBLACK, SK_ColorGRAY,
171 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
172 SK_ColorYELLOW, SK_ColorCYAN, SK_ColorMAGENTA,
173 // arbitrary opaque color with uneven channels
174 SkColorSetARGB(255, 255 / 4, 255 / 3, 255 / 2),
175 };
176 SkColor paintColors[] = {
177 SK_ColorWHITE, SK_ColorBLACK, SK_ColorGRAY,
178 SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE,
179 SK_ColorYELLOW, SK_ColorCYAN, SK_ColorMAGENTA,
180 SkColorSetARGB(255, 255 / 4, 255 / 3, 255 / 2),
181 };
182 SkAlpha alphaValues[] = {
183 0, 10, 100, 200, 245 /*SkARGB32_Opaque_Blitter is used when alpha is 255*/
184 };
185
186 for (SkColor backgroundColor : backgroundColors) {
187 for (SkColor paintColor : paintColors) {
188 for (SkAlpha alpha : alphaValues) {
189 SkColor newColor = SkColorSetA(paintColor, alpha);
190 compare_mask_and_antiH(r,
191 backgroundColor,
192 newColor,
193 [](const SkPixmap& device, const SkPaint& paint) -> std::unique_ptr<SkBlitter> {
194 return std::make_unique<SkARGB32_Blitter>(device, paint);
195 });
196 }
197 }
198 }
199 }
200