xref: /aosp_15_r20/external/skia/gm/fontmgr.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2013 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "gm/gm.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkColor.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontMetrics.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontMgr.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontStyle.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontTypes.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkGraphics.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPathEffect.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypeface.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkDashPathEffect.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkFontPriv.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "tools/SkMetaData.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
35*c8dee2aaSAndroid Build Coastguard Worker 
36*c8dee2aaSAndroid Build Coastguard Worker // limit this just so we don't take too long to draw
37*c8dee2aaSAndroid Build Coastguard Worker #define MAX_FAMILIES    30
38*c8dee2aaSAndroid Build Coastguard Worker 
drawString(SkCanvas * canvas,const SkString & text,SkScalar x,SkScalar y,const SkFont & font)39*c8dee2aaSAndroid Build Coastguard Worker static SkScalar drawString(SkCanvas* canvas, const SkString& text, SkScalar x,
40*c8dee2aaSAndroid Build Coastguard Worker                            SkScalar y, const SkFont& font) {
41*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawString(text, x, y, font, SkPaint());
42*c8dee2aaSAndroid Build Coastguard Worker     return x + font.measureText(text.c_str(), text.size(), SkTextEncoding::kUTF8);
43*c8dee2aaSAndroid Build Coastguard Worker }
44*c8dee2aaSAndroid Build Coastguard Worker 
drawCharacter(SkCanvas * canvas,uint32_t character,SkScalar x,SkScalar y,const SkFont & origFont,SkFontMgr * fm,const char * fontName,const char * bcp47[],int bcp47Count,const SkFontStyle & fontStyle)45*c8dee2aaSAndroid Build Coastguard Worker static SkScalar drawCharacter(SkCanvas* canvas, uint32_t character, SkScalar x,
46*c8dee2aaSAndroid Build Coastguard Worker                               SkScalar y, const SkFont& origFont, SkFontMgr* fm,
47*c8dee2aaSAndroid Build Coastguard Worker                               const char* fontName, const char* bcp47[], int bcp47Count,
48*c8dee2aaSAndroid Build Coastguard Worker                               const SkFontStyle& fontStyle) {
49*c8dee2aaSAndroid Build Coastguard Worker     SkFont font = origFont;
50*c8dee2aaSAndroid Build Coastguard Worker     // find typeface containing the requested character and draw it
51*c8dee2aaSAndroid Build Coastguard Worker     SkString ch;
52*c8dee2aaSAndroid Build Coastguard Worker     ch.appendUnichar(character);
53*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkTypeface> typeface(fm->matchFamilyStyleCharacter(fontName, fontStyle,
54*c8dee2aaSAndroid Build Coastguard Worker                                                              bcp47, bcp47Count, character));
55*c8dee2aaSAndroid Build Coastguard Worker     font.setTypeface(typeface);
56*c8dee2aaSAndroid Build Coastguard Worker     x = drawString(canvas, ch, x, y, font) + 20;
57*c8dee2aaSAndroid Build Coastguard Worker 
58*c8dee2aaSAndroid Build Coastguard Worker     if (nullptr == typeface) {
59*c8dee2aaSAndroid Build Coastguard Worker         return x;
60*c8dee2aaSAndroid Build Coastguard Worker     }
61*c8dee2aaSAndroid Build Coastguard Worker 
62*c8dee2aaSAndroid Build Coastguard Worker     // repeat the process, but this time use the family name of the typeface
63*c8dee2aaSAndroid Build Coastguard Worker     // from the first pass.  This emulates the behavior in Blink where it
64*c8dee2aaSAndroid Build Coastguard Worker     // it expects to get the same glyph when following this pattern.
65*c8dee2aaSAndroid Build Coastguard Worker     SkString familyName;
66*c8dee2aaSAndroid Build Coastguard Worker     typeface->getFamilyName(&familyName);
67*c8dee2aaSAndroid Build Coastguard Worker     font.setTypeface(fm->legacyMakeTypeface(familyName.c_str(), typeface->fontStyle()));
68*c8dee2aaSAndroid Build Coastguard Worker     return drawString(canvas, ch, x, y, font) + 20;
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker 
71*c8dee2aaSAndroid Build Coastguard Worker static const char* zh = "zh";
72*c8dee2aaSAndroid Build Coastguard Worker static const char* ja = "ja";
73*c8dee2aaSAndroid Build Coastguard Worker 
74*c8dee2aaSAndroid Build Coastguard Worker class FontMgrGM : public skiagm::GM {
75*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkFontMgr> fFM;
76*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()77*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
78*c8dee2aaSAndroid Build Coastguard Worker         SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
79*c8dee2aaSAndroid Build Coastguard Worker         fFM = ToolUtils::TestFontMgr();
80*c8dee2aaSAndroid Build Coastguard Worker     }
81*c8dee2aaSAndroid Build Coastguard Worker 
getName() const82*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("fontmgr_iter"); }
83*c8dee2aaSAndroid Build Coastguard Worker 
getISize()84*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {1536, 768}; }
85*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * errorMsg)86*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
87*c8dee2aaSAndroid Build Coastguard Worker         SkScalar y = 20;
88*c8dee2aaSAndroid Build Coastguard Worker         SkFont font = ToolUtils::DefaultFont();
89*c8dee2aaSAndroid Build Coastguard Worker         font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
90*c8dee2aaSAndroid Build Coastguard Worker         font.setSubpixel(true);
91*c8dee2aaSAndroid Build Coastguard Worker         font.setSize(17);
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker         SkFontMgr* fm = fFM.get();
94*c8dee2aaSAndroid Build Coastguard Worker         int count = std::min(fm->countFamilies(), MAX_FAMILIES);
95*c8dee2aaSAndroid Build Coastguard Worker         if (count == 0) {
96*c8dee2aaSAndroid Build Coastguard Worker             *errorMsg = "No families in SkFontMgr";
97*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
98*c8dee2aaSAndroid Build Coastguard Worker         }
99*c8dee2aaSAndroid Build Coastguard Worker 
100*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < count; ++i) {
101*c8dee2aaSAndroid Build Coastguard Worker             SkString familyName;
102*c8dee2aaSAndroid Build Coastguard Worker             fm->getFamilyName(i, &familyName);
103*c8dee2aaSAndroid Build Coastguard Worker             font.setTypeface(ToolUtils::DefaultTypeface());
104*c8dee2aaSAndroid Build Coastguard Worker             (void)drawString(canvas, familyName, 20, y, font);
105*c8dee2aaSAndroid Build Coastguard Worker 
106*c8dee2aaSAndroid Build Coastguard Worker             SkScalar x = 220;
107*c8dee2aaSAndroid Build Coastguard Worker 
108*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
109*c8dee2aaSAndroid Build Coastguard Worker             for (int j = 0; j < set->count(); ++j) {
110*c8dee2aaSAndroid Build Coastguard Worker                 SkString sname;
111*c8dee2aaSAndroid Build Coastguard Worker                 SkFontStyle fs;
112*c8dee2aaSAndroid Build Coastguard Worker                 set->getStyle(j, &fs, &sname);
113*c8dee2aaSAndroid Build Coastguard Worker                 sname.appendf(" [%d %d %d]", fs.weight(), fs.width(), fs.slant());
114*c8dee2aaSAndroid Build Coastguard Worker 
115*c8dee2aaSAndroid Build Coastguard Worker                 font.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
116*c8dee2aaSAndroid Build Coastguard Worker                 x = drawString(canvas, sname, x, y, font) + 20;
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker                 // check to see that we get different glyphs in japanese and chinese
119*c8dee2aaSAndroid Build Coastguard Worker                 x = drawCharacter(canvas, 0x5203, x, y, font, fm, familyName.c_str(), &zh, 1, fs);
120*c8dee2aaSAndroid Build Coastguard Worker                 x = drawCharacter(canvas, 0x5203, x, y, font, fm, familyName.c_str(), &ja, 1, fs);
121*c8dee2aaSAndroid Build Coastguard Worker                 // check that emoji characters are found
122*c8dee2aaSAndroid Build Coastguard Worker                 x = drawCharacter(canvas, 0x1f601, x, y, font, fm, familyName.c_str(), nullptr,0, fs);
123*c8dee2aaSAndroid Build Coastguard Worker             }
124*c8dee2aaSAndroid Build Coastguard Worker             y += 24;
125*c8dee2aaSAndroid Build Coastguard Worker         }
126*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
127*c8dee2aaSAndroid Build Coastguard Worker     }
128*c8dee2aaSAndroid Build Coastguard Worker };
129*c8dee2aaSAndroid Build Coastguard Worker 
130*c8dee2aaSAndroid Build Coastguard Worker class FontMgrMatchGM : public skiagm::GM {
131*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkFontMgr> fFM;
132*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()133*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override {
134*c8dee2aaSAndroid Build Coastguard Worker         fFM = ToolUtils::TestFontMgr();
135*c8dee2aaSAndroid Build Coastguard Worker         SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
136*c8dee2aaSAndroid Build Coastguard Worker     }
137*c8dee2aaSAndroid Build Coastguard Worker 
getName() const138*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override { return SkString("fontmgr_match"); }
139*c8dee2aaSAndroid Build Coastguard Worker 
getISize()140*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {640, 1024}; }
141*c8dee2aaSAndroid Build Coastguard Worker 
iterateFamily(SkCanvas * canvas,const SkFont & font,SkFontStyleSet * fset)142*c8dee2aaSAndroid Build Coastguard Worker     void iterateFamily(SkCanvas* canvas, const SkFont& font, SkFontStyleSet* fset) {
143*c8dee2aaSAndroid Build Coastguard Worker         SkFont f(font);
144*c8dee2aaSAndroid Build Coastguard Worker         SkScalar y = 0;
145*c8dee2aaSAndroid Build Coastguard Worker 
146*c8dee2aaSAndroid Build Coastguard Worker         for (int j = 0; j < fset->count(); ++j) {
147*c8dee2aaSAndroid Build Coastguard Worker             SkString sname;
148*c8dee2aaSAndroid Build Coastguard Worker             SkFontStyle fs;
149*c8dee2aaSAndroid Build Coastguard Worker             fset->getStyle(j, &fs, &sname);
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker             sname.appendf(" [%d %d]", fs.weight(), fs.width());
152*c8dee2aaSAndroid Build Coastguard Worker 
153*c8dee2aaSAndroid Build Coastguard Worker             f.setTypeface(sk_sp<SkTypeface>(fset->createTypeface(j)));
154*c8dee2aaSAndroid Build Coastguard Worker             (void)drawString(canvas, sname, 0, y, f);
155*c8dee2aaSAndroid Build Coastguard Worker             y += 24;
156*c8dee2aaSAndroid Build Coastguard Worker         }
157*c8dee2aaSAndroid Build Coastguard Worker     }
158*c8dee2aaSAndroid Build Coastguard Worker 
exploreFamily(SkCanvas * canvas,const SkFont & font,SkFontStyleSet * fset)159*c8dee2aaSAndroid Build Coastguard Worker     void exploreFamily(SkCanvas* canvas, const SkFont& font, SkFontStyleSet* fset) {
160*c8dee2aaSAndroid Build Coastguard Worker         SkFont f(font);
161*c8dee2aaSAndroid Build Coastguard Worker         SkScalar y = 0;
162*c8dee2aaSAndroid Build Coastguard Worker 
163*c8dee2aaSAndroid Build Coastguard Worker         for (int weight = 100; weight <= 900; weight += 200) {
164*c8dee2aaSAndroid Build Coastguard Worker             for (int width = 1; width <= 9; width += 2) {
165*c8dee2aaSAndroid Build Coastguard Worker                 SkFontStyle fs(weight, width, SkFontStyle::kUpright_Slant);
166*c8dee2aaSAndroid Build Coastguard Worker                 sk_sp<SkTypeface> face(fset->matchStyle(fs));
167*c8dee2aaSAndroid Build Coastguard Worker                 if (face) {
168*c8dee2aaSAndroid Build Coastguard Worker                     SkString str;
169*c8dee2aaSAndroid Build Coastguard Worker                     str.printf("request [%d %d]", fs.weight(), fs.width());
170*c8dee2aaSAndroid Build Coastguard Worker                     f.setTypeface(std::move(face));
171*c8dee2aaSAndroid Build Coastguard Worker                     (void)drawString(canvas, str, 0, y, f);
172*c8dee2aaSAndroid Build Coastguard Worker                     y += 24;
173*c8dee2aaSAndroid Build Coastguard Worker                 }
174*c8dee2aaSAndroid Build Coastguard Worker             }
175*c8dee2aaSAndroid Build Coastguard Worker         }
176*c8dee2aaSAndroid Build Coastguard Worker     }
177*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * errorMsg)178*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
179*c8dee2aaSAndroid Build Coastguard Worker         SkFont font = ToolUtils::DefaultFont();
180*c8dee2aaSAndroid Build Coastguard Worker         font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
181*c8dee2aaSAndroid Build Coastguard Worker         font.setSubpixel(true);
182*c8dee2aaSAndroid Build Coastguard Worker         font.setSize(17);
183*c8dee2aaSAndroid Build Coastguard Worker 
184*c8dee2aaSAndroid Build Coastguard Worker         const char* gNames[] = {
185*c8dee2aaSAndroid Build Coastguard Worker             "Helvetica Neue", "Arial", "sans", "Roboto"
186*c8dee2aaSAndroid Build Coastguard Worker         };
187*c8dee2aaSAndroid Build Coastguard Worker 
188*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkFontStyleSet> fset;
189*c8dee2aaSAndroid Build Coastguard Worker         for (size_t i = 0; i < std::size(gNames); ++i) {
190*c8dee2aaSAndroid Build Coastguard Worker             fset = fFM->matchFamily(gNames[i]);
191*c8dee2aaSAndroid Build Coastguard Worker             if (fset->count() > 0) {
192*c8dee2aaSAndroid Build Coastguard Worker                 break;
193*c8dee2aaSAndroid Build Coastguard Worker             }
194*c8dee2aaSAndroid Build Coastguard Worker         }
195*c8dee2aaSAndroid Build Coastguard Worker         if (!fset || fset->count() == 0) {
196*c8dee2aaSAndroid Build Coastguard Worker             *errorMsg = "No SkFontStyleSet";
197*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
198*c8dee2aaSAndroid Build Coastguard Worker         }
199*c8dee2aaSAndroid Build Coastguard Worker 
200*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(20, 40);
201*c8dee2aaSAndroid Build Coastguard Worker         this->exploreFamily(canvas, font, fset.get());
202*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(150, 0);
203*c8dee2aaSAndroid Build Coastguard Worker         this->iterateFamily(canvas, font, fset.get());
204*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
205*c8dee2aaSAndroid Build Coastguard Worker     }
206*c8dee2aaSAndroid Build Coastguard Worker };
207*c8dee2aaSAndroid Build Coastguard Worker 
208*c8dee2aaSAndroid Build Coastguard Worker class FontMgrBoundsGM : public skiagm::GM {
209*c8dee2aaSAndroid Build Coastguard Worker public:
FontMgrBoundsGM(float scale,float skew)210*c8dee2aaSAndroid Build Coastguard Worker     FontMgrBoundsGM(float scale, float skew) : fScaleX(scale) , fSkewX(skew) {}
211*c8dee2aaSAndroid Build Coastguard Worker 
212*c8dee2aaSAndroid Build Coastguard Worker private:
getName() const213*c8dee2aaSAndroid Build Coastguard Worker     SkString getName() const override {
214*c8dee2aaSAndroid Build Coastguard Worker         if (fScaleX != 1 || fSkewX != 0) {
215*c8dee2aaSAndroid Build Coastguard Worker             return SkStringPrintf("fontmgr_bounds_%g_%g", fScaleX, fSkewX);
216*c8dee2aaSAndroid Build Coastguard Worker         }
217*c8dee2aaSAndroid Build Coastguard Worker         return SkString("fontmgr_bounds");
218*c8dee2aaSAndroid Build Coastguard Worker     }
219*c8dee2aaSAndroid Build Coastguard Worker 
onOnceBeforeDraw()220*c8dee2aaSAndroid Build Coastguard Worker     void onOnceBeforeDraw() override { fFM = ToolUtils::TestFontMgr(); }
221*c8dee2aaSAndroid Build Coastguard Worker 
onGetControls(SkMetaData * controls)222*c8dee2aaSAndroid Build Coastguard Worker     bool onGetControls(SkMetaData* controls) override {
223*c8dee2aaSAndroid Build Coastguard Worker         controls->setBool("Label Bounds", fLabelBounds);
224*c8dee2aaSAndroid Build Coastguard Worker         return true;
225*c8dee2aaSAndroid Build Coastguard Worker     }
226*c8dee2aaSAndroid Build Coastguard Worker 
onSetControls(const SkMetaData & controls)227*c8dee2aaSAndroid Build Coastguard Worker     void onSetControls(const SkMetaData& controls) override {
228*c8dee2aaSAndroid Build Coastguard Worker         controls.findBool("Label Bounds", &fLabelBounds);
229*c8dee2aaSAndroid Build Coastguard Worker     }
230*c8dee2aaSAndroid Build Coastguard Worker 
show_bounds(SkCanvas * canvas,const SkFont & font,SkScalar x,SkScalar y,SkColor boundsColor,bool labelBounds)231*c8dee2aaSAndroid Build Coastguard Worker     static SkRect show_bounds(SkCanvas* canvas, const SkFont& font, SkScalar x, SkScalar y,
232*c8dee2aaSAndroid Build Coastguard Worker                               SkColor boundsColor, bool labelBounds)
233*c8dee2aaSAndroid Build Coastguard Worker     {
234*c8dee2aaSAndroid Build Coastguard Worker         SkGlyphID left = 0, right = 0, top = 0, bottom = 0;
235*c8dee2aaSAndroid Build Coastguard Worker         SkRect min = SkRect::MakeLTRB(SK_ScalarInfinity, SK_ScalarInfinity,
236*c8dee2aaSAndroid Build Coastguard Worker                                       SK_ScalarNegativeInfinity, SK_ScalarNegativeInfinity);
237*c8dee2aaSAndroid Build Coastguard Worker         {
238*c8dee2aaSAndroid Build Coastguard Worker             int numGlyphs = font.getTypeface()->countGlyphs();
239*c8dee2aaSAndroid Build Coastguard Worker             for (int i = 0; i < numGlyphs; ++i) {
240*c8dee2aaSAndroid Build Coastguard Worker                 SkGlyphID glyphId = i;
241*c8dee2aaSAndroid Build Coastguard Worker                 SkRect cur;
242*c8dee2aaSAndroid Build Coastguard Worker                 font.getBounds(&glyphId, 1, &cur, nullptr);
243*c8dee2aaSAndroid Build Coastguard Worker                 if (cur.fLeft   < min.fLeft  ) { min.fLeft   = cur.fLeft;   left   = i; }
244*c8dee2aaSAndroid Build Coastguard Worker                 if (cur.fTop    < min.fTop   ) { min.fTop    = cur.fTop ;   top    = i; }
245*c8dee2aaSAndroid Build Coastguard Worker                 if (min.fRight  < cur.fRight ) { min.fRight  = cur.fRight;  right  = i; }
246*c8dee2aaSAndroid Build Coastguard Worker                 if (min.fBottom < cur.fBottom) { min.fBottom = cur.fBottom; bottom = i; }
247*c8dee2aaSAndroid Build Coastguard Worker             }
248*c8dee2aaSAndroid Build Coastguard Worker         }
249*c8dee2aaSAndroid Build Coastguard Worker 
250*c8dee2aaSAndroid Build Coastguard Worker         SkRect fontBounds = SkFontPriv::GetFontBounds(font);
251*c8dee2aaSAndroid Build Coastguard Worker 
252*c8dee2aaSAndroid Build Coastguard Worker         SkRect drawBounds = min;
253*c8dee2aaSAndroid Build Coastguard Worker         drawBounds.join(fontBounds);
254*c8dee2aaSAndroid Build Coastguard Worker 
255*c8dee2aaSAndroid Build Coastguard Worker         SkAutoCanvasRestore acr(canvas, true);
256*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(x - drawBounds.left(), y);
257*c8dee2aaSAndroid Build Coastguard Worker 
258*c8dee2aaSAndroid Build Coastguard Worker         SkPaint boundsPaint;
259*c8dee2aaSAndroid Build Coastguard Worker         boundsPaint.setAntiAlias(true);
260*c8dee2aaSAndroid Build Coastguard Worker         boundsPaint.setColor(boundsColor);
261*c8dee2aaSAndroid Build Coastguard Worker         boundsPaint.setStyle(SkPaint::kStroke_Style);
262*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawRect(fontBounds, boundsPaint);
263*c8dee2aaSAndroid Build Coastguard Worker 
264*c8dee2aaSAndroid Build Coastguard Worker         const SkScalar intervals[] = { 10.f, 10.f };
265*c8dee2aaSAndroid Build Coastguard Worker         boundsPaint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0.f));
266*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawRect(min, boundsPaint);
267*c8dee2aaSAndroid Build Coastguard Worker 
268*c8dee2aaSAndroid Build Coastguard Worker         SkFontMetrics fm;
269*c8dee2aaSAndroid Build Coastguard Worker         font.getMetrics(&fm);
270*c8dee2aaSAndroid Build Coastguard Worker         SkPaint metricsPaint(boundsPaint);
271*c8dee2aaSAndroid Build Coastguard Worker         metricsPaint.setStyle(SkPaint::kFill_Style);
272*c8dee2aaSAndroid Build Coastguard Worker         metricsPaint.setAlphaf(0.25f);
273*c8dee2aaSAndroid Build Coastguard Worker         if ((fm.fFlags & SkFontMetrics::kUnderlinePositionIsValid_Flag) &&
274*c8dee2aaSAndroid Build Coastguard Worker             (fm.fFlags & SkFontMetrics::kUnderlineThicknessIsValid_Flag))
275*c8dee2aaSAndroid Build Coastguard Worker         {
276*c8dee2aaSAndroid Build Coastguard Worker             SkRect underline{ min.fLeft,  fm.fUnderlinePosition,
277*c8dee2aaSAndroid Build Coastguard Worker                               min.fRight, fm.fUnderlinePosition + fm.fUnderlineThickness };
278*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawRect(underline, metricsPaint);
279*c8dee2aaSAndroid Build Coastguard Worker         }
280*c8dee2aaSAndroid Build Coastguard Worker 
281*c8dee2aaSAndroid Build Coastguard Worker         if ((fm.fFlags & SkFontMetrics::kStrikeoutPositionIsValid_Flag) &&
282*c8dee2aaSAndroid Build Coastguard Worker             (fm.fFlags & SkFontMetrics::kStrikeoutThicknessIsValid_Flag))
283*c8dee2aaSAndroid Build Coastguard Worker         {
284*c8dee2aaSAndroid Build Coastguard Worker             SkRect strikeout{ min.fLeft,  fm.fStrikeoutPosition - fm.fStrikeoutThickness,
285*c8dee2aaSAndroid Build Coastguard Worker                               min.fRight, fm.fStrikeoutPosition };
286*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawRect(strikeout, metricsPaint);
287*c8dee2aaSAndroid Build Coastguard Worker         }
288*c8dee2aaSAndroid Build Coastguard Worker 
289*c8dee2aaSAndroid Build Coastguard Worker         struct GlyphToDraw {
290*c8dee2aaSAndroid Build Coastguard Worker             SkGlyphID id;
291*c8dee2aaSAndroid Build Coastguard Worker             SkPoint location;
292*c8dee2aaSAndroid Build Coastguard Worker             SkScalar rotation;
293*c8dee2aaSAndroid Build Coastguard Worker         } glyphsToDraw [] = {
294*c8dee2aaSAndroid Build Coastguard Worker             {left,   {min.left(),    min.centerY()}, 270},
295*c8dee2aaSAndroid Build Coastguard Worker             {right,  {min.right(),   min.centerY()},  90},
296*c8dee2aaSAndroid Build Coastguard Worker             {top,    {min.centerX(), min.top()    },   0},
297*c8dee2aaSAndroid Build Coastguard Worker             {bottom, {min.centerX(), min.bottom() }, 180},
298*c8dee2aaSAndroid Build Coastguard Worker         };
299*c8dee2aaSAndroid Build Coastguard Worker 
300*c8dee2aaSAndroid Build Coastguard Worker         SkFont labelFont;
301*c8dee2aaSAndroid Build Coastguard Worker         labelFont.setEdging(SkFont::Edging::kAntiAlias);
302*c8dee2aaSAndroid Build Coastguard Worker         labelFont.setTypeface(ToolUtils::DefaultPortableTypeface());
303*c8dee2aaSAndroid Build Coastguard Worker 
304*c8dee2aaSAndroid Build Coastguard Worker         if (labelBounds) {
305*c8dee2aaSAndroid Build Coastguard Worker             SkString name;
306*c8dee2aaSAndroid Build Coastguard Worker             font.getTypeface()->getFamilyName(&name);
307*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawString(name, min.fLeft, min.fBottom, labelFont, SkPaint());
308*c8dee2aaSAndroid Build Coastguard Worker         }
309*c8dee2aaSAndroid Build Coastguard Worker         for (const GlyphToDraw& glyphToDraw : glyphsToDraw) {
310*c8dee2aaSAndroid Build Coastguard Worker             SkPath path;
311*c8dee2aaSAndroid Build Coastguard Worker             font.getPath(glyphToDraw.id, &path);
312*c8dee2aaSAndroid Build Coastguard Worker             SkPaint::Style style = path.isEmpty() ? SkPaint::kFill_Style : SkPaint::kStroke_Style;
313*c8dee2aaSAndroid Build Coastguard Worker             SkPaint glyphPaint;
314*c8dee2aaSAndroid Build Coastguard Worker             glyphPaint.setStyle(style);
315*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawSimpleText(&glyphToDraw.id, sizeof(glyphToDraw.id),
316*c8dee2aaSAndroid Build Coastguard Worker                                    SkTextEncoding::kGlyphID, 0, 0, font, glyphPaint);
317*c8dee2aaSAndroid Build Coastguard Worker 
318*c8dee2aaSAndroid Build Coastguard Worker             if (labelBounds) {
319*c8dee2aaSAndroid Build Coastguard Worker                 SkAutoCanvasRestore acr2(canvas, true);
320*c8dee2aaSAndroid Build Coastguard Worker                 canvas->translate(glyphToDraw.location.fX, glyphToDraw.location.fY);
321*c8dee2aaSAndroid Build Coastguard Worker                 canvas->rotate(glyphToDraw.rotation);
322*c8dee2aaSAndroid Build Coastguard Worker                 SkString glyphStr;
323*c8dee2aaSAndroid Build Coastguard Worker                 glyphStr.appendS32(glyphToDraw.id);
324*c8dee2aaSAndroid Build Coastguard Worker                 canvas->drawString(glyphStr, 0, 0, labelFont, SkPaint());
325*c8dee2aaSAndroid Build Coastguard Worker             }
326*c8dee2aaSAndroid Build Coastguard Worker         }
327*c8dee2aaSAndroid Build Coastguard Worker 
328*c8dee2aaSAndroid Build Coastguard Worker         return drawBounds;
329*c8dee2aaSAndroid Build Coastguard Worker     }
330*c8dee2aaSAndroid Build Coastguard Worker 
getISize()331*c8dee2aaSAndroid Build Coastguard Worker     SkISize getISize() override { return {1024, 850}; }
332*c8dee2aaSAndroid Build Coastguard Worker 
onDraw(SkCanvas * canvas,SkString * errorMsg)333*c8dee2aaSAndroid Build Coastguard Worker     DrawResult onDraw(SkCanvas* canvas, SkString* errorMsg) override {
334*c8dee2aaSAndroid Build Coastguard Worker         SkFont font = ToolUtils::DefaultFont();
335*c8dee2aaSAndroid Build Coastguard Worker         font.setEdging(SkFont::Edging::kAntiAlias);
336*c8dee2aaSAndroid Build Coastguard Worker         font.setSubpixel(true);
337*c8dee2aaSAndroid Build Coastguard Worker         font.setSize(100);
338*c8dee2aaSAndroid Build Coastguard Worker         font.setScaleX(fScaleX);
339*c8dee2aaSAndroid Build Coastguard Worker         font.setSkewX(fSkewX);
340*c8dee2aaSAndroid Build Coastguard Worker 
341*c8dee2aaSAndroid Build Coastguard Worker         const SkColor boundsColors[2] = { SK_ColorRED, SK_ColorBLUE };
342*c8dee2aaSAndroid Build Coastguard Worker 
343*c8dee2aaSAndroid Build Coastguard Worker         SkFontMgr* fm = fFM.get();
344*c8dee2aaSAndroid Build Coastguard Worker         int count = std::min(fm->countFamilies(), 32);
345*c8dee2aaSAndroid Build Coastguard Worker         if (count == 0) {
346*c8dee2aaSAndroid Build Coastguard Worker             *errorMsg = "No families in SkFontMgr under test.";
347*c8dee2aaSAndroid Build Coastguard Worker             return DrawResult::kSkip;
348*c8dee2aaSAndroid Build Coastguard Worker         }
349*c8dee2aaSAndroid Build Coastguard Worker 
350*c8dee2aaSAndroid Build Coastguard Worker         int index = 0;
351*c8dee2aaSAndroid Build Coastguard Worker         SkScalar x = 0, y = 0;
352*c8dee2aaSAndroid Build Coastguard Worker 
353*c8dee2aaSAndroid Build Coastguard Worker         canvas->translate(10, 120);
354*c8dee2aaSAndroid Build Coastguard Worker 
355*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < count; ++i) {
356*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
357*c8dee2aaSAndroid Build Coastguard Worker             for (int j = 0; j < set->count() && j < 3; ++j) {
358*c8dee2aaSAndroid Build Coastguard Worker                 font.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
359*c8dee2aaSAndroid Build Coastguard Worker                 // Fonts with lots of glyphs are interesting, but can take a long time to find
360*c8dee2aaSAndroid Build Coastguard Worker                 // the glyphs which make up the maximum extent.
361*c8dee2aaSAndroid Build Coastguard Worker                 SkTypeface* typeface = font.getTypeface();
362*c8dee2aaSAndroid Build Coastguard Worker                 if (typeface && 0 < typeface->countGlyphs() && typeface->countGlyphs() < 1000) {
363*c8dee2aaSAndroid Build Coastguard Worker                     SkColor color = boundsColors[index & 1];
364*c8dee2aaSAndroid Build Coastguard Worker                     SkRect drawBounds = show_bounds(canvas, font, x, y, color, fLabelBounds);
365*c8dee2aaSAndroid Build Coastguard Worker                     x += drawBounds.width() + 20;
366*c8dee2aaSAndroid Build Coastguard Worker                     index += 1;
367*c8dee2aaSAndroid Build Coastguard Worker                     if (x > 900) {
368*c8dee2aaSAndroid Build Coastguard Worker                         x = 0;
369*c8dee2aaSAndroid Build Coastguard Worker                         y += 160;
370*c8dee2aaSAndroid Build Coastguard Worker                     }
371*c8dee2aaSAndroid Build Coastguard Worker                     if (y >= 700) {
372*c8dee2aaSAndroid Build Coastguard Worker                         return DrawResult::kOk;
373*c8dee2aaSAndroid Build Coastguard Worker                     }
374*c8dee2aaSAndroid Build Coastguard Worker                 }
375*c8dee2aaSAndroid Build Coastguard Worker             }
376*c8dee2aaSAndroid Build Coastguard Worker         }
377*c8dee2aaSAndroid Build Coastguard Worker         return DrawResult::kOk;
378*c8dee2aaSAndroid Build Coastguard Worker     }
379*c8dee2aaSAndroid Build Coastguard Worker 
380*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkFontMgr> fFM;
381*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar fScaleX;
382*c8dee2aaSAndroid Build Coastguard Worker     const SkScalar fSkewX;
383*c8dee2aaSAndroid Build Coastguard Worker     bool fLabelBounds = false;
384*c8dee2aaSAndroid Build Coastguard Worker };
385*c8dee2aaSAndroid Build Coastguard Worker 
386*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////////
387*c8dee2aaSAndroid Build Coastguard Worker 
388*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new FontMgrGM;)
389*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new FontMgrMatchGM;)
390*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new FontMgrBoundsGM(1, 0);)
391*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new FontMgrBoundsGM(0.75f, 0);)
392*c8dee2aaSAndroid Build Coastguard Worker DEF_GM(return new FontMgrBoundsGM(1, -0.25f);)
393