1 /*
2 * Copyright 2023 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
8 #include "gm/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkData.h"
12 #include "include/core/SkFont.h"
13 #include "include/core/SkFontTypes.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkStream.h"
16 #include "include/core/SkString.h"
17 #include "include/core/SkSurface.h"
18 #include "include/core/SkTypeface.h"
19 #include "include/ports/SkTypeface_fontations.h"
20 #include "modules/skshaper/include/SkShaper.h"
21 #include "src/core/SkColorPriv.h"
22 #include "src/ports/SkTypeface_FreeType.h"
23 #include "tools/Resources.h"
24 #include "tools/TestFontDataProvider.h"
25
26 namespace skiagm {
27
28 namespace {
29
30 constexpr int kGmWidth = 1000;
31 constexpr int kMargin = 30;
32 constexpr float kFontSize = 24;
33 constexpr float kLangYIncrementScale = 1.9;
34
35 /** Compare bitmap A and B, in this case originating from text rendering results with FreeType and
36 * Fontations + Skia path rendering, compute individual pixel differences for the rectangles that
37 * must match in size. Produce a highlighted difference bitmap, in which any pixel becomes white for
38 * which a difference was determined. */
comparePixels(const SkPixmap & pixmapA,const SkPixmap & pixmapB,SkBitmap * outPixelDiffBitmap,SkBitmap * outHighlightDiffBitmap)39 void comparePixels(const SkPixmap& pixmapA,
40 const SkPixmap& pixmapB,
41 SkBitmap* outPixelDiffBitmap,
42 SkBitmap* outHighlightDiffBitmap) {
43 if (pixmapA.dimensions() != pixmapB.dimensions()) {
44 return;
45 }
46 if (pixmapA.dimensions() != outPixelDiffBitmap->dimensions()) {
47 return;
48 }
49
50 SkISize dimensions = pixmapA.dimensions();
51 for (int32_t x = 0; x < dimensions.fWidth; x++) {
52 for (int32_t y = 0; y < dimensions.fHeight; y++) {
53 SkColor c0 = pixmapA.getColor(x, y);
54 SkColor c1 = pixmapB.getColor(x, y);
55 int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1);
56 int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1);
57 int db = SkGetPackedB32(c0) - SkGetPackedB32(c1);
58
59 *(outPixelDiffBitmap->getAddr32(x, y)) =
60 SkPackARGB32(0xFF, SkAbs32(dr), SkAbs32(dg), SkAbs32(db));
61
62 if (dr != 0 || dg != 0 || db != 0) {
63 *(outHighlightDiffBitmap->getAddr32(x, y)) = SK_ColorWHITE;
64 } else {
65 *(outHighlightDiffBitmap->getAddr32(x, y)) = SK_ColorBLACK;
66 }
67 }
68 }
69 }
70
71 } // namespace
72
73 class FontationsFtCompareGM : public GM {
74 public:
75 enum SimulatePixelGeometry { kLeaveAsIs, kSimulateUnknown };
76
FontationsFtCompareGM(std::string testName,std::string fontNameFilterRegexp,std::string langFilterRegexp,SimulatePixelGeometry simulatePixelGeometry,SkFontHinting hintingMode=SkFontHinting::kNone)77 FontationsFtCompareGM(std::string testName,
78 std::string fontNameFilterRegexp,
79 std::string langFilterRegexp,
80 SimulatePixelGeometry simulatePixelGeometry,
81 SkFontHinting hintingMode = SkFontHinting::kNone)
82 : fTestDataIterator(fontNameFilterRegexp, langFilterRegexp)
83 , fTestName(testName.c_str())
84 , fSimulatePixelGeometry(simulatePixelGeometry)
85 , fHintingMode(hintingMode) {
86 this->setBGColor(SK_ColorWHITE);
87 }
88
89 protected:
getName() const90 SkString getName() const override {
91 SkString testName = SkStringPrintf("fontations_compare_ft_%s", fTestName.c_str());
92 switch (fHintingMode) {
93 case SkFontHinting::kNormal: {
94 testName.append("_hint_normal");
95 break;
96 }
97 case SkFontHinting::kSlight: {
98 testName.append("_hint_slight");
99 break;
100 }
101 case SkFontHinting::kFull: {
102 testName.append("_hint_full");
103 break;
104 }
105 case SkFontHinting::kNone: {
106 testName.append("_hint_none");
107 break;
108 }
109 }
110
111 if (fSimulatePixelGeometry == SimulatePixelGeometry::kSimulateUnknown) {
112 testName.append("_unknown_px_geometry");
113 }
114 return testName;
115 }
116
getISize()117 SkISize getISize() override {
118 TestFontDataProvider::TestSet testSet;
119 fTestDataIterator.rewind();
120 fTestDataIterator.next(&testSet);
121
122 return SkISize::Make(kGmWidth,
123 testSet.langSamples.size() * kFontSize * kLangYIncrementScale + 100);
124 }
125
wrapCanvasUnknownGeometry(SkCanvas * source,sk_sp<SkSurface> & target)126 bool wrapCanvasUnknownGeometry(SkCanvas* source, sk_sp<SkSurface>& target) {
127 SkPixmap canvasPixmap;
128 if (!source->peekPixels(&canvasPixmap)) {
129 return false;
130 }
131
132 SkSurfaceProps canvasSurfaceProps = source->getBaseProps();
133 SkSurfaceProps unknownGeometrySurfaceProps = canvasSurfaceProps.cloneWithPixelGeometry(
134 SkPixelGeometry::kUnknown_SkPixelGeometry);
135 target = SkSurfaces::WrapPixels(canvasPixmap, &unknownGeometrySurfaceProps);
136 return true;
137 }
138
onDraw(SkCanvas * canvas,SkString * errorMsg)139 DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
140 SkPaint paint;
141 paint.setColor(SK_ColorBLACK);
142
143 fTestDataIterator.rewind();
144 TestFontDataProvider::TestSet testSet;
145
146 while (fTestDataIterator.next(&testSet)) {
147 sk_sp<SkTypeface> testTypeface = SkTypeface_Make_Fontations(
148 SkStream::MakeFromFile(testSet.fontFilename.c_str()), SkFontArguments());
149 sk_sp<SkTypeface> ftTypeface = SkTypeface_FreeType::MakeFromStream(
150 SkStream::MakeFromFile(testSet.fontFilename.c_str()), SkFontArguments());
151
152 if (!testTypeface || !ftTypeface) {
153 *errorMsg = "Unable to initialize typeface.";
154 return DrawResult::kSkip;
155 }
156
157 auto configureFont = [this](SkFont& font) {
158 font.setSize(kFontSize);
159 font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
160 font.setSubpixel(true);
161 font.setHinting(fHintingMode);
162 };
163
164 SkFont font(testTypeface);
165 configureFont(font);
166
167 SkFont ftFont(ftTypeface);
168 configureFont(ftFont);
169 enum class DrawPhase { Fontations, FreeType, Comparison };
170
171 SkCanvas* drawCanvas = canvas;
172
173 // See https://issues.skia.org/issues/396360753
174 // We would like Fontations anti-aliasing on a surface with unknown pixel geometry to
175 // look like the FreeType backend in order to avoid perceived regressions
176 // in contrast/sharpness.
177 // Simulate the unknown geometry case for tests that request it.
178 sk_sp<SkSurface> surface = nullptr;
179 if (!wrapCanvasUnknownGeometry(canvas, surface)) {
180 return DrawResult::kFail;
181 }
182 drawCanvas = surface->getCanvas();
183
184 SkRect maxBounds = SkRect::MakeEmpty();
185 for (auto phase : {DrawPhase::Fontations, DrawPhase::FreeType, DrawPhase::Comparison}) {
186 SkScalar yCoord = kFontSize * 1.5f;
187
188 for (auto& langEntry : testSet.langSamples) {
189 auto shapeAndDrawToCanvas = [drawCanvas, paint, langEntry](const SkFont& font,
190 SkPoint coord) {
191 std::string testString(langEntry.sampleShort.c_str(),
192 langEntry.sampleShort.size());
193 SkTextBlobBuilderRunHandler textBlobBuilder(testString.c_str(), {0, 0});
194 std::unique_ptr<SkShaper> shaper = SkShaper::Make();
195 shaper->shape(testString.c_str(),
196 testString.size(),
197 font,
198 true,
199 999999, /* Don't linebreak. */
200 &textBlobBuilder);
201 sk_sp<const SkTextBlob> blob = textBlobBuilder.makeBlob();
202 drawCanvas->drawTextBlob(blob.get(), coord.x(), coord.y(), paint);
203 return blob->bounds();
204 };
205
206 auto roundToDevicePixels = [drawCanvas](SkPoint& point) {
207 SkMatrix ctm = drawCanvas->getLocalToDeviceAs3x3();
208 SkPoint mapped = ctm.mapPoint(point);
209 SkPoint mappedRounded =
210 SkPoint::Make(roundf(mapped.x()), roundf(mapped.y()));
211 SkMatrix inverse;
212 bool inverseExists = ctm.invert(&inverse);
213 SkASSERT(inverseExists);
214 if (inverseExists) {
215 point = inverse.mapPoint(mappedRounded);
216 }
217 };
218
219 auto fontationsCoord = [yCoord, roundToDevicePixels]() {
220 SkPoint fontationsCoord = SkPoint::Make(kMargin, yCoord);
221 roundToDevicePixels(fontationsCoord);
222 return fontationsCoord;
223 };
224
225 auto freetypeCoord = [yCoord, maxBounds, roundToDevicePixels]() {
226 SkPoint freetypeCoord = SkPoint::Make(
227 2 * kMargin + maxBounds.left() + maxBounds.width(), yCoord);
228 roundToDevicePixels(freetypeCoord);
229 return freetypeCoord;
230 };
231
232 switch (phase) {
233 case DrawPhase::Fontations: {
234 SkRect boundsFontations = shapeAndDrawToCanvas(font, fontationsCoord());
235 /* Determine maximum of column width across all language samples. */
236 boundsFontations.roundOut();
237 maxBounds.join(boundsFontations);
238 break;
239 }
240 case DrawPhase::FreeType: {
241 shapeAndDrawToCanvas(ftFont, freetypeCoord());
242 break;
243 }
244 case DrawPhase::Comparison: {
245 /* Read back pixels from equally sized rectangles from the space in
246 * SkCanvas where Fontations and FreeType sample texts were drawn,
247 * compare them using pixel comparisons similar to SkDiff, draw a
248 * comparison as faint pixel differences, and as an amplified
249 * visualization in which each differing pixel is drawn as white. */
250 SkPoint fontationsOrigin = fontationsCoord();
251 SkPoint freetypeOrigin = freetypeCoord();
252 SkRect fontationsBBox(maxBounds.makeOffset(fontationsOrigin));
253 SkRect freetypeBBox(maxBounds.makeOffset(freetypeOrigin));
254
255 SkMatrix ctm = drawCanvas->getLocalToDeviceAs3x3();
256 ctm.mapRect(&fontationsBBox, fontationsBBox);
257 ctm.mapRect(&freetypeBBox, freetypeBBox);
258
259 SkIRect fontationsIBox(fontationsBBox.roundOut());
260 SkIRect freetypeIBox(freetypeBBox.roundOut());
261
262 SkISize pixelDimensions(fontationsIBox.size());
263 SkImageInfo canvasImageInfo = drawCanvas->imageInfo();
264 SkImageInfo diffImageInfo =
265 SkImageInfo::Make(pixelDimensions,
266 SkColorType::kN32_SkColorType,
267 SkAlphaType::kUnpremul_SkAlphaType);
268
269 SkBitmap diffBitmap, highlightDiffBitmap;
270 diffBitmap.allocPixels(diffImageInfo, 0);
271 highlightDiffBitmap.allocPixels(diffImageInfo, 0);
272
273 // Workaround OveridePaintFilterCanvas limitations
274 // by getting pixel access through peekPixels()
275 // instead of readPixels(). Then use same pixmap to
276 // later write back the comparison results.
277 SkPixmap canvasPixmap;
278 if (!drawCanvas->peekPixels(&canvasPixmap)) {
279 break;
280 }
281
282 SkPixmap fontationsPixmap, freetypePixmap;
283 if (!canvasPixmap.extractSubset(&fontationsPixmap, fontationsIBox) ||
284 !canvasPixmap.extractSubset(&freetypePixmap, freetypeIBox)) {
285 break;
286 }
287
288 comparePixels(fontationsPixmap,
289 freetypePixmap,
290 &diffBitmap,
291 &highlightDiffBitmap);
292
293 /* Place comparison results as two extra columns, shift up to account
294 for placement of rectangles vs. SkTextBlobs (baseline shift). */
295 SkPoint comparisonCoord = ctm.mapPoint(SkPoint::Make(
296 3 * kMargin + maxBounds.width() * 2, yCoord + maxBounds.top()));
297 SkPoint whiteCoord = ctm.mapPoint(SkPoint::Make(
298 4 * kMargin + maxBounds.width() * 3, yCoord + maxBounds.top()));
299
300 SkSurfaceProps canvasSurfaceProps = drawCanvas->getBaseProps();
301 sk_sp<SkSurface> writeBackSurface =
302 SkSurfaces::WrapPixels(canvasPixmap, &canvasSurfaceProps);
303
304 writeBackSurface->writePixels(
305 diffBitmap, comparisonCoord.x(), comparisonCoord.y());
306 writeBackSurface->writePixels(
307 highlightDiffBitmap, whiteCoord.x(), whiteCoord.y());
308 break;
309 }
310 }
311
312 yCoord += font.getSize() * kLangYIncrementScale;
313 }
314 }
315 }
316
317 return DrawResult::kOk;
318 }
319
320 private:
321 using INHERITED = GM;
322
323 TestFontDataProvider fTestDataIterator;
324 SkString fTestName;
325 SimulatePixelGeometry fSimulatePixelGeometry;
326 SkFontHinting fHintingMode;
327 sk_sp<SkTypeface> fReportTypeface;
328 std::unique_ptr<SkFontArguments::VariationPosition::Coordinate[]> fCoordinates;
329 };
330
331 DEF_GM(return new FontationsFtCompareGM(
332 "NotoSans",
333 "Noto Sans",
334 "en_Latn|es_Latn|pt_Latn|id_Latn|ru_Cyrl|fr_Latn|tr_Latn|vi_Latn|de_"
335 "Latn|it_Latn|pl_Latn|nl_Latn|uk_Cyrl|gl_Latn|ro_Latn|cs_Latn|hu_Latn|"
336 "el_Grek|se_Latn|da_Latn|bg_Latn|sk_Latn|fi_Latn|bs_Latn|ca_Latn|no_"
337 "Latn|sr_Latn|sr_Cyrl|lt_Latn|hr_Latn|sl_Latn|uz_Latn|uz_Cyrl|lv_Latn|"
338 "et_Latn|az_Latn|az_Cyrl|la_Latn|tg_Latn|tg_Cyrl|sw_Latn|mn_Cyrl|kk_"
339 "Latn|kk_Cyrl|sq_Latn|af_Latn|ha_Latn|ky_Cyrl",
340 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
341
342 DEF_GM(return new FontationsFtCompareGM(
343 "NotoSans",
344 "Noto Sans",
345 "en_Latn|es_Latn|pt_Latn|id_Latn|ru_Cyrl|fr_Latn|tr_Latn|vi_Latn|de_"
346 "Latn|it_Latn|pl_Latn|nl_Latn|uk_Cyrl|gl_Latn|ro_Latn|cs_Latn|hu_Latn|"
347 "el_Grek|se_Latn|da_Latn|bg_Latn|sk_Latn|fi_Latn|bs_Latn|ca_Latn|no_"
348 "Latn|sr_Latn|sr_Cyrl|lt_Latn|hr_Latn|sl_Latn|uz_Latn|uz_Cyrl|lv_Latn|"
349 "et_Latn|az_Latn|az_Cyrl|la_Latn|tg_Latn|tg_Cyrl|sw_Latn|mn_Cyrl|kk_"
350 "Latn|kk_Cyrl|sq_Latn|af_Latn|ha_Latn|ky_Cyrl",
351 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs,
352 SkFontHinting::kSlight));
353
354 DEF_GM(return new FontationsFtCompareGM(
355 "NotoSans",
356 "Noto Sans",
357 "en_Latn|es_Latn|pt_Latn|id_Latn|ru_Cyrl|fr_Latn|tr_Latn|vi_Latn|de_"
358 "Latn|it_Latn|pl_Latn|nl_Latn|uk_Cyrl|gl_Latn|ro_Latn|cs_Latn|hu_Latn|"
359 "el_Grek|se_Latn|da_Latn|bg_Latn|sk_Latn|fi_Latn|bs_Latn|ca_Latn|no_"
360 "Latn|sr_Latn|sr_Cyrl|lt_Latn|hr_Latn|sl_Latn|uz_Latn|uz_Cyrl|lv_Latn|"
361 "et_Latn|az_Latn|az_Cyrl|la_Latn|tg_Latn|tg_Cyrl|sw_Latn|mn_Cyrl|kk_"
362 "Latn|kk_Cyrl|sq_Latn|af_Latn|ha_Latn|ky_Cyrl",
363 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs,
364 SkFontHinting::kNormal));
365
366 DEF_GM(return new FontationsFtCompareGM(
367 "NotoSans",
368 "Noto Sans",
369 "en_Latn|es_Latn|pt_Latn|id_Latn|ru_Cyrl|fr_Latn|tr_Latn|vi_Latn|de_"
370 "Latn|it_Latn|pl_Latn|nl_Latn|uk_Cyrl|gl_Latn|ro_Latn|cs_Latn|hu_Latn|"
371 "el_Grek|se_Latn|da_Latn|bg_Latn|sk_Latn|fi_Latn|bs_Latn|ca_Latn|no_"
372 "Latn|sr_Latn|sr_Cyrl|lt_Latn|hr_Latn|sl_Latn|uz_Latn|uz_Cyrl|lv_Latn|"
373 "et_Latn|az_Latn|az_Cyrl|la_Latn|tg_Latn|tg_Cyrl|sw_Latn|mn_Cyrl|kk_"
374 "Latn|kk_Cyrl|sq_Latn|af_Latn|ha_Latn|ky_Cyrl",
375 FontationsFtCompareGM::SimulatePixelGeometry::kSimulateUnknown));
376
377 DEF_GM(return new FontationsFtCompareGM(
378 "NotoSans",
379 "Noto Sans",
380 "en_Latn|es_Latn|pt_Latn|id_Latn|ru_Cyrl|fr_Latn|tr_Latn|vi_Latn|de_"
381 "Latn|it_Latn|pl_Latn|nl_Latn|uk_Cyrl|gl_Latn|ro_Latn|cs_Latn|hu_Latn|"
382 "el_Grek|se_Latn|da_Latn|bg_Latn|sk_Latn|fi_Latn|bs_Latn|ca_Latn|no_"
383 "Latn|sr_Latn|sr_Cyrl|lt_Latn|hr_Latn|sl_Latn|uz_Latn|uz_Cyrl|lv_Latn|"
384 "et_Latn|az_Latn|az_Cyrl|la_Latn|tg_Latn|tg_Cyrl|sw_Latn|mn_Cyrl|kk_"
385 "Latn|kk_Cyrl|sq_Latn|af_Latn|ha_Latn|ky_Cyrl",
386 FontationsFtCompareGM::SimulatePixelGeometry::kSimulateUnknown,
387 SkFontHinting::kSlight));
388
389 DEF_GM(return new FontationsFtCompareGM(
390 "NotoSans",
391 "Noto Sans",
392 "en_Latn|es_Latn|pt_Latn|id_Latn|ru_Cyrl|fr_Latn|tr_Latn|vi_Latn|de_"
393 "Latn|it_Latn|pl_Latn|nl_Latn|uk_Cyrl|gl_Latn|ro_Latn|cs_Latn|hu_Latn|"
394 "el_Grek|se_Latn|da_Latn|bg_Latn|sk_Latn|fi_Latn|bs_Latn|ca_Latn|no_"
395 "Latn|sr_Latn|sr_Cyrl|lt_Latn|hr_Latn|sl_Latn|uz_Latn|uz_Cyrl|lv_Latn|"
396 "et_Latn|az_Latn|az_Cyrl|la_Latn|tg_Latn|tg_Cyrl|sw_Latn|mn_Cyrl|kk_"
397 "Latn|kk_Cyrl|sq_Latn|af_Latn|ha_Latn|ky_Cyrl",
398 FontationsFtCompareGM::SimulatePixelGeometry::kSimulateUnknown,
399 SkFontHinting::kNormal));
400
401 DEF_GM(return new FontationsFtCompareGM("NotoSans_Deva",
402 "Noto Sans Devanagari",
403 "hi_Deva|mr_Deva",
404 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
405
406 DEF_GM(return new FontationsFtCompareGM("NotoSans_Deva",
407 "Noto Sans Devanagari",
408 "hi_Deva|mr_Deva",
409 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs,
410 SkFontHinting::kSlight));
411
412 DEF_GM(return new FontationsFtCompareGM("NotoSans_Deva",
413 "Noto Sans Devanagari",
414 "hi_Deva|mr_Deva",
415 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs,
416 SkFontHinting::kNormal));
417
418 DEF_GM(return new FontationsFtCompareGM("NotoSans_ar_Arab",
419 "Noto Sans Arabic",
420 "ar_Arab|uz_Arab|kk_Arab|ky_Arab",
421 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
422
423 DEF_GM(return new FontationsFtCompareGM("NotoSans_ar_Arab",
424 "Noto Sans Arabic",
425 "ar_Arab|uz_Arab|kk_Arab|ky_Arab",
426 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs,
427 SkFontHinting::kSlight));
428
429 DEF_GM(return new FontationsFtCompareGM("NotoSans_ar_Arab",
430 "Noto Sans Arabic",
431 "ar_Arab|uz_Arab|kk_Arab|ky_Arab",
432 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs,
433 SkFontHinting::kNormal));
434
435 DEF_GM(return new FontationsFtCompareGM("NotoSans_Beng",
436 "Noto Sans Bengali",
437 "bn_Beng",
438 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
439
440 DEF_GM(return new FontationsFtCompareGM("NotoSans_Jpan",
441 "Noto Sans JP",
442 "ja_Jpan",
443 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
444
445 DEF_GM(return new FontationsFtCompareGM("NotoSans_Thai",
446 "Noto Sans Thai",
447 "th_Thai",
448 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
449
450 DEF_GM(return new FontationsFtCompareGM("NotoSans_Hans",
451 "Noto Sans SC",
452 "zh_Hans",
453 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
454
455 DEF_GM(return new FontationsFtCompareGM("NotoSans_Hant",
456 "Noto Sans TC",
457 "zh_Hant",
458 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
459
460 DEF_GM(return new FontationsFtCompareGM("NotoSans_Kore",
461 "Noto Sans KR",
462 "ko_Kore",
463 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
464
465 DEF_GM(return new FontationsFtCompareGM("NotoSans_Taml",
466 "Noto Sans Tamil",
467 "ta_Taml",
468 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
469
470 DEF_GM(return new FontationsFtCompareGM("NotoSans_Newa",
471 "Noto Sans Newa",
472 "new_Newa",
473 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
474
475 DEF_GM(return new FontationsFtCompareGM("NotoSans_Knda",
476 "Noto Sans Kannada",
477 "kn_Knda",
478 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
479
480 DEF_GM(return new FontationsFtCompareGM("NotoSans_Tglg",
481 "Noto Sans Tagalog",
482 "fil_Tglg",
483 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
484
485 DEF_GM(return new FontationsFtCompareGM("NotoSans_Telu",
486 "Noto Sans Telugu",
487 "te_Telu",
488 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
489
490 DEF_GM(return new FontationsFtCompareGM("NotoSans_Gujr",
491 "Noto Sans Gujarati",
492 "gu_Gujr",
493 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
494
495 DEF_GM(return new FontationsFtCompareGM("NotoSans_Geor",
496 "Noto Sans Georgian",
497 "ka_Geor",
498 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
499
500 DEF_GM(return new FontationsFtCompareGM("NotoSans_Mlym",
501 "Noto Sans Malayalam",
502 "ml_Mlym",
503 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
504
505 DEF_GM(return new FontationsFtCompareGM("NotoSans_Khmr",
506 "Noto Sans Khmer",
507 "km_Khmr",
508 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
509
510 DEF_GM(return new FontationsFtCompareGM("NotoSans_Sinh",
511 "Noto Sans Sinhala",
512 "si_Sinh",
513 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
514
515 DEF_GM(return new FontationsFtCompareGM("NotoSans_Mymr",
516 "Noto Sans Myanmar",
517 "my_Mymr",
518 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
519
520 DEF_GM(return new FontationsFtCompareGM("NotoSans_Java",
521 "Noto Sans Javanese",
522 "jv_Java",
523 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
524
525 DEF_GM(return new FontationsFtCompareGM("NotoSans_Mong",
526 "Noto Sans Mongolian",
527 "mn_Mong",
528 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
529
530 DEF_GM(return new FontationsFtCompareGM("NotoSans_Armn",
531 "Noto Sans Armenian",
532 "hy_Armn",
533 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
534
535 DEF_GM(return new FontationsFtCompareGM("NotoSans_Elba",
536 "Noto Sans Elbasan",
537 "sq_Elba",
538 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
539
540 DEF_GM(return new FontationsFtCompareGM("NotoSans_Vith",
541 "Noto Sans Vithkuqi",
542 "sq_Vith",
543 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
544
545 DEF_GM(return new FontationsFtCompareGM("NotoSans_Guru",
546 "Noto Sans Gurmukhi",
547 "pa_Guru",
548 FontationsFtCompareGM::SimulatePixelGeometry::kLeaveAsIs));
549
550 } // namespace skiagm
551