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