textbloblooper.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * Copyright 2013 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/SkBlendMode.h"
  9. #include "include/core/SkBlurTypes.h"
  10. #include "include/core/SkCanvas.h"
  11. #include "include/core/SkColor.h"
  12. #include "include/core/SkColorFilter.h"
  13. #include "include/core/SkDrawLooper.h"
  14. #include "include/core/SkFont.h"
  15. #include "include/core/SkFontTypes.h"
  16. #include "include/core/SkMaskFilter.h"
  17. #include "include/core/SkMatrix.h"
  18. #include "include/core/SkPaint.h"
  19. #include "include/core/SkPath.h"
  20. #include "include/core/SkPathEffect.h"
  21. #include "include/core/SkPoint.h"
  22. #include "include/core/SkRect.h"
  23. #include "include/core/SkRefCnt.h"
  24. #include "include/core/SkScalar.h"
  25. #include "include/core/SkShader.h"
  26. #include "include/core/SkSize.h"
  27. #include "include/core/SkString.h"
  28. #include "include/core/SkTextBlob.h"
  29. #include "include/core/SkTileMode.h"
  30. #include "include/core/SkTypeface.h"
  31. #include "include/core/SkTypes.h"
  32. #include "include/effects/Sk2DPathEffect.h"
  33. #include "include/effects/SkColorMatrixFilter.h"
  34. #include "include/effects/SkGradientShader.h"
  35. #include "include/effects/SkLayerDrawLooper.h"
  36. #include "include/private/SkTArray.h"
  37. #include "include/private/SkTDArray.h"
  38. #include "src/core/SkBlurMask.h"
  39. #include "tools/ToolUtils.h"
  40. #include <string.h>
  41. #ifdef SK_SUPPORT_LEGACY_DRAWLOOPER
  42. namespace skiagm {
  43. constexpr int kWidth = 1250;
  44. constexpr int kHeight = 700;
  45. // Unlike the variant in ToolUtils, this version positions the glyphs on a diagonal
  46. static void add_to_text_blob(SkTextBlobBuilder* builder, const char* text, const SkFont& font,
  47. SkScalar x, SkScalar y) {
  48. SkTDArray<uint16_t> glyphs;
  49. size_t len = strlen(text);
  50. glyphs.append(font.countText(text, len, SkTextEncoding::kUTF8));
  51. font.textToGlyphs(text, len, SkTextEncoding::kUTF8, glyphs.begin(), glyphs.count());
  52. const SkScalar advanceX = font.getSize() * 0.85f;
  53. const SkScalar advanceY = font.getSize() * 1.5f;
  54. SkTDArray<SkScalar> pos;
  55. for (unsigned i = 0; i < len; ++i) {
  56. *pos.append() = x + i * advanceX;
  57. *pos.append() = y + i * (advanceY / len);
  58. }
  59. const SkTextBlobBuilder::RunBuffer& run = builder->allocRunPos(font, glyphs.count());
  60. memcpy(run.glyphs, glyphs.begin(), glyphs.count() * sizeof(uint16_t));
  61. memcpy(run.pos, pos.begin(), len * sizeof(SkScalar) * 2);
  62. }
  63. typedef void (*LooperProc)(SkPaint*);
  64. struct LooperSettings {
  65. SkBlendMode fMode;
  66. SkColor fColor;
  67. SkPaint::Style fStyle;
  68. SkScalar fWidth;
  69. SkScalar fOffset;
  70. SkScalar fSkewX;
  71. bool fEffect;
  72. };
  73. static void mask_filter(SkPaint* paint) {
  74. paint->setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle,
  75. SkBlurMask::ConvertRadiusToSigma(3.f)));
  76. }
  77. static sk_sp<SkPathEffect> make_tile_effect() {
  78. SkMatrix m;
  79. m.setScale(1.f, 1.f);
  80. SkPath path;
  81. path.addCircle(0, 0, SkIntToScalar(5));
  82. return SkPath2DPathEffect::Make(m, path);
  83. }
  84. static void path_effect(SkPaint* paint) {
  85. paint->setPathEffect(make_tile_effect());
  86. }
  87. static sk_sp<SkShader> make_shader(const SkRect& bounds) {
  88. const SkPoint pts[] = {
  89. { bounds.left(), bounds.top() },
  90. { bounds.right(), bounds.bottom() },
  91. };
  92. const SkColor colors[] = {
  93. SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE, SK_ColorBLACK,
  94. SK_ColorCYAN, SK_ColorMAGENTA, SK_ColorYELLOW,
  95. };
  96. return SkGradientShader::MakeLinear(pts, colors, nullptr, SK_ARRAY_COUNT(colors),
  97. SkTileMode::kClamp);
  98. }
  99. static void color_filter(SkPaint* paint) {
  100. SkRect r;
  101. r.setWH(SkIntToScalar(kWidth), 50);
  102. paint->setShader(make_shader(r));
  103. paint->setColorFilter(SkColorMatrixFilter::MakeLightingFilter(0xF0F0F0, 0));
  104. }
  105. static void kitchen_sink(SkPaint* paint) {
  106. color_filter(paint);
  107. path_effect(paint);
  108. mask_filter(paint);
  109. }
  110. static sk_sp<SkDrawLooper> setupLooper(SkLayerDrawLooper::BitFlags bits,
  111. LooperProc proc,
  112. const LooperSettings settings[],
  113. size_t size) {
  114. SkLayerDrawLooper::Builder looperBuilder;
  115. SkLayerDrawLooper::LayerInfo info;
  116. info.fPaintBits = bits;
  117. info.fColorMode = SkBlendMode::kSrc;
  118. for (size_t i = 0; i < size; i++) {
  119. info.fOffset.set(settings[i].fOffset, settings[i].fOffset);
  120. SkPaint* paint = looperBuilder.addLayer(info);
  121. paint->setBlendMode(settings[i].fMode);
  122. paint->setColor(settings[i].fColor);
  123. paint->setStyle(settings[i].fStyle);
  124. paint->setStrokeWidth(settings[i].fWidth);
  125. if (settings[i].fEffect) {
  126. (*proc)(paint);
  127. }
  128. }
  129. return looperBuilder.detach();
  130. }
  131. class TextBlobLooperGM : public GM {
  132. public:
  133. TextBlobLooperGM() {}
  134. protected:
  135. void onOnceBeforeDraw() override {
  136. SkTextBlobBuilder builder;
  137. // LCD
  138. SkFont font;
  139. font.setSize(32);
  140. const char* text = "The quick brown fox jumps over the lazy dog";
  141. font.setSubpixel(true);
  142. font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
  143. font.setTypeface(ToolUtils::create_portable_typeface());
  144. add_to_text_blob(&builder, text, font, 0, 0);
  145. fBlob = builder.make();
  146. // create a looper which sandwhiches an effect in two normal draws
  147. LooperSettings looperSandwhich[] = {
  148. { SkBlendMode::kSrc, SK_ColorMAGENTA, SkPaint::kFill_Style, 0, 0, 0, false },
  149. { SkBlendMode::kSrcOver, 0x88000000, SkPaint::kFill_Style, 0, 10.f, 0, true },
  150. { SkBlendMode::kSrcOver, 0x50FF00FF, SkPaint::kFill_Style, 0, 20.f, 0, false },
  151. };
  152. LooperSettings compound[] = {
  153. { SkBlendMode::kSrc, SK_ColorWHITE, SkPaint::kStroke_Style, 1.f * 3/4, 0, 0, false },
  154. { SkBlendMode::kSrc, SK_ColorRED, SkPaint::kStroke_Style, 4.f, 0, 0, false },
  155. { SkBlendMode::kSrc, SK_ColorBLUE, SkPaint::kFill_Style, 0, 0, 0, false },
  156. { SkBlendMode::kSrcOver, 0x88000000, SkPaint::kFill_Style, 0, 10.f, 0, true }
  157. };
  158. LooperSettings xfermode[] = {
  159. { SkBlendMode::kDifference, SK_ColorWHITE, SkPaint::kFill_Style, 0, 0, 0, false },
  160. { SkBlendMode::kSrcOver, 0xFF000000, SkPaint::kFill_Style, 0, 1.f, 0, true },
  161. { SkBlendMode::kSrcOver, 0x50FF00FF, SkPaint::kFill_Style, 0, 2.f, 0, false },
  162. };
  163. // NOTE, this should be ignored by textblobs
  164. LooperSettings skew[] = {
  165. { SkBlendMode::kSrc, SK_ColorRED, SkPaint::kFill_Style, 0, 0, -1.f, false },
  166. { SkBlendMode::kSrc, SK_ColorGREEN, SkPaint::kFill_Style, 0, 10.f, -1.f, false },
  167. { SkBlendMode::kSrc, SK_ColorBLUE, SkPaint::kFill_Style, 0, 20.f, -1.f, false },
  168. };
  169. LooperSettings kitchenSink[] = {
  170. { SkBlendMode::kSrc, SK_ColorWHITE, SkPaint::kStroke_Style, 1.f * 3/4, 0, 0, false },
  171. { SkBlendMode::kSrc, SK_ColorBLACK, SkPaint::kFill_Style, 0, 0, 0, false },
  172. { SkBlendMode::kDifference, SK_ColorWHITE, SkPaint::kFill_Style, 1.f, 10.f, 0, false },
  173. { SkBlendMode::kSrc, SK_ColorWHITE, SkPaint::kFill_Style, 0, 10.f, 0, true },
  174. { SkBlendMode::kSrcOver, 0x50FF00FF, SkPaint::kFill_Style, 0, 20.f, 0, false },
  175. };
  176. fLoopers.push_back(setupLooper(SkLayerDrawLooper::kMaskFilter_Bit |
  177. SkLayerDrawLooper::kXfermode_Bit |
  178. SkLayerDrawLooper::kStyle_Bit, &mask_filter,
  179. compound, SK_ARRAY_COUNT(compound)));
  180. fLoopers.push_back(setupLooper(SkLayerDrawLooper::kPathEffect_Bit |
  181. SkLayerDrawLooper::kXfermode_Bit, &path_effect,
  182. looperSandwhich, SK_ARRAY_COUNT(looperSandwhich)));
  183. fLoopers.push_back(setupLooper(SkLayerDrawLooper::kShader_Bit |
  184. SkLayerDrawLooper::kColorFilter_Bit |
  185. SkLayerDrawLooper::kXfermode_Bit, &color_filter,
  186. looperSandwhich, SK_ARRAY_COUNT(looperSandwhich)));
  187. fLoopers.push_back(setupLooper(SkLayerDrawLooper::kShader_Bit |
  188. SkLayerDrawLooper::kColorFilter_Bit |
  189. SkLayerDrawLooper::kXfermode_Bit, &color_filter,
  190. xfermode, SK_ARRAY_COUNT(xfermode)));
  191. fLoopers.push_back(setupLooper(0, nullptr, skew, SK_ARRAY_COUNT(skew)));
  192. fLoopers.push_back(setupLooper(SkLayerDrawLooper::kMaskFilter_Bit |
  193. SkLayerDrawLooper::kShader_Bit |
  194. SkLayerDrawLooper::kColorFilter_Bit |
  195. SkLayerDrawLooper::kPathEffect_Bit |
  196. SkLayerDrawLooper::kStyle_Bit |
  197. SkLayerDrawLooper::kXfermode_Bit, &kitchen_sink,
  198. kitchenSink, SK_ARRAY_COUNT(kitchenSink)));
  199. // Test we respect overrides
  200. fLoopers.push_back(setupLooper(0, &kitchen_sink,
  201. kitchenSink, SK_ARRAY_COUNT(kitchenSink)));
  202. }
  203. SkString onShortName() override {
  204. return SkString("textbloblooper");
  205. }
  206. SkISize onISize() override {
  207. return SkISize::Make(kWidth, kHeight);
  208. }
  209. void onDraw(SkCanvas* canvas) override {
  210. canvas->drawColor(SK_ColorGRAY);
  211. SkPaint paint;
  212. canvas->translate(10, 40);
  213. SkRect bounds = fBlob->bounds();
  214. int y = 0;
  215. for (int looper = 0; looper < fLoopers.count(); looper++) {
  216. SkTextBlob* b = fBlob.get();
  217. canvas->save();
  218. canvas->translate(0, SkIntToScalar(y));
  219. fLoopers[looper]->apply(canvas, paint, [b](SkCanvas* c, const SkPaint& p) {
  220. c->drawTextBlob(b, 0, 0, p);
  221. });
  222. canvas->restore();
  223. y += SkScalarFloorToInt(bounds.height());
  224. }
  225. }
  226. private:
  227. sk_sp<SkTextBlob> fBlob;
  228. SkTArray<sk_sp<SkDrawLooper>> fLoopers;
  229. typedef GM INHERITED;
  230. };
  231. //////////////////////////////////////////////////////////////////////////////
  232. DEF_GM(return new TextBlobLooperGM;)
  233. }
  234. #endif