| Flutter Impeller |

skia_conversions_unittests.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter 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 "display_list/dl_blend_mode.h"
6 #include "display_list/dl_color.h"
7 #include "display_list/dl_tile_mode.h"
8 #include "flutter/testing/testing.h"
9 #include "impeller/core/formats.h"
10 #include "impeller/display_list/skia_conversions.h"
11 #include "impeller/geometry/color.h"
12 #include "impeller/geometry/scalar.h"
13 #include "include/core/SkMatrix.h"
14 #include "include/core/SkRRect.h"
15
16 namespace impeller {
17 namespace testing {
18
19 TEST(SkiaConversionTest, ToMatrixTranslate) {
20 SkMatrix sk_matrix = SkMatrix::Translate(100, 100);
21 Matrix matrix = skia_conversions::ToMatrix(sk_matrix);
22
23 EXPECT_EQ(matrix.m[12], 100);
24 EXPECT_EQ(matrix.m[13], 100);
25 EXPECT_TRUE(matrix.IsTranslationScaleOnly());
26
27 matrix.m[12] = 0;
28 matrix.m[13] = 0;
29
30 EXPECT_TRUE(matrix.IsIdentity());
31 }
32
33 TEST(SkiaConversionTest, ToMatrixScale) {
34 SkMatrix sk_matrix = SkMatrix::Scale(2, 2);
35 Matrix matrix = skia_conversions::ToMatrix(sk_matrix);
36
37 EXPECT_EQ(matrix.m[0], 2);
38 EXPECT_EQ(matrix.m[5], 2);
39 EXPECT_TRUE(matrix.IsTranslationScaleOnly());
40
41 matrix.m[0] = 1;
42 matrix.m[5] = 1;
43
44 EXPECT_TRUE(matrix.IsIdentity());
45 }
46
47 TEST(SkiaConversionTest, ToMatrixRotate) {
48 SkMatrix sk_matrix = SkMatrix::RotateDeg(90);
49 Matrix matrix = skia_conversions::ToMatrix(sk_matrix);
50
51 EXPECT_EQ(matrix.vec[0], Vector4(0, 1, 0, 0));
52 EXPECT_EQ(matrix.vec[1], Vector4(-1, 0, 0, 0));
53 EXPECT_EQ(matrix.vec[2], Vector4(0, 0, 1, 0));
54 EXPECT_EQ(matrix.vec[3], Vector4(0, 0, 0, 1));
55 EXPECT_FALSE(matrix.IsTranslationScaleOnly());
56 }
57
58 TEST(SkiaConversionTest, ToMatrixSkew) {
59 SkMatrix sk_matrix = SkMatrix::Skew(2, 2);
60 Matrix matrix = skia_conversions::ToMatrix(sk_matrix);
61
62 EXPECT_EQ(matrix.vec[0], Vector4(1, 2, 0, 0));
63 EXPECT_EQ(matrix.vec[1], Vector4(2, 1, 0, 0));
64 EXPECT_EQ(matrix.vec[2], Vector4(0, 0, 1, 0));
65 EXPECT_EQ(matrix.vec[3], Vector4(0, 0, 0, 1));
66 EXPECT_FALSE(matrix.IsTranslationScaleOnly());
67 }
68
69 TEST(SkiaConversionTest, ToSamplerDescriptor) {
70 EXPECT_EQ(skia_conversions::ToSamplerDescriptor(
71 flutter::DlImageSampling::kNearestNeighbor)
72 .min_filter,
73 impeller::MinMagFilter::kNearest);
74 EXPECT_EQ(skia_conversions::ToSamplerDescriptor(
75 flutter::DlImageSampling::kNearestNeighbor)
76 .mip_filter,
77 impeller::MipFilter::kBase);
78
79 EXPECT_EQ(
80 skia_conversions::ToSamplerDescriptor(flutter::DlImageSampling::kLinear)
81 .min_filter,
82 impeller::MinMagFilter::kLinear);
83 EXPECT_EQ(
84 skia_conversions::ToSamplerDescriptor(flutter::DlImageSampling::kLinear)
85 .mip_filter,
86 impeller::MipFilter::kBase);
87
88 EXPECT_EQ(skia_conversions::ToSamplerDescriptor(
89 flutter::DlImageSampling::kMipmapLinear)
90 .min_filter,
91 impeller::MinMagFilter::kLinear);
92 EXPECT_EQ(skia_conversions::ToSamplerDescriptor(
93 flutter::DlImageSampling::kMipmapLinear)
94 .mip_filter,
95 impeller::MipFilter::kLinear);
96 }
97
98 TEST(SkiaConversionsTest, SkPointToPoint) {
99 for (int x = -100; x < 100; x += 4) {
100 for (int y = -100; y < 100; y += 4) {
101 EXPECT_EQ(skia_conversions::ToPoint(SkPoint::Make(x * 0.25f, y * 0.25f)),
102 Point(x * 0.25f, y * 0.25f));
103 }
104 }
105 }
106
107 TEST(SkiaConversionsTest, SkPointToSize) {
108 for (int x = -100; x < 100; x += 4) {
109 for (int y = -100; y < 100; y += 4) {
110 EXPECT_EQ(skia_conversions::ToSize(SkPoint::Make(x * 0.25f, y * 0.25f)),
111 Size(x * 0.25f, y * 0.25f));
112 }
113 }
114 }
115
116 TEST(SkiaConversionsTest, ToColor) {
117 // Create a color with alpha, red, green, and blue values that are all
118 // trivially divisible by 255 so that we can test the conversion results in
119 // correct scalar values.
120 // AARRGGBB
121 const flutter::DlColor color = flutter::DlColor(0x8040C020);
122 auto converted_color = skia_conversions::ToColor(color);
123
124 ASSERT_TRUE(ScalarNearlyEqual(converted_color.alpha, 0x80 * (1.0f / 255)));
125 ASSERT_TRUE(ScalarNearlyEqual(converted_color.red, 0x40 * (1.0f / 255)));
126 ASSERT_TRUE(ScalarNearlyEqual(converted_color.green, 0xC0 * (1.0f / 255)));
127 ASSERT_TRUE(ScalarNearlyEqual(converted_color.blue, 0x20 * (1.0f / 255)));
128 }
129
130 TEST(SkiaConversionsTest, GradientStopConversion) {
131 // Typical gradient.
132 std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
133 flutter::DlColor::kRed(),
134 flutter::DlColor::kGreen()};
135 std::vector<float> stops = {0.0, 0.5, 1.0};
136 const auto gradient =
137 flutter::DlColorSource::MakeLinear(SkPoint::Make(0, 0), //
138 SkPoint::Make(1.0, 1.0), //
139 3, //
140 colors.data(), //
141 stops.data(), //
142 flutter::DlTileMode::kClamp, //
143 nullptr //
144 );
145
146 std::vector<Color> converted_colors;
147 std::vector<Scalar> converted_stops;
148 skia_conversions::ConvertStops(gradient.get(), converted_colors,
149 converted_stops);
150
151 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f));
152 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f));
153 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f));
154 }
155
156 TEST(SkiaConversionsTest, GradientMissing0) {
157 std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
158 flutter::DlColor::kRed()};
159 std::vector<float> stops = {0.5, 1.0};
160 const auto gradient =
161 flutter::DlColorSource::MakeLinear(SkPoint::Make(0, 0), //
162 SkPoint::Make(1.0, 1.0), //
163 2, //
164 colors.data(), //
165 stops.data(), //
166 flutter::DlTileMode::kClamp, //
167 nullptr //
168 );
169
170 std::vector<Color> converted_colors;
171 std::vector<Scalar> converted_stops;
172 skia_conversions::ConvertStops(gradient.get(), converted_colors,
173 converted_stops);
174
175 // First color is inserted as blue.
176 ASSERT_TRUE(ScalarNearlyEqual(converted_colors[0].blue, 1.0f));
177 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f));
178 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f));
179 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f));
180 }
181
182 TEST(SkiaConversionsTest, GradientMissingLastValue) {
183 std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
184 flutter::DlColor::kRed()};
185 std::vector<float> stops = {0.0, .5};
186 const auto gradient =
187 flutter::DlColorSource::MakeLinear(SkPoint::Make(0, 0), //
188 SkPoint::Make(1.0, 1.0), //
189 2, //
190 colors.data(), //
191 stops.data(), //
192 flutter::DlTileMode::kClamp, //
193 nullptr //
194 );
195
196 std::vector<Color> converted_colors;
197 std::vector<Scalar> converted_stops;
198 skia_conversions::ConvertStops(gradient.get(), converted_colors,
199 converted_stops);
200
201 // Last color is inserted as red.
202 ASSERT_TRUE(ScalarNearlyEqual(converted_colors[2].red, 1.0f));
203 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f));
204 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f));
205 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f));
206 }
207
208 TEST(SkiaConversionsTest, GradientStopGreaterThan1) {
209 std::vector<flutter::DlColor> colors = {flutter::DlColor::kBlue(),
210 flutter::DlColor::kGreen(),
211 flutter::DlColor::kRed()};
212 std::vector<float> stops = {0.0, 100, 1.0};
213 const auto gradient =
214 flutter::DlColorSource::MakeLinear(SkPoint::Make(0, 0), //
215 SkPoint::Make(1.0, 1.0), //
216 3, //
217 colors.data(), //
218 stops.data(), //
219 flutter::DlTileMode::kClamp, //
220 nullptr //
221 );
222
223 std::vector<Color> converted_colors;
224 std::vector<Scalar> converted_stops;
225 skia_conversions::ConvertStops(gradient.get(), converted_colors,
226 converted_stops);
227
228 // Value is clamped to 1.0
229 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f));
230 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 1.0f));
231 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 1.0f));
232 }
233
234 TEST(SkiaConversionsTest, GradientConversionNonMonotonic) {
235 std::vector<flutter::DlColor> colors = {
236 flutter::DlColor::kBlue(), flutter::DlColor::kGreen(),
237 flutter::DlColor::kGreen(), flutter::DlColor::kRed()};
238 std::vector<float> stops = {0.0, 0.5, 0.4, 1.0};
239 const auto gradient =
240 flutter::DlColorSource::MakeLinear(SkPoint::Make(0, 0), //
241 SkPoint::Make(1.0, 1.0), //
242 4, //
243 colors.data(), //
244 stops.data(), //
245 flutter::DlTileMode::kClamp, //
246 nullptr //
247 );
248
249 std::vector<Color> converted_colors;
250 std::vector<Scalar> converted_stops;
251 skia_conversions::ConvertStops(gradient.get(), converted_colors,
252 converted_stops);
253
254 // Value is clamped to 0.5
255 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[0], 0.0f));
256 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[1], 0.5f));
257 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[2], 0.5f));
258 ASSERT_TRUE(ScalarNearlyEqual(converted_stops[3], 1.0f));
259 }
260
261 TEST(SkiaConversionsTest, IsNearlySimpleRRect) {
262 EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect(
263 SkRRect::MakeRectXY(SkRect::MakeLTRB(0, 0, 10, 10), 10, 10)));
264 EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect(
265 SkRRect::MakeRectXY(SkRect::MakeLTRB(0, 0, 10, 10), 10, 9.999)));
266 EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect(
267 SkRRect::MakeRectXY(SkRect::MakeLTRB(0, 0, 10, 10), 10, 9)));
268 EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect(
269 SkRRect::MakeRectXY(SkRect::MakeLTRB(0, 0, 10, 10), 10, 5)));
270 SkRect rect = SkRect::MakeLTRB(0, 0, 10, 10);
271 SkRRect rrect;
272 union {
273 SkPoint radii[4] = {
274 {10.0f, 9.0f},
275 {10.0f, 9.0f},
276 {10.0f, 9.0f},
277 {10.0f, 9.0f},
278 };
279 SkScalar values[8];
280 } test;
281 rrect.setRectRadii(rect, test.radii);
282 EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect(rrect));
283 for (int i = 0; i < 8; i++) {
284 auto save = test.values[i];
285 test.values[i] -= kEhCloseEnough * 0.5f;
286 rrect.setRectRadii(rect, test.radii);
287 EXPECT_TRUE(skia_conversions::IsNearlySimpleRRect(rrect))
288 << "values[" << i << "] == " << test.values[i];
289 test.values[i] -= kEhCloseEnough * 2.0f;
290 rrect.setRectRadii(rect, test.radii);
291 EXPECT_FALSE(skia_conversions::IsNearlySimpleRRect(rrect))
292 << "values[" << i << "] == " << test.values[i];
293 test.values[i] = save;
294 }
295 }
296
297 TEST(SkiaConversionsTest, BlendMode) {
298 for (auto i = 0; i < static_cast<int>(flutter::DlBlendMode::kLastMode); i++) {
299 EXPECT_EQ(
300 skia_conversions::ToBlendMode(static_cast<flutter::DlBlendMode>(i)),
301 static_cast<BlendMode>(i));
302 }
303 }
304
305 } // namespace testing
306 } // namespace impeller
impeller::Matrix::m
Scalar m[16]
Definition: matrix.h:39
impeller::skia_conversions::IsNearlySimpleRRect
bool IsNearlySimpleRRect(const SkRRect &rr)
Like SkRRect.isSimple, but allows the corners to differ by kEhCloseEnough.
Definition: skia_conversions.cc:21
impeller::skia_conversions::ConvertStops
void ConvertStops(const flutter::DlGradientColorSourceBase *gradient, std::vector< Color > &colors, std::vector< float > &stops)
Convert display list colors + stops into impeller colors and stops, taking care to ensure that the st...
Definition: skia_conversions.cc:144
impeller::skia_conversions::ToSize
Size ToSize(const SkPoint &point)
Definition: skia_conversions.cc:102
impeller::BlendMode
BlendMode
Definition: color.h:58
impeller::skia_conversions::ToSamplerDescriptor
impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlImageSampling options)
Definition: skia_conversions.cc:169
impeller::kEhCloseEnough
constexpr float kEhCloseEnough
Definition: constants.h:56
impeller::Vector4
Definition: vector.h:232
impeller::skia_conversions::ToMatrix
Matrix ToMatrix(const SkMatrix &m)
Definition: skia_conversions.cc:193
formats.h
impeller::skia_conversions::ToColor
Color ToColor(const flutter::DlColor &color)
Definition: skia_conversions.cc:106
impeller::Size
TSize< Scalar > Size
Definition: size.h:137
impeller::skia_conversions::ToBlendMode
BlendMode ToBlendMode(flutter::DlBlendMode mode)
Definition: skia_conversions.cc:204
impeller::Matrix::vec
Vector4 vec[4]
Definition: matrix.h:41
impeller::MinMagFilter::kNearest
@ kNearest
Select nearest to the sample point. Most widely supported.
impeller::ToSamplerDescriptor
static impeller::SamplerDescriptor ToSamplerDescriptor(const flutter::DlFilterMode options)
Definition: dl_dispatcher.cc:118
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
skia_conversions.h
impeller::MinMagFilter::kLinear
@ kLinear
impeller::Matrix::IsTranslationScaleOnly
constexpr bool IsTranslationScaleOnly() const
Returns true if the matrix has a scale-only basis and is non-projective. Note that an identity matrix...
Definition: matrix.h:397
impeller::skia_conversions::ToPoint
Point ToPoint(const SkPoint &point)
Definition: skia_conversions.cc:98
impeller::Matrix::IsIdentity
constexpr bool IsIdentity() const
Definition: matrix.h:384
scalar.h
impeller::MipFilter::kBase
@ kBase
The texture is sampled as if it only had a single mipmap level.
impeller::MipFilter::kLinear
@ kLinear
Sample from the two nearest mip levels and linearly interpolate.
impeller::ScalarNearlyEqual
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
Definition: scalar.h:35
color.h
color
DlColor color
Definition: dl_golden_blur_unittests.cc:24
impeller
Definition: allocation.cc:12
impeller::testing::TEST
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Definition: allocation_size_unittests.cc:10
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37