• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 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.h"
9 #include "sk_tool_utils.h"
10 #include "SkCanvas.h"
11 #include "SkFontMgr.h"
12 #include "SkGraphics.h"
13 #include "SkTypeface.h"
14 
15 // limit this just so we don't take too long to draw
16 #define MAX_FAMILIES    30
17 
drawString(SkCanvas * canvas,const SkString & text,SkScalar x,SkScalar y,const SkPaint & paint)18 static SkScalar drawString(SkCanvas* canvas, const SkString& text, SkScalar x,
19                            SkScalar y, const SkPaint& paint) {
20     canvas->drawString(text, x, y, paint);
21     return x + paint.measureText(text.c_str(), text.size());
22 }
23 
drawCharacter(SkCanvas * canvas,uint32_t character,SkScalar x,SkScalar y,SkPaint & paint,SkFontMgr * fm,const char * fontName,const char * bcp47[],int bcp47Count,const SkFontStyle & fontStyle)24 static SkScalar drawCharacter(SkCanvas* canvas, uint32_t character, SkScalar x,
25                               SkScalar y, SkPaint& paint, SkFontMgr* fm,
26                               const char* fontName, const char* bcp47[], int bcp47Count,
27                               const SkFontStyle& fontStyle) {
28     // find typeface containing the requested character and draw it
29     SkString ch;
30     ch.appendUnichar(character);
31     sk_sp<SkTypeface> typeface(fm->matchFamilyStyleCharacter(fontName, fontStyle,
32                                                              bcp47, bcp47Count, character));
33     paint.setTypeface(typeface);
34     x = drawString(canvas, ch, x, y, paint) + 20;
35 
36     if (nullptr == typeface) {
37         return x;
38     }
39 
40     // repeat the process, but this time use the family name of the typeface
41     // from the first pass.  This emulates the behavior in Blink where it
42     // it expects to get the same glyph when following this pattern.
43     SkString familyName;
44     typeface->getFamilyName(&familyName);
45     paint.setTypeface(fm->legacyMakeTypeface(familyName.c_str(), typeface->fontStyle()));
46     return drawString(canvas, ch, x, y, paint) + 20;
47 }
48 
49 static const char* zh = "zh";
50 static const char* ja = "ja";
51 
52 class FontMgrGM : public skiagm::GM {
53 public:
FontMgrGM()54     FontMgrGM() {
55         SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
56 
57         fName.set("fontmgr_iter");
58         fFM = SkFontMgr::RefDefault();
59         fName.append(sk_tool_utils::platform_font_manager());
60     }
61 
62 protected:
onShortName()63     SkString onShortName() override {
64         return fName;
65     }
66 
onISize()67     SkISize onISize() override {
68         return SkISize::Make(1536, 768);
69     }
70 
onDraw(SkCanvas * canvas)71     void onDraw(SkCanvas* canvas) override {
72         SkScalar y = 20;
73         SkPaint paint;
74         paint.setAntiAlias(true);
75         paint.setLCDRenderText(true);
76         paint.setSubpixelText(true);
77         paint.setTextSize(17);
78 
79         SkFontMgr* fm = fFM.get();
80         int count = SkMin32(fm->countFamilies(), MAX_FAMILIES);
81 
82         for (int i = 0; i < count; ++i) {
83             SkString familyName;
84             fm->getFamilyName(i, &familyName);
85             paint.setTypeface(nullptr);
86             (void)drawString(canvas, familyName, 20, y, paint);
87 
88             SkScalar x = 220;
89 
90             sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
91             for (int j = 0; j < set->count(); ++j) {
92                 SkString sname;
93                 SkFontStyle fs;
94                 set->getStyle(j, &fs, &sname);
95                 sname.appendf(" [%d %d %d]", fs.weight(), fs.width(), fs.slant());
96 
97                 paint.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
98                 x = drawString(canvas, sname, x, y, paint) + 20;
99 
100                 // check to see that we get different glyphs in japanese and chinese
101                 x = drawCharacter(canvas, 0x5203, x, y, paint, fm, familyName.c_str(), &zh, 1, fs);
102                 x = drawCharacter(canvas, 0x5203, x, y, paint, fm, familyName.c_str(), &ja, 1, fs);
103                 // check that emoji characters are found
104                 x = drawCharacter(canvas, 0x1f601, x, y, paint, fm, familyName.c_str(), nullptr,0, fs);
105             }
106             y += 24;
107         }
108     }
109 
110 private:
111     sk_sp<SkFontMgr> fFM;
112     SkString fName;
113     typedef GM INHERITED;
114 };
115 
116 class FontMgrMatchGM : public skiagm::GM {
117     sk_sp<SkFontMgr> fFM;
118 
119 public:
FontMgrMatchGM()120     FontMgrMatchGM() : fFM(SkFontMgr::RefDefault()) {
121         SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
122     }
123 
124 protected:
onShortName()125     SkString onShortName() override {
126         SkString name("fontmgr_match");
127         name.append(sk_tool_utils::platform_font_manager());
128         return name;
129     }
130 
onISize()131     SkISize onISize() override {
132         return SkISize::Make(640, 1024);
133     }
134 
iterateFamily(SkCanvas * canvas,const SkPaint & paint,SkFontStyleSet * fset)135     void iterateFamily(SkCanvas* canvas, const SkPaint& paint,
136                        SkFontStyleSet* fset) {
137         SkPaint p(paint);
138         SkScalar y = 0;
139 
140         for (int j = 0; j < fset->count(); ++j) {
141             SkString sname;
142             SkFontStyle fs;
143             fset->getStyle(j, &fs, &sname);
144 
145             sname.appendf(" [%d %d]", fs.weight(), fs.width());
146 
147             p.setTypeface(sk_sp<SkTypeface>(fset->createTypeface(j)));
148             (void)drawString(canvas, sname, 0, y, p);
149             y += 24;
150         }
151     }
152 
exploreFamily(SkCanvas * canvas,const SkPaint & paint,SkFontStyleSet * fset)153     void exploreFamily(SkCanvas* canvas, const SkPaint& paint,
154                        SkFontStyleSet* fset) {
155         SkPaint p(paint);
156         SkScalar y = 0;
157 
158         for (int weight = 100; weight <= 900; weight += 200) {
159             for (int width = 1; width <= 9; width += 2) {
160                 SkFontStyle fs(weight, width, SkFontStyle::kUpright_Slant);
161                 sk_sp<SkTypeface> face(fset->matchStyle(fs));
162                 if (face) {
163                     SkString str;
164                     str.printf("request [%d %d]", fs.weight(), fs.width());
165                     p.setTypeface(std::move(face));
166                     (void)drawString(canvas, str, 0, y, p);
167                     y += 24;
168                 }
169             }
170         }
171     }
172 
onDraw(SkCanvas * canvas)173     void onDraw(SkCanvas* canvas) override {
174         SkPaint paint;
175         paint.setAntiAlias(true);
176         paint.setLCDRenderText(true);
177         paint.setSubpixelText(true);
178         paint.setTextSize(17);
179 
180         const char* gNames[] = {
181             "Helvetica Neue", "Arial"
182         };
183 
184         sk_sp<SkFontStyleSet> fset;
185         for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) {
186             fset.reset(fFM->matchFamily(gNames[i]));
187             if (fset->count() > 0) {
188                 break;
189             }
190         }
191         if (nullptr == fset.get()) {
192             return;
193         }
194 
195         canvas->translate(20, 40);
196         this->exploreFamily(canvas, paint, fset.get());
197         canvas->translate(150, 0);
198         this->iterateFamily(canvas, paint, fset.get());
199     }
200 
201 private:
202     typedef GM INHERITED;
203 };
204 
205 class FontMgrBoundsGM : public skiagm::GM {
206 public:
FontMgrBoundsGM(double scale,double skew)207     FontMgrBoundsGM(double scale, double skew)
208         : fScaleX(SkDoubleToScalar(scale))
209         , fSkewX(SkDoubleToScalar(skew))
210     {
211         fName.set("fontmgr_bounds");
212         if (scale != 1 || skew != 0) {
213             fName.appendf("_%g_%g", scale, skew);
214         }
215         fName.append(sk_tool_utils::platform_font_manager());
216         fFM = SkFontMgr::RefDefault();
217     }
218 
show_bounds(SkCanvas * canvas,const SkPaint & paint,SkScalar x,SkScalar y,SkColor boundsColor)219     static void show_bounds(SkCanvas* canvas, const SkPaint& paint, SkScalar x, SkScalar y,
220                             SkColor boundsColor)
221     {
222         SkPaint glyphPaint(paint);
223         SkRect fontBounds = glyphPaint.getFontBounds();
224         fontBounds.offset(x, y);
225         SkPaint boundsPaint(glyphPaint);
226         boundsPaint.setColor(boundsColor);
227         canvas->drawRect(fontBounds, boundsPaint);
228 
229         SkPaint::FontMetrics fm;
230         glyphPaint.getFontMetrics(&fm);
231         SkPaint metricsPaint(boundsPaint);
232         metricsPaint.setStyle(SkPaint::kFill_Style);
233         metricsPaint.setAlpha(0x40);
234         if ((fm.fFlags & SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag) &&
235             (fm.fFlags & SkPaint::FontMetrics::kUnderlinePositionIsValid_Flag))
236         {
237             SkRect underline{ fontBounds.fLeft,  fm.fUnderlinePosition+y,
238                               fontBounds.fRight, fm.fUnderlinePosition+y + fm.fUnderlineThickness };
239             canvas->drawRect(underline, metricsPaint);
240         }
241 
242         if ((fm.fFlags & SkPaint::FontMetrics::kStrikeoutPositionIsValid_Flag) &&
243             (fm.fFlags & SkPaint::FontMetrics::kStrikeoutPositionIsValid_Flag))
244         {
245             SkRect strikeout{ fontBounds.fLeft,  fm.fStrikeoutPosition+y - fm.fStrikeoutThickness,
246                               fontBounds.fRight, fm.fStrikeoutPosition+y };
247             canvas->drawRect(strikeout, metricsPaint);
248         }
249 
250         SkGlyphID left = 0, right = 0, top = 0, bottom = 0;
251         {
252             int numGlyphs = glyphPaint.getTypeface()->countGlyphs();
253             SkRect min = {0, 0, 0, 0};
254             glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
255             for (int i = 0; i < numGlyphs; ++i) {
256                 SkGlyphID glyphId = i;
257                 SkRect cur;
258                 glyphPaint.measureText(&glyphId, sizeof(glyphId), &cur);
259                 if (cur.fLeft   < min.fLeft  ) { min.fLeft   = cur.fLeft;   left   = i; }
260                 if (cur.fTop    < min.fTop   ) { min.fTop    = cur.fTop ;   top    = i; }
261                 if (min.fRight  < cur.fRight ) { min.fRight  = cur.fRight;  right  = i; }
262                 if (min.fBottom < cur.fBottom) { min.fBottom = cur.fBottom; bottom = i; }
263             }
264         }
265         SkGlyphID str[] = { left, right, top, bottom };
266         for (size_t i = 0; i < SK_ARRAY_COUNT(str); ++i) {
267             canvas->drawText(&str[i], sizeof(str[0]), x, y, glyphPaint);
268         }
269     }
270 
271 protected:
onShortName()272     SkString onShortName() override {
273         return fName;
274     }
275 
onISize()276     SkISize onISize() override {
277         return SkISize::Make(1024, 850);
278     }
279 
onDraw(SkCanvas * canvas)280     void onDraw(SkCanvas* canvas) override {
281         SkPaint paint;
282         paint.setAntiAlias(true);
283         paint.setSubpixelText(true);
284         paint.setTextSize(100);
285         paint.setStyle(SkPaint::kStroke_Style);
286         paint.setTextScaleX(fScaleX);
287         paint.setTextSkewX(fSkewX);
288 
289         const SkColor boundsColors[2] = { SK_ColorRED, SK_ColorBLUE };
290 
291         SkFontMgr* fm = fFM.get();
292         int count = SkMin32(fm->countFamilies(), 32);
293 
294         int index = 0;
295         SkScalar x = 0, y = 0;
296 
297         canvas->translate(10, 120);
298 
299         for (int i = 0; i < count; ++i) {
300             sk_sp<SkFontStyleSet> set(fm->createStyleSet(i));
301             for (int j = 0; j < set->count() && j < 3; ++j) {
302                 paint.setTypeface(sk_sp<SkTypeface>(set->createTypeface(j)));
303                 // Fonts with lots of glyphs are interesting, but can take a long time to find
304                 // the glyphs which make up the maximum extent.
305                 if (paint.getTypeface() && paint.getTypeface()->countGlyphs() < 1000) {
306                     SkRect fontBounds = paint.getFontBounds();
307                     x -= fontBounds.fLeft;
308                     show_bounds(canvas, paint, x, y, boundsColors[index & 1]);
309                     x += fontBounds.fRight + 20;
310                     index += 1;
311                     if (x > 900) {
312                         x = 0;
313                         y += 160;
314                     }
315                     if (y >= 700) {
316                         return;
317                     }
318                 }
319             }
320         }
321     }
322 
323 private:
324     sk_sp<SkFontMgr> fFM;
325     SkString fName;
326     SkScalar fScaleX, fSkewX;
327     typedef GM INHERITED;
328 };
329 
330 //////////////////////////////////////////////////////////////////////////////
331 
332 DEF_GM(return new FontMgrGM;)
333 DEF_GM(return new FontMgrMatchGM;)
334 DEF_GM(return new FontMgrBoundsGM(1.0, 0);)
335 DEF_GM(return new FontMgrBoundsGM(0.75, 0);)
336 DEF_GM(return new FontMgrBoundsGM(1.0, -0.25);)
337