Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
colrv1.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 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"
11#include "include/core/SkFont.h"
18#include "include/core/SkSize.h"
22#include "tools/Resources.h"
23#include "tools/ToolUtils.h"
25
26#if defined(SK_TYPEFACE_FACTORY_FONTATIONS)
28#endif
29
30#include <string.h>
31#include <initializer_list>
32
33namespace skiagm {
34
35namespace {
36const SkScalar kTextSizes[] = {12, 18, 30, 120};
37const char kTestFontName[] = "fonts/test_glyphs-glyf_colr_1.ttf";
38const char kTestFontNameVariable[] = "fonts/test_glyphs-glyf_colr_1_variable.ttf";
39const SkScalar xWidth = 1200;
40const SkScalar xTranslate = 200;
41} // namespace
42
43class ColrV1GM : public GM {
44public:
45 ColrV1GM(const char* testName,
46 SkSpan<const uint32_t> codepoints,
47 SkScalar skewX,
48 SkScalar rotateDeg,
49 std::initializer_list<SkFontArguments::VariationPosition::Coordinate>
50 specifiedVariations)
51 : fTestName(testName), fCodepoints(codepoints), fSkewX(skewX), fRotateDeg(rotateDeg) {
52 fVariationPosition.coordinateCount = specifiedVariations.size();
53 fCoordinates = std::make_unique<SkFontArguments::VariationPosition::Coordinate[]>(
54 specifiedVariations.size());
55 for (size_t i = 0; i < specifiedVariations.size(); ++i) {
56 fCoordinates[i] = std::data(specifiedVariations)[i];
57 }
58
59 fVariationPosition.coordinates = fCoordinates.get();
60 }
61
62protected:
63 void onOnceBeforeDraw() override {
64 if (fVariationPosition.coordinateCount) {
65 fTypeface = ToolUtils::CreateTypefaceFromResource(kTestFontNameVariable, 0);
66 } else {
67 fTypeface = ToolUtils::CreateTypefaceFromResource(kTestFontName, 0);
68 }
69 fVariationSliders = ToolUtils::VariationSliders(fTypeface.get(), fVariationPosition);
70 }
71
72 SkString getName() const override {
73 SkASSERT(!fTestName.isEmpty());
74 SkString gm_name = SkStringPrintf("colrv1_%s", fTestName.c_str());
75
76 if (fSkewX) {
77 gm_name.append(SkStringPrintf("_skew_%.2f", fSkewX));
78 }
79
80 if (fRotateDeg) {
81 gm_name.append(SkStringPrintf("_rotate_%.2f", fRotateDeg));
82 }
83
84 for (int i = 0; i < fVariationPosition.coordinateCount; ++i) {
86 fVariationPosition.coordinates[i].axis);
87 gm_name.append(SkStringPrintf(
88 "_%s_%.2f", tagName.c_str(), fVariationPosition.coordinates[i].value));
89 }
90
91 return gm_name;
92 }
93
94 bool onGetControls(SkMetaData* controls) override {
95 return fVariationSliders.writeControls(controls);
96 }
97
98 void onSetControls(const SkMetaData& controls) override {
99 return fVariationSliders.readControls(controls);
100 }
101
102 SkISize getISize() override {
103 // Sweep tests get a slightly wider canvas so that glyphs from one group fit in one row.
104 if (fTestName.equals("sweep_varsweep")) {
105 return SkISize::Make(xWidth + 500, xWidth);
106 }
107 return SkISize::Make(xWidth, xWidth);
108 }
109
111 if (!fTypeface) {
112 return nullptr;
113 }
115 fVariationSliders.getCoordinates();
116 SkFontArguments::VariationPosition varPos = {coords.data(),
117 static_cast<int>(coords.size())};
120 return fTypeface->makeClone(args);
121 }
122
123 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
124 canvas->drawColor(SK_ColorWHITE);
126
127 canvas->translate(xTranslate, 20);
128
129 if (!fTypeface) {
130 *errorMsg = "Did not recognize COLR v1 font format.";
131 return DrawResult::kSkip;
132 }
133
134 canvas->rotate(fRotateDeg);
135 canvas->skew(fSkewX, 0);
136
138
139 SkFontMetrics metrics;
140 SkScalar y = 0;
141 std::vector<SkColor> paint_colors = {
143 auto paint_color_iterator = paint_colors.begin();
144 for (SkScalar textSize : kTextSizes) {
145 font.setSize(textSize);
146 font.getMetrics(&metrics);
147 SkScalar y_shift = -(metrics.fAscent + metrics.fDescent + metrics.fLeading) * 1.2;
148 y += y_shift;
149 paint.setColor(*paint_color_iterator);
150 int x = 0;
151 // Perform simple line breaking to fit more glyphs into the GM canvas.
152 for (size_t i = 0; i < fCodepoints.size(); ++i) {
153 SkScalar glyphAdvance = font.measureText(
154 &fCodepoints[i], sizeof(uint32_t), SkTextEncoding::kUTF32, nullptr);
155 if (0 < x && getISize().width() - xTranslate < x + glyphAdvance) {
156 y += y_shift;
157 x = 0;
158 }
159 canvas->drawSimpleText(&fCodepoints[i],
160 sizeof(uint32_t),
162 x,
163 y,
164 font,
165 paint);
166 x += glyphAdvance + glyphAdvance * 0.05f;
167 }
168 paint_color_iterator++;
169 }
170 return DrawResult::kOk;
171 }
172
173private:
174 using INHERITED = GM;
175
176 SkString fTestName;
177 sk_sp<SkTypeface> fTypeface;
178 SkSpan<const uint32_t> fCodepoints;
179 SkScalar fSkewX;
180 SkScalar fRotateDeg;
181 std::unique_ptr<SkFontArguments::VariationPosition::Coordinate[]> fCoordinates;
182 SkFontArguments::VariationPosition fVariationPosition;
183 ToolUtils::VariationSliders fVariationSliders;
184};
185
186// clang-format off
187// Generated using test glyphs generator script from https://github.com/googlefonts/color-fonts:
188// $ python3 config/test_glyphs-glyf_colr_1.py -vvv --generate-descriptions fonts/
189// Regenerate descriptions and paste the generated arrays here when updating the test font.
190namespace ColrV1TestDefinitions {
191const uint32_t gradient_stops_repeat[] = {0xf0100, 0xf0101, 0xf0102, 0xf0103};
192const uint32_t sweep_varsweep[] = {
193 0xf0200, 0xf0201, 0xf0202, 0xf0203, 0xf0204, 0xf0205, 0xf0206, 0xf0207, 0xf0208,
194 0xf0209, 0xf020a, 0xf020b, 0xf020c, 0xf020d, 0xf020e, 0xf020f, 0xf0210, 0xf0211,
195 0xf0212, 0xf0213, 0xf0214, 0xf0215, 0xf0216, 0xf0217, 0xf0218, 0xf0219, 0xf021a,
196 0xf021b, 0xf021c, 0xf021d, 0xf021e, 0xf021f, 0xf0220, 0xf0221, 0xf0222, 0xf0223,
197 0xf0224, 0xf0225, 0xf0226, 0xf0227, 0xf0228, 0xf0229, 0xf022a, 0xf022b, 0xf022c,
198 0xf022d, 0xf022e, 0xf022f, 0xf0230, 0xf0231, 0xf0232, 0xf0233, 0xf0234, 0xf0235,
199 0xf0236, 0xf0237, 0xf0238, 0xf0239, 0xf023a, 0xf023b, 0xf023c, 0xf023d, 0xf023e,
200 0xf023f, 0xf0240, 0xf0241, 0xf0242, 0xf0243, 0xf0244, 0xf0245, 0xf0246, 0xf0247};
201const uint32_t paint_scale[] = {0xf0300, 0xf0301, 0xf0302, 0xf0303, 0xf0304, 0xf0305};
202const uint32_t extend_mode[] = {
203 0xf0500, 0xf0501, 0xf0502, 0xf0503, 0xf0504, 0xf0505, 0xf0506, 0xf0507, 0xf0508};
204const uint32_t paint_rotate[] = {0xf0600, 0xf0601, 0xf0602, 0xf0603};
205const uint32_t paint_skew[] = {0xf0700, 0xf0701, 0xf0702, 0xf0703, 0xf0704, 0xf0705};
206const uint32_t paint_transform[] = {0xf0800, 0xf0801, 0xf0802, 0xf0803};
207const uint32_t paint_translate[] = {0xf0900, 0xf0901, 0xf0902, 0xf0903, 0xf0904, 0xf0905, 0xf0906};
208const uint32_t composite_mode[] = {0xf0a00, 0xf0a01, 0xf0a02, 0xf0a03, 0xf0a04, 0xf0a05, 0xf0a06,
209 0xf0a07, 0xf0a08, 0xf0a09, 0xf0a0a, 0xf0a0b, 0xf0a0c, 0xf0a0d,
210 0xf0a0e, 0xf0a0f, 0xf0a10, 0xf0a11, 0xf0a12, 0xf0a13, 0xf0a14,
211 0xf0a15, 0xf0a16, 0xf0a17, 0xf0a18, 0xf0a19, 0xf0a1a, 0xf0a1b};
212const uint32_t foreground_color[] = {
213 0xf0b00, 0xf0b01, 0xf0b02, 0xf0b03, 0xf0b04, 0xf0b05, 0xf0b06, 0xf0b07};
214const uint32_t clipbox[] = {0xf0c00, 0xf0c01, 0xf0c02, 0xf0c03, 0xf0c04};
215const uint32_t gradient_p2_skewed[] = {0xf0d00};
216const uint32_t variable_alpha[] = {0xf1000};
217const uint32_t paintcolrglyph_cycle[] = { 0xf1100, 0xf1101, 0xf1200 };
218const uint32_t sweep_coincident[] = { 0xf1300, 0xf1301, 0xf1302, 0xf1303, 0xf1304, 0xf1305,
219 0xf1306, 0xf1307, 0xf1308, 0xf1309, 0xf130a, 0xf130b,
220 0xf130c, 0xf130d, 0xf130e, 0xf130f, 0xf1310, 0xf1311,
221 0xf1312, 0xf1313, 0xf1314, 0xf1315, 0xf1316, 0xf1317};
222const uint32_t paint_glyph_nested[] = { 0xf1400, 0xf1401, 0xf1402, 0xf1403,
223 0xf1404, 0xf1405, 0xf1406, 0xf1407,
224 0xf1408, 0xf1409, 0xf140a, 0xf140b,
225 0xf140c, 0xf140d, 0xf140e, 0xf140f };
226// clang-format on
227
228}; // namespace ColrV1TestDefinitions
229
230namespace {
231std::unique_ptr<ColrV1GM> F(
232 const char* name,
233 SkSpan<const uint32_t> codepoints,
234 SkScalar skewX,
235 SkScalar rotateDeg,
236 std::initializer_list<SkFontArguments::VariationPosition::Coordinate> variations) {
237 return std::make_unique<ColrV1GM>(name, codepoints, skewX, rotateDeg, variations);
238}
239
240SkFourByteTag constexpr operator"" _t(const char* tagName, size_t size) {
241 SkASSERT(size == 4);
242 return SkSetFourByteTag(tagName[0], tagName[1], tagName[2], tagName[3]);
243}
244} // namespace
245
246// clang-format off
247#define C(TEST_CATEGORY) #TEST_CATEGORY, ColrV1TestDefinitions::TEST_CATEGORY
248DEF_GM(return F(C(clipbox), 0.0f, 0.0f, {}))
249DEF_GM(return F(C(clipbox), 0.0f, 0.0f, {{"CLIO"_t, 200.f}}))
250DEF_GM(return F(C(composite_mode), 0.0f, 0.0f, {}))
251DEF_GM(return F(C(composite_mode), -0.5f, 0.0f, {}))
252DEF_GM(return F(C(composite_mode), -0.5f, 20.0f, {}))
253DEF_GM(return F(C(composite_mode), 0.0f, 20.0f, {}))
254DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {}))
255DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"COL1"_t, -0.25f}, {"COL3"_t, 0.25f}}))
256DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"COL1"_t, 0.5f}, {"COL3"_t, -0.5f}}))
257DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"COL3"_t, 0.5f}}))
258DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"COL3"_t, 1.f}}))
259// Radial gradient tests where radii become negative
260DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"COL1"_t, -1.5f}}))
261// Both radii negative and equal, nothing should render.
262DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"GRR0"_t, -200.f}, {"GRR1"_t, -300.f}}))
263// Small cones opening to the right.
264DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"GRX0"_t, -1000.f}, {"GRX1"_t, -1000.f}, {"GRR0"_t, -1000.f}, {"GRR1"_t, -900.f}}))
265// Small cones opening to the left.
266DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"GRX0"_t, 1000.f}, {"GRX1"_t, -1000.f}, {"GRR0"_t, -1000.f}, {"GRR1"_t, 200.f}}))
267// Pad cone should appear green.
268DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"GRR0"_t, -50.f}, {"COL3"_t, -2.f}, {"COL2"_t, -2.f}, {"COL1"_t, -0.9f}}))
269// Pad cone should appear red.
270DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"GRR0"_t, -50.f}, {"COL3"_t, -2.f}, {"COL2"_t, -2.f}, {"COL1"_t, -1.1f}}))
271// Hard boundary for pad mode, should appear on the right inside the glyph for linear and radial.
272DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"COL3"_t, 1.f}, {"COL2"_t, 1.5f}, {"COL1"_t, 2.f}}))
273// Extend mode with rotation or skew below.
274DEF_GM(return F(C(extend_mode), -0.5f, 0.0f, {}))
275DEF_GM(return F(C(extend_mode), -0.5f, 20.0f, {}))
276DEF_GM(return F(C(extend_mode), 0.0f, 20.0f, {}))
277DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"COL2"_t, -0.3f}}))
278DEF_GM(return F(C(extend_mode), 0.0f, 0.0f, {{"GRR0"_t, 430.f}, {"GRR1"_t, 40.f}}))
279DEF_GM(return F(C(foreground_color), 0.0f, 0.0f, {}))
280DEF_GM(return F(C(gradient_p2_skewed), 0.0f, 0.0f, {}))
281DEF_GM(return F(C(gradient_stops_repeat), 0.0f, 0.0f, {}))
282DEF_GM(return F(C(gradient_stops_repeat), -0.5f, 0.0f, {}))
283DEF_GM(return F(C(gradient_stops_repeat), -0.5f, 20.0f, {}))
284DEF_GM(return F(C(gradient_stops_repeat), 0.0f, 20.0f, {}))
285DEF_GM(return F(C(paint_rotate), 0.0f, 0.0f, {}))
286DEF_GM(return F(C(paint_rotate), 0.0f, 0.0f, {{"ROTA"_t, 40.f}}))
287DEF_GM(return F(C(paint_rotate), 0.0f, 0.0f, {{"ROTX"_t, -250.f}, {"ROTY"_t, -250.f}}))
288DEF_GM(return F(C(paint_scale), 0.0f, 0.0f, {}))
289DEF_GM(return F(C(paint_scale), 0.0f, 0.0f, {{"SCOX"_t, 200.f}, {"SCOY"_t, 200.f}}))
290DEF_GM(return F(C(paint_scale), 0.0f, 0.0f, {{"SCSX"_t, 0.25f}, {"SCOY"_t, 0.25f}}))
291DEF_GM(return F(C(paint_scale), 0.0f, 0.0f, {{"SCSX"_t, -1.f}, {"SCOY"_t, -1.f}}))
292DEF_GM(return F(C(paint_skew), 0.0f, 0.0f, {}))
293DEF_GM(return F(C(paint_skew), 0.0f, 0.0f, {{"SKXA"_t, 20.f}}))
294DEF_GM(return F(C(paint_skew), 0.0f, 0.0f, {{"SKYA"_t, 20.f}}))
295DEF_GM(return F(C(paint_skew), 0.0f, 0.0f, {{"SKCX"_t, 200.f},{"SKCY"_t, 200.f}}))
296DEF_GM(return F(C(paint_transform), 0.0f, 0.0f, {}))
297DEF_GM(return F(C(paint_translate), 0.0f, 0.0f, {}))
298DEF_GM(return F(C(paint_translate), 0.0f, 0.0f, {{"TLDX"_t, 100.f}, {"TLDY"_t, 100.f}}))
299DEF_GM(return F(C(sweep_varsweep), 0.0f, 0.0f, {}))
300DEF_GM(return F(C(sweep_varsweep), -0.5f, 0.0f, {}))
301DEF_GM(return F(C(sweep_varsweep), -0.5f, 20.0f, {}))
302DEF_GM(return F(C(sweep_varsweep), 0.0f, 20.0f, {}))
303DEF_GM(return F(C(sweep_varsweep), 0.0f, 0.0f, {{"SWPS"_t, 0.f}}))
304DEF_GM(return F(C(sweep_varsweep), 0.0f, 0.0f, {{"SWPS"_t, 90.f}}))
305DEF_GM(return F(C(sweep_varsweep), 0.0f, 0.0f, {{"SWPE"_t, -90.f}}))
306DEF_GM(return F(C(sweep_varsweep), 0.0f, 0.0f, {{"SWPE"_t, -45.f}}))
307DEF_GM(return F(C(sweep_varsweep), 0.0f, 0.0f, {{"SWPS"_t, -45.f},{"SWPE"_t, 45.f}}))
308DEF_GM(return F(C(sweep_varsweep),
309 0.0f,
310 0.0f,
311 {{"SWC1"_t, -0.25f},
312 {"SWC2"_t, 0.083333333f},
313 {"SWC3"_t, 0.083333333f},
314 {"SWC4"_t, +0.25f}}))
315DEF_GM(return F(C(variable_alpha), 0.0f, 0.0f, {}))
316DEF_GM(return F(C(variable_alpha), 0.0f, 0.0f, {{"APH1"_t, -0.7f}}))
317DEF_GM(return F(C(variable_alpha), 0.0f, 0.0f, {{"APH2"_t, -0.7f}, {"APH3"_t, -0.2f}}))
318DEF_GM(return F(C(paintcolrglyph_cycle), 0.0f, 0.0f, {}))
319DEF_GM(return F(C(sweep_coincident), 0.0f, 0.0f, {}))
320DEF_GM(return F(C(paint_glyph_nested), 0.0f, 0.0f, {}))
321// clang-format on
322
323} // namespace skiagm
#define SkASSERT(cond)
Definition SkAssert.h:116
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
constexpr SkColor SK_ColorRED
Definition SkColor.h:126
constexpr SkColor SK_ColorBLACK
Definition SkColor.h:103
constexpr SkColor SK_ColorGREEN
Definition SkColor.h:131
constexpr SkColor SK_ColorWHITE
Definition SkColor.h:122
@ kUTF32
uses four byte words to represent all of Unicode
SK_API SkString static SkString SkStringPrintf()
Definition SkString.h:287
uint32_t SkFourByteTag
Definition SkTypes.h:166
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
#define F(x)
void drawSimpleText(const void *text, size_t byteLength, SkTextEncoding encoding, SkScalar x, SkScalar y, const SkFont &font, const SkPaint &paint)
void translate(SkScalar dx, SkScalar dy)
void drawColor(SkColor color, SkBlendMode mode=SkBlendMode::kSrcOver)
Definition SkCanvas.h:1182
void rotate(SkScalar degrees)
void skew(SkScalar sx, SkScalar sy)
constexpr T * data() const
Definition SkSpan_impl.h:94
constexpr size_t size() const
Definition SkSpan_impl.h:95
bool equals(const SkString &) const
Definition SkString.cpp:324
bool isEmpty() const
Definition SkString.h:130
void append(const char text[])
Definition SkString.h:203
const char * c_str() const
Definition SkString.h:133
sk_sp< SkTypeface > makeClone(const SkFontArguments &) const
SkSpan< const SkFontArguments::VariationPosition::Coordinate > getCoordinates()
void readControls(const SkMetaData &controls, bool *changed=nullptr)
static SkString tagToString(SkFourByteTag tag)
bool writeControls(SkMetaData *controls)
T * get() const
Definition SkRefCnt.h:303
void onSetControls(const SkMetaData &controls) override
Definition colrv1.cpp:98
bool onGetControls(SkMetaData *controls) override
Definition colrv1.cpp:94
ColrV1GM(const char *testName, SkSpan< const uint32_t > codepoints, SkScalar skewX, SkScalar rotateDeg, std::initializer_list< SkFontArguments::VariationPosition::Coordinate > specifiedVariations)
Definition colrv1.cpp:45
sk_sp< SkTypeface > makeVariedTypeface()
Definition colrv1.cpp:110
void onOnceBeforeDraw() override
Definition colrv1.cpp:63
DrawResult onDraw(SkCanvas *canvas, SkString *errorMsg) override
Definition colrv1.cpp:123
SkISize getISize() override
Definition colrv1.cpp:102
SkString getName() const override
Definition colrv1.cpp:72
const Paint & paint
#define C(TEST_CATEGORY)
Definition colrv1.cpp:247
float SkScalar
Definition extension.cpp:12
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const char * name
Definition fuchsia.cc:50
#define DEF_GM(CODE)
Definition gm.h:40
double y
double x
sk_sp< SkTypeface > CreateTypefaceFromResource(const char *resource, int ttcIndex)
DrawResult
Definition gm.h:104
Definition SkMD5.cpp:120
SkFontArguments & setVariationDesignPosition(VariationPosition position)
SkScalar fLeading
distance to add between lines, typically positive or zero
SkScalar fAscent
distance to reserve above baseline, typically negative
SkScalar fDescent
distance to reserve below baseline, typically positive
static constexpr SkISize Make(int32_t w, int32_t h)
Definition SkSize.h:20
constexpr int32_t width() const
Definition SkSize.h:36