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