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 21static 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 27static 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 (NULL == 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 53static const char* zh = "zh"; 54static const char* ja = "ja"; 55 56class FontMgrGM : public skiagm::GM { 57public: 58 FontMgrGM(SkFontMgr* fontMgr = NULL) { 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 } 69 70protected: 71 SkString onShortName() override { 72 return fName; 73 } 74 75 SkISize onISize() override { 76 return SkISize::Make(1536, 768); 77 } 78 79 void onDraw(SkCanvas* canvas) override { 80 SkScalar y = 20; 81 SkPaint paint; 82 paint.setAntiAlias(true); 83 paint.setLCDRenderText(true); 84 paint.setSubpixelText(true); 85 paint.setTextSize(17); 86 87 SkFontMgr* fm = fFM; 88 int count = SkMin32(fm->countFamilies(), MAX_FAMILIES); 89 90 for (int i = 0; i < count; ++i) { 91 SkString familyName; 92 fm->getFamilyName(i, &familyName); 93 paint.setTypeface(NULL); 94 (void)drawString(canvas, familyName, 20, y, paint); 95 96 SkScalar x = 220; 97 98 SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i)); 99 for (int j = 0; j < set->count(); ++j) { 100 SkString sname; 101 SkFontStyle fs; 102 set->getStyle(j, &fs, &sname); 103 sname.appendf(" [%d %d %d]", fs.weight(), fs.width(), fs.isItalic()); 104 105 SkSafeUnref(paint.setTypeface(set->createTypeface(j))); 106 x = drawString(canvas, sname, x, y, paint) + 20; 107 108 // check to see that we get different glyphs in japanese and chinese 109 x = drawCharacter(canvas, 0x5203, x, y, paint, fm, familyName.c_str(), &zh, 1, fs); 110 x = drawCharacter(canvas, 0x5203, x, y, paint, fm, familyName.c_str(), &ja, 1, fs); 111 // check that emoji characters are found 112 x = drawCharacter(canvas, 0x1f601, x, y, paint, fm, familyName.c_str(), NULL,0, fs); 113 } 114 y += 24; 115 } 116 } 117 118private: 119 SkAutoTUnref<SkFontMgr> fFM; 120 SkString fName; 121 typedef GM INHERITED; 122}; 123 124class FontMgrMatchGM : public skiagm::GM { 125 SkAutoTUnref<SkFontMgr> fFM; 126 127public: 128 FontMgrMatchGM() : fFM(SkFontMgr::RefDefault()) { 129 SkGraphics::SetFontCacheLimit(16 * 1024 * 1024); 130 } 131 132protected: 133 SkString onShortName() override { 134 return SkString("fontmgr_match"); 135 } 136 137 SkISize onISize() override { 138 return SkISize::Make(640, 1024); 139 } 140 141 void iterateFamily(SkCanvas* canvas, const SkPaint& paint, 142 SkFontStyleSet* fset) { 143 SkPaint p(paint); 144 SkScalar y = 0; 145 146 for (int j = 0; j < fset->count(); ++j) { 147 SkString sname; 148 SkFontStyle fs; 149 fset->getStyle(j, &fs, &sname); 150 151 sname.appendf(" [%d %d]", fs.weight(), fs.width()); 152 153 SkSafeUnref(p.setTypeface(fset->createTypeface(j))); 154 (void)drawString(canvas, sname, 0, y, p); 155 y += 24; 156 } 157 } 158 159 void exploreFamily(SkCanvas* canvas, const SkPaint& paint, 160 SkFontStyleSet* fset) { 161 SkPaint p(paint); 162 SkScalar y = 0; 163 164 for (int weight = 100; weight <= 900; weight += 200) { 165 for (int width = 1; width <= 9; width += 2) { 166 SkFontStyle fs(weight, width, SkFontStyle::kUpright_Slant); 167 SkTypeface* face = fset->matchStyle(fs); 168 if (face) { 169 SkString str; 170 str.printf("request [%d %d]", fs.weight(), fs.width()); 171 p.setTypeface(face)->unref(); 172 (void)drawString(canvas, str, 0, y, p); 173 y += 24; 174 } 175 } 176 } 177 } 178 179 void onDraw(SkCanvas* canvas) override { 180 SkPaint paint; 181 paint.setAntiAlias(true); 182 paint.setLCDRenderText(true); 183 paint.setSubpixelText(true); 184 paint.setTextSize(17); 185 186 static const char* gNames[] = { 187 "Helvetica Neue", "Arial" 188 }; 189 190 SkAutoTUnref<SkFontStyleSet> fset; 191 for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) { 192 fset.reset(fFM->matchFamily(gNames[i])); 193 if (fset->count() > 0) { 194 break; 195 } 196 } 197 if (NULL == fset.get()) { 198 return; 199 } 200 201 canvas->translate(20, 40); 202 this->exploreFamily(canvas, paint, fset); 203 canvas->translate(150, 0); 204 this->iterateFamily(canvas, paint, fset); 205 } 206 207private: 208 typedef GM INHERITED; 209}; 210 211class FontMgrBoundsGM : public skiagm::GM { 212public: 213 FontMgrBoundsGM(double scale, double skew) 214 : fScaleX(SkDoubleToScalar(scale)) 215 , fSkewX(SkDoubleToScalar(skew)) 216 { 217 fName.set("fontmgr_bounds"); 218 if (scale != 1 || skew != 0) { 219 fName.appendf("_%g_%g", scale, skew); 220 } 221 fFM.reset(SkFontMgr::RefDefault()); 222 } 223 224 static void show_bounds(SkCanvas* canvas, const SkPaint& paint, SkScalar x, SkScalar y, 225 SkColor boundsColor) { 226 const char str[] = "jyHO[]{}@-_&%$"; 227 228 for (int i = 0; str[i]; ++i) { 229 canvas->drawText(&str[i], 1, x, y, paint); 230 } 231 232 SkRect r = paint.getFontBounds(); 233 r.offset(x, y); 234 SkPaint p(paint); 235 p.setColor(boundsColor); 236 canvas->drawRect(r, p); 237 } 238 239protected: 240 SkString onShortName() override { 241 return fName; 242 } 243 244 SkISize onISize() override { 245 return SkISize::Make(1024, 850); 246 } 247 248 void onDraw(SkCanvas* canvas) override { 249 SkPaint paint; 250 paint.setAntiAlias(true); 251 paint.setSubpixelText(true); 252 paint.setTextSize(100); 253 paint.setStyle(SkPaint::kStroke_Style); 254 paint.setTextScaleX(fScaleX); 255 paint.setTextSkewX(fSkewX); 256 257 const SkColor boundsColors[2] = { SK_ColorRED, SK_ColorBLUE }; 258 259 SkFontMgr* fm = fFM; 260 int count = SkMin32(fm->countFamilies(), 32); 261 262 int index = 0; 263 SkScalar x = 0, y = 0; 264 265 canvas->translate(80, 120); 266 267 for (int i = 0; i < count; ++i) { 268 SkAutoTUnref<SkFontStyleSet> set(fm->createStyleSet(i)); 269 for (int j = 0; j < set->count(); ++j) { 270 SkSafeUnref(paint.setTypeface(set->createTypeface(j))); 271 if (paint.getTypeface()) { 272 show_bounds(canvas, paint, x, y, boundsColors[index & 1]); 273 index += 1; 274 x += 160; 275 if (0 == (index % 6)) { 276 x = 0; 277 y += 160; 278 } 279 if (index >= 30) { 280 return; 281 } 282 } 283 } 284 } 285 } 286 287private: 288 SkAutoTUnref<SkFontMgr> fFM; 289 SkString fName; 290 SkScalar fScaleX, fSkewX; 291 typedef GM INHERITED; 292}; 293 294////////////////////////////////////////////////////////////////////////////// 295 296DEF_GM( return SkNEW(FontMgrGM); ) 297DEF_GM( return SkNEW(FontMgrMatchGM); ) 298DEF_GM( return SkNEW(FontMgrBoundsGM(1.0, 0)); ) 299DEF_GM( return SkNEW(FontMgrBoundsGM(0.75, 0)); ) 300DEF_GM( return SkNEW(FontMgrBoundsGM(1.0, -0.25)); ) 301 302#ifdef SK_BUILD_FOR_WIN 303 DEF_GM( return SkNEW_ARGS(FontMgrGM, (SkFontMgr_New_DirectWrite())); ) 304#endif 305