blob: c329395b86a0332da1866b2ee5e0f94a630797cb [file] [log] [blame]
scroggo@google.com3cb969f2012-07-27 20:39:19 +00001/*
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
reed@google.com92abe482013-02-26 16:57:16 +000014static const char* gFaces[] = {
scroggo@google.com3cb969f2012-07-27 20:39:19 +000015 "Times Roman",
16 "Hiragino Maru Gothic Pro",
17 "Papyrus",
18 "Helvetica",
19 "Courier New"
20};
21
reed@google.com92abe482013-02-26 16:57:16 +000022class TypefaceGM : public skiagm::GM {
scroggo@google.com3cb969f2012-07-27 20:39:19 +000023public:
24 TypefaceGM() {
25 fFaces = new SkTypeface*[SK_ARRAY_COUNT(gFaces)];
26 for (size_t i = 0; i < SK_ARRAY_COUNT(gFaces); i++) {
Cary Clark992c7b02014-07-31 08:58:44 -040027 fFaces[i] = sk_tool_utils::create_portable_typeface(gFaces[i], SkTypeface::kNormal);
scroggo@google.com3cb969f2012-07-27 20:39:19 +000028 }
29 }
30
31 virtual ~TypefaceGM() {
32 for (size_t i = 0; i < SK_ARRAY_COUNT(gFaces); i++) {
reed@google.com098b7ff2013-02-26 17:01:26 +000033 SkSafeUnref(fFaces[i]);
scroggo@google.com3cb969f2012-07-27 20:39:19 +000034 }
robertphillips@google.com5d8d1862012-08-15 14:36:41 +000035 delete [] fFaces;
scroggo@google.com3cb969f2012-07-27 20:39:19 +000036 }
37
38protected:
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);
reed@google.com7fa2a652014-01-27 13:42:58 +000053 for (int i = 0; i < (int)SK_ARRAY_COUNT(gFaces); i++) {
scroggo@google.com3cb969f2012-07-27 20:39:19 +000054 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
62private:
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;
rmistry@google.comae933ce2012-08-23 18:19:56 +000071
reed@google.com92abe482013-02-26 16:57:16 +000072 typedef skiagm::GM INHERITED;
scroggo@google.com3cb969f2012-07-27 20:39:19 +000073};
74
reed@google.com92abe482013-02-26 16:57:16 +000075///////////////////////////////////////////////////////////////////////////////
scroggo@google.com3cb969f2012-07-27 20:39:19 +000076
reed@google.com35fe7372013-10-30 15:07:03 +000077static 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);
skia.committer@gmail.com7ed98df2013-10-31 07:01:53 +000084
reed@google.com35fe7372013-10-30 15:07:03 +000085 for (int i = 0; i < count; ++i) {
86 pos[i].set(x, y);
87 x += widths[i];
88 }
89}
90
91static 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
102static 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
reed@google.com92abe482013-02-26 16:57:16 +0000135static 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};
scroggo@google.com3cb969f2012-07-27 20:39:19 +0000152
reed@google.com92abe482013-02-26 16:57:16 +0000153static const int gFaceStylesCount = SK_ARRAY_COUNT(gFaceStyles);
154
155class TypefaceStylesGM : public skiagm::GM {
156 SkTypeface* fFaces[gFaceStylesCount];
reed@google.com35fe7372013-10-30 15:07:03 +0000157 bool fApplyKerning;
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +0000158
reed@google.com92abe482013-02-26 16:57:16 +0000159public:
reed@google.com35fe7372013-10-30 15:07:03 +0000160 TypefaceStylesGM(bool applyKerning) : fApplyKerning(applyKerning) {
reed@google.com92abe482013-02-26 16:57:16 +0000161 for (int i = 0; i < gFaceStylesCount; i++) {
Cary Clark992c7b02014-07-31 08:58:44 -0400162 fFaces[i] = sk_tool_utils::create_portable_typeface(gFaceStyles[i].fName,
163 gFaceStyles[i].fStyle);
reed@google.com92abe482013-02-26 16:57:16 +0000164 }
165 }
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +0000166
reed@google.com92abe482013-02-26 16:57:16 +0000167 virtual ~TypefaceStylesGM() {
168 for (int i = 0; i < gFaceStylesCount; i++) {
169 SkSafeUnref(fFaces[i]);
170 }
171 }
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +0000172
reed@google.com92abe482013-02-26 16:57:16 +0000173protected:
174 virtual SkString onShortName() SK_OVERRIDE {
reed@google.com35fe7372013-10-30 15:07:03 +0000175 SkString name("typefacestyles");
176 if (fApplyKerning) {
177 name.append("_kerning");
178 }
179 return name;
reed@google.com92abe482013-02-26 16:57:16 +0000180 }
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +0000181
reed@google.com92abe482013-02-26 16:57:16 +0000182 virtual SkISize onISize() SK_OVERRIDE {
183 return SkISize::Make(640, 480);
184 }
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +0000185
reed@google.com92abe482013-02-26 16:57:16 +0000186 virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
187 SkPaint paint;
188 paint.setAntiAlias(true);
189 paint.setTextSize(SkIntToScalar(30));
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +0000190
reed@google.com35fe7372013-10-30 15:07:03 +0000191 const char* text = fApplyKerning ? "Type AWAY" : "Hamburgefons";
reed@google.com92abe482013-02-26 16:57:16 +0000192 const size_t textLen = strlen(text);
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +0000193
reed@google.com92abe482013-02-26 16:57:16 +0000194 SkScalar x = SkIntToScalar(10);
195 SkScalar dy = paint.getFontMetrics(NULL);
196 SkScalar y = dy;
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +0000197
reed@google.com35fe7372013-10-30 15:07:03 +0000198 if (fApplyKerning) {
199 paint.setSubpixelText(true);
200 } else {
201 paint.setLinearText(true);
202 }
reed@google.com92abe482013-02-26 16:57:16 +0000203 for (int i = 0; i < gFaceStylesCount; i++) {
204 paint.setTypeface(fFaces[i]);
205 canvas->drawText(text, textLen, x, y, paint);
reed@google.com35fe7372013-10-30 15:07:03 +0000206 if (fApplyKerning) {
207 drawKernText(canvas, text, textLen, x + 240, y, paint);
208 }
reed@google.com92abe482013-02-26 16:57:16 +0000209 y += dy;
210 }
211 }
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +0000212
reed@google.com92abe482013-02-26 16:57:16 +0000213private:
214 typedef skiagm::GM INHERITED;
215};
skia.committer@gmail.com12eea2b2013-02-27 07:10:10 +0000216
reed@google.com92abe482013-02-26 16:57:16 +0000217///////////////////////////////////////////////////////////////////////////////
218
219DEF_GM( return new TypefaceGM; )
reed@google.com35fe7372013-10-30 15:07:03 +0000220DEF_GM( return new TypefaceStylesGM(false); )
221DEF_GM( return new TypefaceStylesGM(true); )