textblob.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright 2014 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/SkCanvas.h"
  9. #include "include/core/SkColor.h"
  10. #include "include/core/SkFont.h"
  11. #include "include/core/SkFontStyle.h"
  12. #include "include/core/SkFontTypes.h"
  13. #include "include/core/SkPaint.h"
  14. #include "include/core/SkPoint.h"
  15. #include "include/core/SkRect.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/SkTDArray.h"
  24. #include "tools/ToolUtils.h"
  25. #include <cstring>
  26. namespace {
  27. enum Pos {
  28. kDefault_Pos = 0,
  29. kScalar_Pos = 1,
  30. kPoint_Pos = 2,
  31. };
  32. const struct BlobCfg {
  33. unsigned count;
  34. Pos pos;
  35. SkScalar scale;
  36. } blobConfigs[][3][3] = {
  37. {
  38. { { 1024, kDefault_Pos, 1 }, { 0, kDefault_Pos, 0 }, { 0, kDefault_Pos, 0 } },
  39. { { 1024, kScalar_Pos, 1 }, { 0, kScalar_Pos, 0 }, { 0, kScalar_Pos, 0 } },
  40. { { 1024, kPoint_Pos, 1 }, { 0, kPoint_Pos, 0 }, { 0, kPoint_Pos, 0 } },
  41. },
  42. {
  43. { { 4, kDefault_Pos, 1 }, { 4, kDefault_Pos, 1 }, { 4, kDefault_Pos, 1 } },
  44. { { 4, kScalar_Pos, 1 }, { 4, kScalar_Pos, 1 }, { 4, kScalar_Pos, 1 } },
  45. { { 4, kPoint_Pos, 1 }, { 4, kPoint_Pos, 1 }, { 4, kPoint_Pos, 1 } },
  46. },
  47. {
  48. { { 4, kDefault_Pos, 1 }, { 4, kDefault_Pos, 1 }, { 4, kScalar_Pos, 1 } },
  49. { { 4, kScalar_Pos, 1 }, { 4, kScalar_Pos, 1 }, { 4, kPoint_Pos, 1 } },
  50. { { 4, kPoint_Pos, 1 }, { 4, kPoint_Pos, 1 }, { 4, kDefault_Pos, 1 } },
  51. },
  52. {
  53. { { 4, kDefault_Pos, 1 }, { 4, kScalar_Pos, 1 }, { 4, kPoint_Pos, 1 } },
  54. { { 4, kScalar_Pos, 1 }, { 4, kPoint_Pos, 1 }, { 4, kDefault_Pos, 1 } },
  55. { { 4, kPoint_Pos, 1 }, { 4, kDefault_Pos, 1 }, { 4, kScalar_Pos, 1 } },
  56. },
  57. {
  58. { { 4, kDefault_Pos, .75f }, { 4, kDefault_Pos, 1 }, { 4, kScalar_Pos, 1.25f } },
  59. { { 4, kScalar_Pos, .75f }, { 4, kScalar_Pos, 1 }, { 4, kPoint_Pos, 1.25f } },
  60. { { 4, kPoint_Pos, .75f }, { 4, kPoint_Pos, 1 }, { 4, kDefault_Pos, 1.25f } },
  61. },
  62. {
  63. { { 4, kDefault_Pos, 1 }, { 4, kScalar_Pos, .75f }, { 4, kPoint_Pos, 1.25f } },
  64. { { 4, kScalar_Pos, 1 }, { 4, kPoint_Pos, .75f }, { 4, kDefault_Pos, 1.25f } },
  65. { { 4, kPoint_Pos, 1 }, { 4, kDefault_Pos, .75f }, { 4, kScalar_Pos, 1.25f } },
  66. },
  67. };
  68. const SkScalar kFontSize = 16;
  69. }
  70. class TextBlobGM : public skiagm::GM {
  71. public:
  72. TextBlobGM(const char* txt)
  73. : fText(txt) {
  74. }
  75. protected:
  76. void onOnceBeforeDraw() override {
  77. fTypeface = ToolUtils::create_portable_typeface("serif", SkFontStyle());
  78. SkFont font(fTypeface);
  79. size_t txtLen = strlen(fText);
  80. int glyphCount = font.countText(fText, txtLen, SkTextEncoding::kUTF8);
  81. fGlyphs.append(glyphCount);
  82. font.textToGlyphs(fText, txtLen, SkTextEncoding::kUTF8, fGlyphs.begin(), glyphCount);
  83. }
  84. SkString onShortName() override {
  85. return SkString("textblob");
  86. }
  87. SkISize onISize() override {
  88. return SkISize::Make(640, 480);
  89. }
  90. void onDraw(SkCanvas* canvas) override {
  91. for (unsigned b = 0; b < SK_ARRAY_COUNT(blobConfigs); ++b) {
  92. sk_sp<SkTextBlob> blob(this->makeBlob(b));
  93. SkPaint p;
  94. p.setAntiAlias(true);
  95. SkPoint offset = SkPoint::Make(SkIntToScalar(10 + 300 * (b % 2)),
  96. SkIntToScalar(20 + 150 * (b / 2)));
  97. canvas->drawTextBlob(blob, offset.x(), offset.y(), p);
  98. p.setColor(SK_ColorBLUE);
  99. p.setStyle(SkPaint::kStroke_Style);
  100. SkRect box = blob->bounds();
  101. box.offset(offset);
  102. p.setAntiAlias(false);
  103. canvas->drawRect(box, p);
  104. }
  105. }
  106. private:
  107. sk_sp<SkTextBlob> makeBlob(unsigned blobIndex) {
  108. SkTextBlobBuilder builder;
  109. SkFont font;
  110. font.setSubpixel(true);
  111. font.setEdging(SkFont::Edging::kAntiAlias);
  112. font.setTypeface(fTypeface);
  113. for (unsigned l = 0; l < SK_ARRAY_COUNT(blobConfigs[blobIndex]); ++l) {
  114. unsigned currentGlyph = 0;
  115. for (unsigned c = 0; c < SK_ARRAY_COUNT(blobConfigs[blobIndex][l]); ++c) {
  116. const BlobCfg* cfg = &blobConfigs[blobIndex][l][c];
  117. unsigned count = cfg->count;
  118. if (count > fGlyphs.count() - currentGlyph) {
  119. count = fGlyphs.count() - currentGlyph;
  120. }
  121. if (0 == count) {
  122. break;
  123. }
  124. font.setSize(kFontSize * cfg->scale);
  125. const SkScalar advanceX = font.getSize() * 0.85f;
  126. const SkScalar advanceY = font.getSize() * 1.5f;
  127. SkPoint offset = SkPoint::Make(currentGlyph * advanceX + c * advanceX,
  128. advanceY * l);
  129. switch (cfg->pos) {
  130. case kDefault_Pos: {
  131. const SkTextBlobBuilder::RunBuffer& buf = builder.allocRun(font, count,
  132. offset.x(),
  133. offset.y());
  134. memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
  135. } break;
  136. case kScalar_Pos: {
  137. const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPosH(font, count,
  138. offset.y());
  139. SkTDArray<SkScalar> pos;
  140. for (unsigned i = 0; i < count; ++i) {
  141. *pos.append() = offset.x() + i * advanceX;
  142. }
  143. memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
  144. memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar));
  145. } break;
  146. case kPoint_Pos: {
  147. const SkTextBlobBuilder::RunBuffer& buf = builder.allocRunPos(font, count);
  148. SkTDArray<SkScalar> pos;
  149. for (unsigned i = 0; i < count; ++i) {
  150. *pos.append() = offset.x() + i * advanceX;
  151. *pos.append() = offset.y() + i * (advanceY / count);
  152. }
  153. memcpy(buf.glyphs, fGlyphs.begin() + currentGlyph, count * sizeof(uint16_t));
  154. memcpy(buf.pos, pos.begin(), count * sizeof(SkScalar) * 2);
  155. } break;
  156. default:
  157. SK_ABORT("unhandled pos value");
  158. }
  159. currentGlyph += count;
  160. }
  161. }
  162. return builder.make();
  163. }
  164. SkTDArray<uint16_t> fGlyphs;
  165. sk_sp<SkTypeface> fTypeface;
  166. const char* fText;
  167. typedef skiagm::GM INHERITED;
  168. };
  169. DEF_GM(return new TextBlobGM("hamburgefons");)