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 
getGlyphPositions(const SkPaint & paint,const uint16_t glyphs[],int count,SkScalar x,SkScalar y,SkPoint pos[])14 static void getGlyphPositions(const SkPaint& paint, const uint16_t glyphs[],
15                              int count, SkScalar x, SkScalar y, SkPoint pos[]) {
16     SkASSERT(SkPaint::kGlyphID_TextEncoding == paint.getTextEncoding());
17 
18     SkAutoSTMalloc<128, SkScalar> widthStorage(count);
19     SkScalar* widths = widthStorage.get();
20     paint.getTextWidths(glyphs, count * sizeof(uint16_t), widths);
21 
22     for (int i = 0; i < count; ++i) {
23         pos[i].set(x, y);
24         x += widths[i];
25     }
26 }
27 
applyKerning(SkPoint pos[],const int32_t adjustments[],int count,const SkPaint & paint)28 static void applyKerning(SkPoint pos[], const int32_t adjustments[], int count,
29                          const SkPaint& paint) {
30     SkScalar scale = paint.getTextSize() / paint.getTypeface()->getUnitsPerEm();
31 
32     SkScalar globalAdj = 0;
33     for (int i = 0; i < count - 1; ++i) {
34         globalAdj += adjustments[i] * scale;
35         pos[i + 1].fX += globalAdj;
36     }
37 }
38 
drawKernText(SkCanvas * canvas,const void * text,size_t len,SkScalar x,SkScalar y,const SkPaint & paint)39 static void drawKernText(SkCanvas* canvas, const void* text, size_t len,
40                          SkScalar x, SkScalar y, const SkPaint& paint) {
41     SkTypeface* face = paint.getTypeface();
42     if (!face) {
43         canvas->drawText(text, len, x, y, paint);
44         return;
45     }
46 
47     SkAutoSTMalloc<128, uint16_t> glyphStorage(len);
48     uint16_t* glyphs = glyphStorage.get();
49     int glyphCount = paint.textToGlyphs(text, len, glyphs);
50     if (glyphCount < 1) {
51         return;
52     }
53 
54     SkAutoSTMalloc<128, int32_t> adjustmentStorage(glyphCount - 1);
55     int32_t* adjustments = adjustmentStorage.get();
56     if (!face->getKerningPairAdjustments(glyphs, glyphCount, adjustments)) {
57         canvas->drawText(text, len, x, y, paint);
58         return;
59     }
60 
61     SkPaint glyphPaint(paint);
62     glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
63 
64     SkAutoSTMalloc<128, SkPoint> posStorage(glyphCount);
65     SkPoint* pos = posStorage.get();
66     getGlyphPositions(glyphPaint, glyphs, glyphCount, x, y, pos);
67 
68     applyKerning(pos, adjustments, glyphCount, glyphPaint);
69     canvas->drawPosText(glyphs, glyphCount * sizeof(uint16_t), pos, glyphPaint);
70 }
71 
72 static const struct {
73     const char* fName;
74     SkTypeface::Style   fStyle;
75 } gFaceStyles[] = {
76     { "sans-serif", SkTypeface::kNormal },
77     { "sans-serif", SkTypeface::kBold },
78     { "sans-serif", SkTypeface::kItalic },
79     { "sans-serif", SkTypeface::kBoldItalic },
80     { "serif", SkTypeface::kNormal },
81     { "serif", SkTypeface::kBold },
82     { "serif", SkTypeface::kItalic },
83     { "serif", SkTypeface::kBoldItalic },
84     { "monospace", SkTypeface::kNormal },
85     { "monospace", SkTypeface::kBold },
86     { "monospace", SkTypeface::kItalic },
87     { "monospace", SkTypeface::kBoldItalic },
88 };
89 
90 static const int gFaceStylesCount = SK_ARRAY_COUNT(gFaceStyles);
91 
92 class TypefaceStylesGM : public skiagm::GM {
93     SkTypeface* fFaces[gFaceStylesCount];
94     bool fApplyKerning;
95 
96 public:
TypefaceStylesGM(bool applyKerning)97     TypefaceStylesGM(bool applyKerning)
98         : fApplyKerning(applyKerning) {
99         memset(fFaces, 0, sizeof(fFaces));
100     }
101 
~TypefaceStylesGM()102     virtual ~TypefaceStylesGM() {
103         for (int i = 0; i < gFaceStylesCount; i++) {
104             SkSafeUnref(fFaces[i]);
105         }
106     }
107 
108 protected:
onOnceBeforeDraw()109     void onOnceBeforeDraw() override {
110         for (int i = 0; i < gFaceStylesCount; i++) {
111             fFaces[i] = SkTypeface::CreateFromName(
112                     sk_tool_utils::platform_font_name(gFaceStyles[i].fName), gFaceStyles[i].fStyle);
113         }
114     }
115 
onShortName()116     SkString onShortName() override {
117         SkString name("typefacestyles");
118         if (fApplyKerning) {
119             name.append("_kerning");
120         }
121         name.append(sk_tool_utils::major_platform_os_name());
122         return name;
123     }
124 
onISize()125     SkISize onISize() override {
126         return SkISize::Make(640, 480);
127     }
128 
onDraw(SkCanvas * canvas)129     void onDraw(SkCanvas* canvas) override {
130         SkPaint paint;
131         paint.setAntiAlias(true);
132         paint.setTextSize(SkIntToScalar(30));
133 
134         const char* text = fApplyKerning ? "Type AWAY" : "Hamburgefons";
135         const size_t textLen = strlen(text);
136 
137         SkScalar x = SkIntToScalar(10);
138         SkScalar dy = paint.getFontMetrics(nullptr);
139         SkScalar y = dy;
140 
141         if (fApplyKerning) {
142             paint.setSubpixelText(true);
143         } else {
144             paint.setLinearText(true);
145         }
146         for (int i = 0; i < gFaceStylesCount; i++) {
147             paint.setTypeface(fFaces[i]);
148             canvas->drawText(text, textLen, x, y, paint);
149             if (fApplyKerning) {
150                 drawKernText(canvas, text, textLen, x + 240, y, paint);
151             }
152             y += dy;
153         }
154     }
155 
156 private:
157     typedef skiagm::GM INHERITED;
158 };
159 
160 ///////////////////////////////////////////////////////////////////////////////
161 
162 DEF_GM( return new TypefaceStylesGM(false); )
163 DEF_GM( return new TypefaceStylesGM(true); )
164