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 18static 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 24static 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 49static const char* zh = "zh"; 50static const char* ja = "ja"; 51 52class FontMgrGM : public skiagm::GM { 53public: 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 62protected: 63 SkString onShortName() override { 64 return fName; 65 } 66 67 SkISize onISize() override { 68 return SkISize::Make(1536, 768); 69 } 70 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 110private: 111 sk_sp<SkFontMgr> fFM; 112 SkString fName; 113 typedef GM INHERITED; 114}; 115 116class FontMgrMatchGM : public skiagm::GM { 117 sk_sp<SkFontMgr> fFM; 118 119public: 120 FontMgrMatchGM() : fFM(SkFontMgr::RefDefault()) { 121 SkGraphics::SetFontCacheLimit(16 * 1024 * 1024); 122 } 123 124protected: 125 SkString onShortName() override { 126 SkString name("fontmgr_match"); 127 name.append(sk_tool_utils::platform_font_manager()); 128 return name; 129 } 130 131 SkISize onISize() override { 132 return SkISize::Make(640, 1024); 133 } 134 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 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 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 201private: 202 typedef GM INHERITED; 203}; 204 205class FontMgrBoundsGM : public skiagm::GM { 206public: 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 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 271protected: 272 SkString onShortName() override { 273 return fName; 274 } 275 276 SkISize onISize() override { 277 return SkISize::Make(1024, 850); 278 } 279 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 323private: 324 sk_sp<SkFontMgr> fFM; 325 SkString fName; 326 SkScalar fScaleX, fSkewX; 327 typedef GM INHERITED; 328}; 329 330////////////////////////////////////////////////////////////////////////////// 331 332DEF_GM(return new FontMgrGM;) 333DEF_GM(return new FontMgrMatchGM;) 334DEF_GM(return new FontMgrBoundsGM(1.0, 0);) 335DEF_GM(return new FontMgrBoundsGM(0.75, 0);) 336DEF_GM(return new FontMgrBoundsGM(1.0, -0.25);) 337