Home | History | Annotate | Download | only in gm
      1 /*
      2  * Copyright 2012 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 "SkString.h"
     11 #include "SkTypeface.h"
     12 #include "SkTypes.h"
     13 
     14 static const char* gFaces[] = {
     15     "Times Roman",
     16     "Hiragino Maru Gothic Pro",
     17     "Papyrus",
     18     "Helvetica",
     19     "Courier New"
     20 };
     21 
     22 class TypefaceGM : public skiagm::GM {
     23 public:
     24     TypefaceGM() {
     25         fFaces = new SkTypeface*[SK_ARRAY_COUNT(gFaces)];
     26         for (size_t i = 0; i < SK_ARRAY_COUNT(gFaces); i++) {
     27             fFaces[i] = SkTypeface::CreateFromName(gFaces[i], SkTypeface::kNormal);
     28         }
     29     }
     30 
     31     virtual ~TypefaceGM() {
     32         for (size_t i = 0; i < SK_ARRAY_COUNT(gFaces); i++) {
     33             SkSafeUnref(fFaces[i]);
     34         }
     35         delete [] fFaces;
     36     }
     37 
     38 protected:
     39     virtual SkString onShortName() SK_OVERRIDE {
     40         return SkString("typeface");
     41     }
     42 
     43     virtual SkISize onISize() SK_OVERRIDE {
     44         return SkISize::Make(640, 480);
     45     }
     46 
     47     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
     48         SkString text("Typefaces are fun!");
     49         SkScalar y = 0;
     50 
     51         SkPaint paint;
     52         paint.setAntiAlias(true);
     53         for (int i = 0; i < (int)SK_ARRAY_COUNT(gFaces); i++) {
     54             this->drawWithFace(text, i, y, paint, canvas);
     55         }
     56         // Now go backwards
     57         for (int i = SK_ARRAY_COUNT(gFaces) - 1; i >= 0; i--) {
     58             this->drawWithFace(text, i, y, paint, canvas);
     59         }
     60     }
     61 
     62 private:
     63     void drawWithFace(const SkString& text, int i, SkScalar& y, SkPaint& paint,
     64                       SkCanvas* canvas) {
     65         paint.setTypeface(fFaces[i]);
     66         y += paint.getFontMetrics(NULL);
     67         canvas->drawText(text.c_str(), text.size(), 0, y, paint);
     68     }
     69 
     70     SkTypeface** fFaces;
     71 
     72     typedef skiagm::GM INHERITED;
     73 };
     74 
     75 ///////////////////////////////////////////////////////////////////////////////
     76 
     77 static void getGlyphPositions(const SkPaint& paint, const uint16_t glyphs[],
     78                              int count, SkScalar x, SkScalar y, SkPoint pos[]) {
     79     SkASSERT(SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding());
     80 
     81     SkAutoSTMalloc<128, SkScalar> widthStorage(count);
     82     SkScalar* widths = widthStorage.get();
     83     paint.getTextWidths(glyphs, count * sizeof(uint16_t), widths);
     84 
     85     for (int i = 0; i < count; ++i) {
     86         pos[i].set(x, y);
     87         x += widths[i];
     88     }
     89 }
     90 
     91 static void applyKerning(SkPoint pos[], const int32_t adjustments[], int count,
     92                          const SkPaint& paint) {
     93     SkScalar scale = paint.getTextSize() / paint.getTypeface()->getUnitsPerEm();
     94 
     95     SkScalar globalAdj = 0;
     96     for (int i = 0; i < count - 1; ++i) {
     97         globalAdj += adjustments[i] * scale;
     98         pos[i + 1].fX += globalAdj;
     99     }
    100 }
    101 
    102 static void drawKernText(SkCanvas* canvas, const void* text, size_t len,
    103                          SkScalar x, SkScalar y, const SkPaint& paint) {
    104     SkTypeface* face = paint.getTypeface();
    105     if (!face) {
    106         canvas->drawText(text, len, x, y, paint);
    107         return;
    108     }
    109 
    110     SkAutoSTMalloc<128, uint16_t> glyphStorage(len);
    111     uint16_t* glyphs = glyphStorage.get();
    112     int glyphCount = paint.textToGlyphs(text, len, glyphs);
    113     if (glyphCount < 1) {
    114         return;
    115     }
    116 
    117     SkAutoSTMalloc<128, int32_t> adjustmentStorage(glyphCount - 1);
    118     int32_t* adjustments = adjustmentStorage.get();
    119     if (!face->getKerningPairAdjustments(glyphs, glyphCount, adjustments)) {
    120         canvas->drawText(text, len, x, y, paint);
    121         return;
    122     }
    123 
    124     SkPaint glyphPaint(paint);
    125     glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    126 
    127     SkAutoSTMalloc<128, SkPoint> posStorage(glyphCount);
    128     SkPoint* pos = posStorage.get();
    129     getGlyphPositions(glyphPaint, glyphs, glyphCount, x, y, pos);
    130 
    131     applyKerning(pos, adjustments, glyphCount, glyphPaint);
    132     canvas->drawPosText(glyphs, glyphCount * sizeof(uint16_t), pos, glyphPaint);
    133 }
    134 
    135 static const struct {
    136     const char* fName;
    137     SkTypeface::Style   fStyle;
    138 } gFaceStyles[] = {
    139     { "sans-serif", SkTypeface::kNormal },
    140     { "sans-serif", SkTypeface::kBold },
    141     { "sans-serif", SkTypeface::kItalic },
    142     { "sans-serif", SkTypeface::kBoldItalic },
    143     { "serif", SkTypeface::kNormal },
    144     { "serif", SkTypeface::kBold },
    145     { "serif", SkTypeface::kItalic },
    146     { "serif", SkTypeface::kBoldItalic },
    147     { "monospace", SkTypeface::kNormal },
    148     { "monospace", SkTypeface::kBold },
    149     { "monospace", SkTypeface::kItalic },
    150     { "monospace", SkTypeface::kBoldItalic },
    151 };
    152 
    153 static const int gFaceStylesCount = SK_ARRAY_COUNT(gFaceStyles);
    154 
    155 class TypefaceStylesGM : public skiagm::GM {
    156     SkTypeface* fFaces[gFaceStylesCount];
    157     bool fApplyKerning;
    158 
    159 public:
    160     TypefaceStylesGM(bool applyKerning) : fApplyKerning(applyKerning) {
    161         for (int i = 0; i < gFaceStylesCount; i++) {
    162             fFaces[i] = SkTypeface::CreateFromName(gFaceStyles[i].fName,
    163                                                    gFaceStyles[i].fStyle);
    164         }
    165     }
    166 
    167     virtual ~TypefaceStylesGM() {
    168         for (int i = 0; i < gFaceStylesCount; i++) {
    169             SkSafeUnref(fFaces[i]);
    170         }
    171     }
    172 
    173 protected:
    174     virtual SkString onShortName() SK_OVERRIDE {
    175         SkString name("typefacestyles");
    176         if (fApplyKerning) {
    177             name.append("_kerning");
    178         }
    179         return name;
    180     }
    181 
    182     virtual SkISize onISize() SK_OVERRIDE {
    183         return SkISize::Make(640, 480);
    184     }
    185 
    186     virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
    187         SkPaint paint;
    188         paint.setAntiAlias(true);
    189         paint.setTextSize(SkIntToScalar(30));
    190 
    191         const char* text = fApplyKerning ? "Type AWAY" : "Hamburgefons";
    192         const size_t textLen = strlen(text);
    193 
    194         SkScalar x = SkIntToScalar(10);
    195         SkScalar dy = paint.getFontMetrics(NULL);
    196         SkScalar y = dy;
    197 
    198         if (fApplyKerning) {
    199             paint.setSubpixelText(true);
    200         } else {
    201             paint.setLinearText(true);
    202         }
    203         for (int i = 0; i < gFaceStylesCount; i++) {
    204             paint.setTypeface(fFaces[i]);
    205             canvas->drawText(text, textLen, x, y, paint);
    206             if (fApplyKerning) {
    207                 drawKernText(canvas, text, textLen, x + 240, y, paint);
    208             }
    209             y += dy;
    210         }
    211     }
    212 
    213 private:
    214     typedef skiagm::GM INHERITED;
    215 };
    216 
    217 ///////////////////////////////////////////////////////////////////////////////
    218 
    219 DEF_GM( return new TypefaceGM; )
    220 DEF_GM( return new TypefaceStylesGM(false); )
    221 DEF_GM( return new TypefaceStylesGM(true); )
    222