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 "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 
     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 
     27 static SkScalar drawCharacter(SkCanvas* canvas, uint32_t character, SkScalar x,
     28                               SkScalar y, SkPaint& paint, SkFontMgr* fm,
     29                               const char* fontName, const char* bpc47,
     30                               const SkFontStyle& fontStyle) {
     31     // find typeface containing the requested character and draw it
     32     SkString ch;
     33     ch.appendUnichar(character);
     34 #ifdef SK_FM_NEW_MATCH_FAMILY_STYLE_CHARACTER
     35     SkTypeface* typeface = fm->matchFamilyStyleCharacter(fontName, fontStyle, &bpc47, 1, character);
     36 #else
     37     SkTypeface* typeface = fm->matchFamilyStyleCharacter(fontName, fontStyle, bpc47, character);
     38 #endif
     39     SkSafeUnref(paint.setTypeface(typeface));
     40     x = drawString(canvas, ch, x, y, paint) + 20;
     41 
     42     if (NULL == typeface) {
     43         return x;
     44     }
     45 
     46     // repeat the process, but this time use the family name of the typeface
     47     // from the first pass.  This emulates the behavior in Blink where it
     48     // it expects to get the same glyph when following this pattern.
     49     SkString familyName;
     50     typeface->getFamilyName(&familyName);
     51     SkTypeface* typefaceCopy = fm->legacyCreateTypeface(familyName.c_str(), typeface->style());
     52     SkSafeUnref(paint.setTypeface(typefaceCopy));
     53     return drawString(canvas, ch, x, y, paint) + 20;
     54 }
     55 
     56 class FontMgrGM : public skiagm::GM {
     57 public:
     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 
     70 protected:
     71     virtual SkString onShortName() {
     72         return fName;
     73     }
     74 
     75     virtual SkISize onISize() {
     76         return SkISize::Make(1536, 768);
     77     }
     78 
     79     virtual void onDraw(SkCanvas* canvas) SK_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 fname;
     92             fm->getFamilyName(i, &fname);
     93             paint.setTypeface(NULL);
     94             (void)drawString(canvas, fname, 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, fName.c_str(), "zh", fs);
    110                 x = drawCharacter(canvas, 0x5203, x, y, paint, fm, fName.c_str(), "ja", fs);
    111                 // check that emoji characters are found
    112                 x = drawCharacter(canvas, 0x1f601, x, y, paint, fm, fName.c_str(), NULL, fs);
    113             }
    114             y += 24;
    115         }
    116     }
    117 
    118     virtual uint32_t onGetFlags() const SK_OVERRIDE {
    119         // fontdescriptors (and therefore serialization) don't yet understand
    120         // these new styles, so skip tests that exercise that for now.
    121 
    122         // If certain fonts are picked up (e.g. Microsoft Jhenghei 20MB for Regular, 12MB for Bold),
    123         // the resulting pdf can be ~700MB and crashes Chrome's PDF viewer.
    124 
    125         return kSkipPicture_Flag | kSkipPipe_Flag | kSkipPDF_Flag;
    126     }
    127 
    128 private:
    129     SkAutoTUnref<SkFontMgr> fFM;
    130     SkString fName;
    131     typedef GM INHERITED;
    132 };
    133 
    134 class FontMgrMatchGM : public skiagm::GM {
    135     SkAutoTUnref<SkFontMgr> fFM;
    136 
    137 public:
    138     FontMgrMatchGM() : fFM(SkFontMgr::RefDefault()) {
    139         SkGraphics::SetFontCacheLimit(16 * 1024 * 1024);
    140     }
    141 
    142 protected:
    143     virtual SkString onShortName() {
    144         return SkString("fontmgr_match");
    145     }
    146 
    147     virtual SkISize onISize() {
    148         return SkISize::Make(640, 1024);
    149     }
    150 
    151     void iterateFamily(SkCanvas* canvas, const SkPaint& paint,
    152                        SkFontStyleSet* fset) {
    153         SkPaint p(paint);
    154         SkScalar y = 0;
    155 
    156         for (int j = 0; j < fset->count(); ++j) {
    157             SkString sname;
    158             SkFontStyle fs;
    159             fset->getStyle(j, &fs, &sname);
    160 
    161             sname.appendf(" [%d %d]", fs.weight(), fs.width());
    162 
    163             SkSafeUnref(p.setTypeface(fset->createTypeface(j)));
    164             (void)drawString(canvas, sname, 0, y, p);
    165             y += 24;
    166         }
    167     }
    168 
    169     void exploreFamily(SkCanvas* canvas, const SkPaint& paint,
    170                        SkFontStyleSet* fset) {
    171         SkPaint p(paint);
    172         SkScalar y = 0;
    173 
    174         for (int weight = 100; weight <= 900; weight += 200) {
    175             for (int width = 1; width <= 9; width += 2) {
    176                 SkFontStyle fs(weight, width, SkFontStyle::kUpright_Slant);
    177                 SkTypeface* face = fset->matchStyle(fs);
    178                 if (face) {
    179                     SkString str;
    180                     str.printf("request [%d %d]", fs.weight(), fs.width());
    181                     p.setTypeface(face)->unref();
    182                     (void)drawString(canvas, str, 0, y, p);
    183                     y += 24;
    184                 }
    185             }
    186         }
    187     }
    188 
    189     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
    190         SkPaint paint;
    191         paint.setAntiAlias(true);
    192         paint.setLCDRenderText(true);
    193         paint.setSubpixelText(true);
    194         paint.setTextSize(17);
    195 
    196         static const char* gNames[] = {
    197             "Helvetica Neue", "Arial"
    198         };
    199 
    200         SkAutoTUnref<SkFontStyleSet> fset;
    201         for (size_t i = 0; i < SK_ARRAY_COUNT(gNames); ++i) {
    202             fset.reset(fFM->matchFamily(gNames[i]));
    203             if (fset->count() > 0) {
    204                 break;
    205             }
    206         }
    207         if (NULL == fset.get()) {
    208             return;
    209         }
    210 
    211         canvas->translate(20, 40);
    212         this->exploreFamily(canvas, paint, fset);
    213         canvas->translate(150, 0);
    214         this->iterateFamily(canvas, paint, fset);
    215     }
    216 
    217     virtual uint32_t onGetFlags() const SK_OVERRIDE {
    218         // fontdescriptors (and therefore serialization) don't yet understand
    219         // these new styles, so skip tests that exercise that for now.
    220         return kSkipPicture_Flag | kSkipPipe_Flag;
    221     }
    222 
    223 private:
    224     typedef GM INHERITED;
    225 };
    226 
    227 //////////////////////////////////////////////////////////////////////////////
    228 
    229 DEF_GM( return SkNEW(FontMgrGM); )
    230 DEF_GM( return SkNEW(FontMgrMatchGM); )
    231 
    232 #ifdef SK_BUILD_FOR_WIN
    233     DEF_GM( return SkNEW_ARGS(FontMgrGM, (SkFontMgr_New_DirectWrite())); )
    234 #endif
    235