typeface.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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. #include "gm/gm.h"
  8. #include "include/core/SkBlurTypes.h"
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkFont.h"
  11. #include "include/core/SkFontStyle.h"
  12. #include "include/core/SkFontTypes.h"
  13. #include "include/core/SkMaskFilter.h"
  14. #include "include/core/SkPaint.h"
  15. #include "include/core/SkPoint.h"
  16. #include "include/core/SkRefCnt.h"
  17. #include "include/core/SkScalar.h"
  18. #include "include/core/SkSize.h"
  19. #include "include/core/SkString.h"
  20. #include "include/core/SkTextBlob.h"
  21. #include "include/core/SkTypeface.h"
  22. #include "include/core/SkTypes.h"
  23. #include "include/private/SkTemplates.h"
  24. #include "tools/Resources.h"
  25. #include <string.h>
  26. #include <utility>
  27. static void getGlyphPositions(const SkFont& font, const uint16_t glyphs[],
  28. int count, SkScalar x, SkScalar y, SkPoint pos[]) {
  29. SkAutoSTMalloc<128, SkScalar> widthStorage(count);
  30. SkScalar* widths = widthStorage.get();
  31. font.getWidths(glyphs, count, widths);
  32. for (int i = 0; i < count; ++i) {
  33. pos[i].set(x, y);
  34. x += widths[i];
  35. }
  36. }
  37. static void applyKerning(SkPoint pos[], const int32_t adjustments[], int count,
  38. const SkFont& font) {
  39. SkScalar scale = font.getSize() / font.getTypefaceOrDefault()->getUnitsPerEm();
  40. SkScalar globalAdj = 0;
  41. for (int i = 0; i < count - 1; ++i) {
  42. globalAdj += adjustments[i] * scale;
  43. pos[i + 1].fX += globalAdj;
  44. }
  45. }
  46. static void drawKernText(SkCanvas* canvas, const void* text, size_t len,
  47. SkScalar x, SkScalar y, const SkFont& font, const SkPaint& paint) {
  48. SkTypeface* face = font.getTypefaceOrDefault();
  49. if (!face) {
  50. canvas->drawSimpleText(text, len, SkTextEncoding::kUTF8, x, y, font, paint);
  51. return;
  52. }
  53. SkAutoSTMalloc<128, uint16_t> glyphStorage(len);
  54. uint16_t* glyphs = glyphStorage.get();
  55. int glyphCount = font.textToGlyphs(text, len, SkTextEncoding::kUTF8, glyphs, len);
  56. if (glyphCount < 1) {
  57. return;
  58. }
  59. SkAutoSTMalloc<128, int32_t> adjustmentStorage(glyphCount - 1);
  60. int32_t* adjustments = adjustmentStorage.get();
  61. if (!face->getKerningPairAdjustments(glyphs, glyphCount, adjustments)) {
  62. canvas->drawSimpleText(text, len, SkTextEncoding::kUTF8, x, y, font, paint);
  63. return;
  64. }
  65. SkTextBlobBuilder builder;
  66. auto rec = builder.allocRunPos(font, glyphCount);
  67. memcpy(rec.glyphs, glyphs, glyphCount * sizeof(SkGlyphID));
  68. getGlyphPositions(font, glyphs, glyphCount, x, y, rec.points());
  69. applyKerning(rec.points(), adjustments, glyphCount, font);
  70. canvas->drawTextBlob(builder.make(), 0, 0, paint);
  71. }
  72. static constexpr SkFontStyle gStyles[] = {
  73. SkFontStyle::Normal(),
  74. SkFontStyle::Bold(),
  75. SkFontStyle::Italic(),
  76. SkFontStyle::BoldItalic(),
  77. };
  78. constexpr int gStylesCount = SK_ARRAY_COUNT(gStyles);
  79. class TypefaceStylesGM : public skiagm::GM {
  80. sk_sp<SkTypeface> fFaces[gStylesCount];
  81. bool fApplyKerning;
  82. public:
  83. TypefaceStylesGM(bool applyKerning) : fApplyKerning(applyKerning) {}
  84. protected:
  85. void onOnceBeforeDraw() override {
  86. for (int i = 0; i < gStylesCount; i++) {
  87. fFaces[i] = SkTypeface::MakeFromName(nullptr, gStyles[i]);
  88. }
  89. }
  90. SkString onShortName() override {
  91. SkString name("typefacestyles");
  92. if (fApplyKerning) {
  93. name.append("_kerning");
  94. }
  95. return name;
  96. }
  97. SkISize onISize() override {
  98. return SkISize::Make(640, 480);
  99. }
  100. void onDraw(SkCanvas* canvas) override {
  101. SkFont font;
  102. font.setSize(30);
  103. const char* text = fApplyKerning ? "Type AWAY" : "Hamburgefons";
  104. const size_t textLen = strlen(text);
  105. SkScalar x = SkIntToScalar(10);
  106. SkScalar dy = font.getMetrics(nullptr);
  107. SkScalar y = dy;
  108. if (fApplyKerning) {
  109. font.setSubpixel(true);
  110. } else {
  111. font.setLinearMetrics(true);
  112. }
  113. SkPaint paint;
  114. for (int i = 0; i < gStylesCount; i++) {
  115. font.setTypeface(fFaces[i]);
  116. canvas->drawSimpleText(text, textLen, SkTextEncoding::kUTF8, x, y, font, paint);
  117. if (fApplyKerning) {
  118. drawKernText(canvas, text, textLen, x + 240, y, font, paint);
  119. }
  120. y += dy;
  121. }
  122. }
  123. private:
  124. typedef skiagm::GM INHERITED;
  125. };
  126. DEF_GM( return new TypefaceStylesGM(false); )
  127. DEF_GM( return new TypefaceStylesGM(true); )
  128. ////////////////////////////////////////////////////////////////////////////////
  129. static void draw_typeface_rendering_gm(SkCanvas* canvas, sk_sp<SkTypeface> face,
  130. char character = 'A') {
  131. struct AliasType {
  132. SkFont::Edging edging;
  133. bool inLayer;
  134. } constexpr aliasTypes[] {
  135. #ifndef SK_BUILD_FOR_IOS
  136. // This gm crashes on iOS when drawing an embedded bitmap when requesting aliased rendering.
  137. // The crash looks like
  138. // libTrueTypeScaler.dylib`<redacted> + 80
  139. // stop reason = EXC_BAD_ACCESS (code=EXC_ARM_DA_ALIGN, address=...)
  140. // -> 0x330b19d0 <+80>: strd r2, r3, [r5, #36]
  141. // 0x330b19d4 <+84>: movs r3, #0x0
  142. // 0x330b19d6 <+86>: add r2, sp, #0x28
  143. // 0x330b19d8 <+88>: ldr r0, [r4, #0x4]
  144. // Disable testing embedded bitmaps on iOS for now.
  145. // See https://bug.skia.org/5530 .
  146. { SkFont::Edging::kAlias , false },
  147. #endif
  148. { SkFont::Edging::kAntiAlias , false },
  149. { SkFont::Edging::kSubpixelAntiAlias, false },
  150. { SkFont::Edging::kAntiAlias , true },
  151. { SkFont::Edging::kSubpixelAntiAlias, true },
  152. };
  153. // The hintgasp.ttf is designed for the following sizes to be different.
  154. // GASP_DOGRAY 0x0002 0<=ppem<=10
  155. // GASP_SYMMETRIC_SMOOTHING 0x0008 0<=ppem<=10
  156. // GASP_GRIDFIT 0x0001 11<=ppem<=12
  157. // GASP_SYMMETRIC_GRIDFIT 0x0004 11<=ppem<=12
  158. // GASP_DOGRAY|GASP_GRIDFIT 0x0003 13<=ppem<=14
  159. // GASP_SYMMETRIC_SMOOTHING|GASP_SYMMETRIC_GRIDFIT 0x000C 13<=ppem<=14
  160. // (neither) 0x0000 15<=ppem
  161. // Odd sizes have embedded bitmaps.
  162. constexpr SkScalar textSizes[] = { 9, 10, 11, 12, 13, 14, 15, 16 };
  163. constexpr SkFontHinting hintingTypes[] = {
  164. SkFontHinting::kNone,
  165. SkFontHinting::kSlight,
  166. SkFontHinting::kNormal,
  167. SkFontHinting::kFull
  168. };
  169. struct SubpixelType {
  170. bool requested;
  171. SkVector offset;
  172. } constexpr subpixelTypes[] = {
  173. { false, { 0.00, 0.00 } },
  174. { true , { 0.00, 0.00 } },
  175. { true , { 0.25, 0.00 } },
  176. { true , { 0.25, 0.25 } },
  177. };
  178. constexpr bool rotateABitTypes[] = { false, true };
  179. SkScalar y = 0; // The baseline of the previous output
  180. {
  181. SkPaint paint;
  182. SkFont font(face);
  183. font.setEmbeddedBitmaps(true);
  184. SkScalar x = 0;
  185. SkScalar xMax = x;
  186. SkScalar xBase = 0;
  187. for (const SubpixelType subpixel : subpixelTypes) {
  188. y = 0;
  189. font.setSubpixel(subpixel.requested);
  190. for (const AliasType& alias : aliasTypes) {
  191. font.setEdging(alias.edging);
  192. SkAutoCanvasRestore acr(canvas, false);
  193. if (alias.inLayer) {
  194. canvas->saveLayer(nullptr, &paint);
  195. }
  196. for (const SkScalar& textSize : textSizes) {
  197. x = xBase + 5;
  198. font.setSize(textSize);
  199. SkScalar dy = SkScalarCeilToScalar(font.getMetrics(nullptr));
  200. y += dy;
  201. for (const SkFontHinting& hinting : hintingTypes) {
  202. font.setHinting(hinting);
  203. for (const bool& rotateABit : rotateABitTypes) {
  204. SkAutoCanvasRestore acr(canvas, true);
  205. if (rotateABit) {
  206. canvas->rotate(2, x + subpixel.offset.x(),
  207. y + subpixel.offset.y());
  208. }
  209. canvas->drawSimpleText(&character, 1, SkTextEncoding::kUTF8,
  210. x + subpixel.offset.x(),
  211. y + subpixel.offset.y(), font, paint);
  212. SkScalar dx = SkScalarCeilToScalar(
  213. font.measureText(&character, 1, SkTextEncoding::kUTF8)) + 5;
  214. x += dx;
  215. xMax = SkTMax(x, xMax);
  216. }
  217. }
  218. }
  219. y += 10;
  220. }
  221. xBase = xMax;
  222. }
  223. }
  224. constexpr struct StyleTests {
  225. SkPaint::Style style;
  226. SkScalar strokeWidth;
  227. } styleTypes[] = {
  228. { SkPaint::kFill_Style, 0.0f},
  229. { SkPaint::kStroke_Style, 0.0f},
  230. { SkPaint::kStroke_Style, 0.5f},
  231. { SkPaint::kStrokeAndFill_Style, 1.0f},
  232. };
  233. constexpr bool fakeBoldTypes[] = { false, true };
  234. {
  235. SkPaint paint;
  236. SkFont font(face, 16);
  237. SkScalar x = 0;
  238. for (const bool& fakeBold : fakeBoldTypes) {
  239. SkScalar dy = SkScalarCeilToScalar(font.getMetrics(nullptr));
  240. y += dy;
  241. x = 5;
  242. font.setEmbolden(fakeBold);
  243. for (const AliasType& alias : aliasTypes) {
  244. font.setEdging(alias.edging);
  245. SkAutoCanvasRestore acr(canvas, false);
  246. if (alias.inLayer) {
  247. canvas->saveLayer(nullptr, &paint);
  248. }
  249. for (const StyleTests& style : styleTypes) {
  250. paint.setStyle(style.style);
  251. paint.setStrokeWidth(style.strokeWidth);
  252. canvas->drawSimpleText(&character, 1, SkTextEncoding::kUTF8, x, y, font, paint);
  253. SkScalar dx = SkScalarCeilToScalar(font.measureText(&character, 1,
  254. SkTextEncoding::kUTF8)) + 5;
  255. x += dx;
  256. }
  257. }
  258. y += 10;
  259. }
  260. }
  261. constexpr struct MaskTests {
  262. SkBlurStyle style;
  263. SkScalar sigma;
  264. } maskTypes[] = {
  265. { SkBlurStyle::kNormal_SkBlurStyle, 0.0f},
  266. { SkBlurStyle::kSolid_SkBlurStyle, 0.0f},
  267. { SkBlurStyle::kOuter_SkBlurStyle, 0.0f},
  268. { SkBlurStyle::kInner_SkBlurStyle, 0.0f},
  269. { SkBlurStyle::kNormal_SkBlurStyle, 0.5f},
  270. { SkBlurStyle::kSolid_SkBlurStyle, 0.5f},
  271. { SkBlurStyle::kOuter_SkBlurStyle, 0.5f},
  272. { SkBlurStyle::kInner_SkBlurStyle, 0.5f},
  273. { SkBlurStyle::kNormal_SkBlurStyle, 2.0f},
  274. { SkBlurStyle::kSolid_SkBlurStyle, 2.0f},
  275. { SkBlurStyle::kOuter_SkBlurStyle, 2.0f},
  276. { SkBlurStyle::kInner_SkBlurStyle, 2.0f},
  277. };
  278. {
  279. SkPaint paint;
  280. SkFont font(face, 16);
  281. SkScalar x = 0;
  282. {
  283. for (const AliasType& alias : aliasTypes) {
  284. SkScalar dy = SkScalarCeilToScalar(font.getMetrics(nullptr));
  285. y += dy;
  286. x = 5;
  287. font.setEdging(alias.edging);
  288. SkAutoCanvasRestore acr(canvas, false);
  289. if (alias.inLayer) {
  290. canvas->saveLayer(nullptr, &paint);
  291. }
  292. for (const MaskTests& mask : maskTypes) {
  293. paint.setMaskFilter(SkMaskFilter::MakeBlur(mask.style, mask.sigma));
  294. canvas->drawSimpleText(&character, 1, SkTextEncoding::kUTF8, x, y, font, paint);
  295. SkScalar dx = SkScalarCeilToScalar(font.measureText(&character, 1,
  296. SkTextEncoding::kUTF8)) + 5;
  297. x += dx;
  298. }
  299. paint.setMaskFilter(nullptr);
  300. }
  301. y += 10;
  302. }
  303. }
  304. }
  305. DEF_SIMPLE_GM(typefacerendering, canvas, 640, 840) {
  306. if (sk_sp<SkTypeface> face = MakeResourceAsTypeface("fonts/hintgasp.ttf")) {
  307. draw_typeface_rendering_gm(canvas, std::move(face));
  308. }
  309. }
  310. // Type1 fonts don't currently work in Skia on Windows.
  311. #ifndef SK_BUILD_FOR_WIN
  312. DEF_SIMPLE_GM(typefacerendering_pfa, canvas, 640, 840) {
  313. if (sk_sp<SkTypeface> face = MakeResourceAsTypeface("fonts/Roboto2-Regular.pfa")) {
  314. // This subsetted typeface doesn't have the character 'A'.
  315. draw_typeface_rendering_gm(canvas, std::move(face), 'O');
  316. }
  317. }
  318. DEF_SIMPLE_GM(typefacerendering_pfb, canvas, 640, 840) {
  319. if (sk_sp<SkTypeface> face = MakeResourceAsTypeface("fonts/Roboto2-Regular.pfb")) {
  320. draw_typeface_rendering_gm(canvas, std::move(face), 'O');
  321. }
  322. }
  323. #endif