Flutter Engine
The Flutter Engine
p3.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 Google Inc.
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
8#include "gm/gm.h"
13#include "include/core/SkFont.h"
31
32#include <math.h>
33#include <string.h>
34
36 const float K = 0.01f;
37 return fabsf(x.fR - y.fR) < K
38 && fabsf(x.fG - y.fG) < K
39 && fabsf(x.fB - y.fB) < K
40 && fabsf(x.fA - y.fA) < K;
41}
42
44 return SkStringPrintf("%.2g %.2g %.2g %.2g", c.fR, c.fG, c.fB, c.fA);
45}
46
50 return c;
51}
52
53static void compare_pixel(const char* label,
54 SkCanvas* canvas, int x, int y,
58 auto canvas_cs = canvas->imageInfo().refColorSpace();
59
60 // I'm not really sure if this makes things easier or harder to follow,
61 // but we sniff the canvas to grab its current y-translate, so that (x,y)
62 // can be written in sort of chunk-relative terms.
63 const SkMatrix& m = canvas->getTotalMatrix();
64 SkASSERT(m.isScaleTranslate());
65 SkScalar dy = m.getTranslateY();
66 SkASSERT(dy == (int)dy);
67 y += (int)dy;
68
69 SkBitmap bm;
71 if (!canvas->readPixels(bm, x,y)) {
72 MarkGMGood(canvas, 140,40);
73 canvas->drawString("can't readPixels() on this canvas :(", 100,20, font, paint);
74 return;
75 }
76
77 SkColor4f pixel;
78 memcpy(&pixel, bm.getAddr(0,0), sizeof(pixel));
79
80 SkColor4f expected = transform(color,cs, canvas_cs.get());
82 // We can't expect normalized formats to hold values outside [0,1].
83 for (int i = 0; i < 4; ++i) {
84 expected[i] = SkTPin(expected[i], 0.0f, 1.0f);
85 }
86 }
87 if (canvas->imageInfo().colorType() == kGray_8_SkColorType) {
88 // Drawing into Gray8 is known to be maybe-totally broken.
89 // TODO: update expectation here to be {lum,lum,lum,1} if we fix Gray8.
90 expected = SkColor4f{NAN, NAN, NAN, 1};
91 }
92
93 if (nearly_equal(pixel, expected)) {
94 MarkGMGood(canvas, 140,40);
95 } else {
96 MarkGMBad(canvas, 140,40);
97 }
98
99 struct {
100 const char* label;
102 } lines[] = {
103 {"Pixel:" , pixel },
104 {"Expected:", expected},
105 };
106
107 SkAutoCanvasRestore saveRestore(canvas, true);
108 canvas->drawString(label, 80,20, font, paint);
109 for (auto l : lines) {
110 canvas->translate(0,20);
111 canvas->drawString(l.label, 80,20, font, paint);
112 canvas->drawString(fmt(l.color).c_str(), 140,20, font, paint);
113 }
114}
115
116DEF_SIMPLE_GM(p3, canvas, 450, 1300) {
118 auto srgb = SkColorSpace::MakeSRGB();
119
120 auto p3_to_srgb = [&](SkColor4f c) {
121 SkPaint p;
122 p.setColor4f(c, p3.get());
123 return p.getColor4f();
124 };
125
126 // Draw a P3 red rectangle and check the corner.
127 {
129 paint.setColor4f({1,0,0,1}, p3.get());
130
131 canvas->drawRect({10,10,70,70}, paint);
132 compare_pixel("drawRect P3 red ",
133 canvas, 10,10,
134 {1,0,0,1}, p3.get());
135 }
136
137 canvas->translate(0,80);
138
139 // Draw a P3 red bitmap, using a draw.
140 {
141 SkBitmap bm;
143
145 paint.setColor4f({1,0,0,1}, p3.get());
146 SkCanvas{bm}.drawPaint(paint);
147
148 canvas->drawImage(bm.asImage(), 10,10);
149 compare_pixel("drawBitmap P3 red, from drawPaint",
150 canvas, 10,10,
151 {1,0,0,1}, p3.get());
152 }
153
154 canvas->translate(0,80);
155
156 // TODO(mtklein): sample and check the middle points of these gradients too.
157
158 // Draw a gradient from P3 red to P3 green interpolating in unpremul P3, checking the corners.
159 {
160
161 SkPoint points[] = {{10.5,10.5}, {69.5,69.5}};
162 SkColor4f colors[] = {{1,0,0,1}, {0,1,0,1}};
163
166 nullptr, std::size(colors),
168 canvas->drawRect({10,10,70,70}, paint);
169 canvas->save();
170 compare_pixel("UPM P3 gradient, P3 red",
171 canvas, 10,10,
172 {1,0,0,1}, p3.get());
173
174 canvas->translate(180, 0);
175
176 compare_pixel("UPM P3 gradient, P3 green",
177 canvas, 69,69,
178 {0,1,0,1}, p3.get());
179 canvas->restore();
180 }
181
182 canvas->translate(0,80);
183
184 // Draw a gradient from P3 red to P3 green interpolating in premul P3, checking the corners.
185 {
186
187 SkPoint points[] = {{10.5,10.5}, {69.5,69.5}};
188 SkColor4f colors[] = {{1,0,0,1}, {0,1,0,1}};
189
191 paint.setShader(
193 nullptr, std::size(colors),
196 nullptr/*local matrix*/));
197 canvas->drawRect({10,10,70,70}, paint);
198 canvas->save();
199 compare_pixel("PM P3 gradient, P3 red",
200 canvas, 10,10,
201 {1,0,0,1}, p3.get());
202
203 canvas->translate(180, 0);
204
205 compare_pixel("PM P3 gradient, P3 green",
206 canvas, 69,69,
207 {0,1,0,1}, p3.get());
208 canvas->restore();
209 }
210
211 canvas->translate(0,80);
212
213 // Draw a gradient from P3 red to P3 green interpolating in unpremul sRGB, checking the corners.
214 {
215
216 SkPoint points[] = {{10.5,10.5}, {69.5,69.5}};
217 SkColor4f colors[] = {p3_to_srgb({1,0,0,1}), p3_to_srgb({0,1,0,1})};
218
221 nullptr, std::size(colors),
223 canvas->drawRect({10,10,70,70}, paint);
224 canvas->save();
225 compare_pixel("UPM sRGB gradient, P3 red",
226 canvas, 10,10,
227 {1,0,0,1}, p3.get());
228
229 canvas->translate(180, 0);
230
231 compare_pixel("UPM sRGB gradient, P3 green",
232 canvas, 69,69,
233 {0,1,0,1}, p3.get());
234 canvas->restore();
235 }
236
237 canvas->translate(0,80);
238
239 // Draw a gradient from P3 red to P3 green interpolating in premul sRGB, checking the corners.
240 {
241
242 SkPoint points[] = {{10.5,10.5}, {69.5,69.5}};
243 SkColor4f colors[] = {p3_to_srgb({1,0,0,1}), p3_to_srgb({0,1,0,1})};
244
246 paint.setShader(
248 nullptr, std::size(colors),
251 nullptr/*local matrix*/));
252 canvas->drawRect({10,10,70,70}, paint);
253 canvas->save();
254 compare_pixel("PM sRGB gradient, P3 red",
255 canvas, 10,10,
256 {1,0,0,1}, p3.get());
257
258 canvas->translate(180, 0);
259
260 compare_pixel("PM sRGB gradient, P3 green",
261 canvas, 69,69,
262 {0,1,0,1}, p3.get());
263 canvas->restore();
264 }
265
266 canvas->translate(0,80);
267
268 // Leon's blue -> green -> red gradient, interpolating in premul.
269 {
270 SkPoint points[] = {{10.5,10.5}, {10.5,69.5}};
271 SkColor4f colors[] = { {0,0,1,1}, {0,1,0,1}, {1,0,0,1} };
272
274 paint.setShader(
276 nullptr, std::size(colors),
279 nullptr/*local matrix*/));
280 canvas->drawRect({10,10,70,70}, paint);
281 canvas->save();
282 compare_pixel("Leon's gradient, P3 blue",
283 canvas, 10,10,
284 {0,0,1,1}, p3.get());
285
286 canvas->translate(180, 0);
287
288 compare_pixel("Leon's gradient, P3 red",
289 canvas, 10,69,
290 {1,0,0,1}, p3.get());
291 canvas->restore();
292 }
293
294 canvas->translate(0,80);
295
296 // Draw an A8 image with a P3 red, scaled and not, as a shader or bitmap.
297 {
298 uint8_t mask[256];
299 for (int i = 0; i < 256; i++) {
300 mask[i] = 255-i;
301 }
302
303 SkBitmap bm;
304 bm.installPixels(SkImageInfo::MakeA8(16,16), mask, 16);
305
306 SkPaint as_bitmap;
307 as_bitmap.setColor4f({1,0,0,1}, p3.get());
309
310 SkPaint as_shader;
311 as_shader.setColor4f({1,0,0,1}, p3.get());
312 as_shader.setShader(bm.makeShader(sampling));
313
314 canvas->drawImage(bm.asImage(), 10,10, sampling, &as_bitmap);
315 compare_pixel("A8 sprite bitmap P3 red",
316 canvas, 10,10,
317 {1,0,0,1}, p3.get());
318
319 canvas->translate(0, 80);
320
321 canvas->save();
322 canvas->translate(10,10);
323 canvas->drawRect({0,0,16,16}, as_shader);
324 canvas->restore();
325 compare_pixel("A8 sprite shader P3 red",
326 canvas, 10,10,
327 {1,0,0,1}, p3.get());
328
329 canvas->translate(0,80);
330
331 canvas->drawImageRect(bm.asImage(), {10,10,70,70}, sampling, &as_bitmap);
332 compare_pixel("A8 scaled bitmap P3 red",
333 canvas, 10,10,
334 {1,0,0,1}, p3.get());
335
336 canvas->translate(0,80);
337
338 canvas->save();
339 canvas->translate(10,10);
340 canvas->scale(3.75,3.75);
341 canvas->drawRect({0,0,16,16}, as_shader);
342 canvas->restore();
343 compare_pixel("A8 scaled shader P3 red",
344 canvas, 10,10,
345 {1,0,0,1}, p3.get());
346 }
347
348 // TODO: draw P3 colors more ways
349}
350
351DEF_SIMPLE_GM(p3_ovals, canvas, 450, 320) {
353
354 // Test cases that exercise each Op in GrOvalOpFactory.cpp
355
356 // Draw a circle and check the center (CircleOp)
357 {
359 paint.setAntiAlias(true);
360 paint.setColor4f({ 1,0,0,1 }, p3.get());
361
362 canvas->drawCircle(40, 40, 30, paint);
363 compare_pixel("drawCircle P3 red ",
364 canvas, 40, 40,
365 { 1,0,0,1 }, p3.get());
366 }
367
368 canvas->translate(0, 80);
369
370 // Draw an oval and check the center (EllipseOp)
371 {
373 paint.setAntiAlias(true);
374 paint.setColor4f({ 1,0,0,1 }, p3.get());
375
376 canvas->drawOval({ 20,10,60,70 }, paint);
377 compare_pixel("drawOval P3 red ",
378 canvas, 40, 40,
379 { 1,0,0,1 }, p3.get());
380 }
381
382 canvas->translate(0, 80);
383
384 // Draw a butt-capped dashed circle and check the top of the stroke (ButtCappedDashedCircleOp)
385 {
387 paint.setAntiAlias(true);
388 paint.setColor4f({ 1,0,0,1 }, p3.get());
390 float intervals[] = { 70, 10 };
391 paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
392 paint.setStrokeWidth(10);
393
394 canvas->drawCircle(40, 40, 30, paint);
395 compare_pixel("drawDashedCircle P3 red ",
396 canvas, 40, 10,
397 { 1,0,0,1 }, p3.get());
398 }
399
400 canvas->translate(0, 80);
401
402 // Draw an oval with rotation and check the center (DIEllipseOp)
403 {
405 paint.setAntiAlias(true);
406 paint.setColor4f({ 1,0,0,1 }, p3.get());
407
408 canvas->save();
409 canvas->translate(40, 40);
410 canvas->rotate(45);
411 canvas->drawOval({ -20,-30,20,30 }, paint);
412 canvas->restore();
413 compare_pixel("drawRotatedOval P3 red ",
414 canvas, 40, 40,
415 { 1,0,0,1 }, p3.get());
416 }
417
418 canvas->translate(0, 80);
419}
static const int points[]
kUnpremul_SkAlphaType
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kGray_8_SkColorType
pixel with grayscale level in 8-bit byte
Definition: SkColorType.h:35
@ kRGBA_F32_SkColorType
pixel using C float for red, green, blue, alpha; in 128-bit word
Definition: SkColorType.h:40
static bool SkColorTypeIsNormalized(SkColorType ct)
SK_API SkString SkStringPrintf(const char *format,...) SK_PRINTF_LIKE(1
Creates a new string and writes into it using a printf()-style format.
static constexpr const T & SkTPin(const T &x, const T &lo, const T &hi)
Definition: SkTPin.h:19
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
sk_sp< SkImage > asImage() const
Definition: SkBitmap.cpp:645
bool installPixels(const SkImageInfo &info, void *pixels, size_t rowBytes, void(*releaseProc)(void *addr, void *context), void *context)
Definition: SkBitmap.cpp:323
void * getAddr(int x, int y) const
Definition: SkBitmap.cpp:406
sk_sp< SkShader > makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions &, const SkMatrix *localMatrix=nullptr) const
Definition: SkBitmap.cpp:669
void translate(SkScalar dx, SkScalar dy)
Definition: SkCanvas.cpp:1278
SkMatrix getTotalMatrix() const
Definition: SkCanvas.cpp:1629
void drawString(const char str[], SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
Definition: SkCanvas.h:1803
SkImageInfo imageInfo() const
Definition: SkCanvas.cpp:1206
bool readPixels(const SkImageInfo &dstInfo, void *dstPixels, size_t dstRowBytes, int srcX, int srcY)
Definition: SkCanvas.cpp:382
static sk_sp< SkColorSpace > MakeSRGB()
static sk_sp< SkColorSpace > MakeRGB(const skcms_TransferFunction &transferFn, const skcms_Matrix3x3 &toXYZ)
static sk_sp< SkPathEffect > Make(const SkScalar intervals[], int count, SkScalar phase)
Definition: SkFont.h:35
static sk_sp< SkShader > MakeLinear(const SkPoint pts[2], const SkColor colors[], const SkScalar pos[], int count, SkTileMode mode, uint32_t flags=0, const SkMatrix *localMatrix=nullptr)
@ kStroke_Style
set to stroke geometry
Definition: SkPaint.h:194
void setColor4f(const SkColor4f &color, SkColorSpace *colorSpace=nullptr)
Definition: SkPaint.h:253
void setShader(sk_sp< SkShader > shader)
const char * c_str() const
Definition: SkString.h:133
const Paint & paint
Definition: color_source.cc:38
static const int K
Definition: daa.cpp:21
DlColor color
float SkScalar
Definition: extension.cpp:12
void MarkGMGood(SkCanvas *canvas, SkScalar x, SkScalar y)
Definition: gm.cpp:221
void MarkGMBad(SkCanvas *canvas, SkScalar x, SkScalar y)
Definition: gm.cpp:238
double y
double x
static constexpr skcms_Matrix3x3 kDisplayP3
Definition: SkColorSpace.h:87
static constexpr skcms_TransferFunction kSRGB
Definition: SkColorSpace.h:45
PODArray< SkColor > colors
Definition: SkRecords.h:276
SkSamplingOptions sampling
Definition: SkRecords.h:337
SkFont DefaultPortableFont()
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
font
Font Metadata and Metrics.
dst
Definition: cp.py:12
static bool nearly_equal(SkColor4f x, SkColor4f y)
Definition: p3.cpp:35
DEF_SIMPLE_GM(p3, canvas, 450, 1300)
Definition: p3.cpp:116
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition: p3.cpp:47
static SkString fmt(SkColor4f c)
Definition: p3.cpp:43
static void compare_pixel(const char *label, SkCanvas *canvas, int x, int y, SkColor4f color, SkColorSpace *cs)
Definition: p3.cpp:53
void apply(float rgba[4]) const
sk_sp< SkColorSpace > refColorSpace() const
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
SkColorType colorType() const
Definition: SkImageInfo.h:373
static SkImageInfo MakeA8(int width, int height)