• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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