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] = sk_tool_utils::create_portable_typeface(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 SkString onShortName() override { 40 return SkString("typeface"); 41 } 42 43 SkISize onISize() override { 44 return SkISize::Make(640, 480); 45 } 46 47 void onDraw(SkCanvas* canvas) 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] = sk_tool_utils::create_portable_typeface(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 SkString onShortName() override { 175 SkString name("typefacestyles"); 176 if (fApplyKerning) { 177 name.append("_kerning"); 178 } 179 return name; 180 } 181 182 SkISize onISize() override { 183 return SkISize::Make(640, 480); 184 } 185 186 void onDraw(SkCanvas* canvas) 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