drawatlas.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * Copyright 2015 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/SkCanvas.h"
  10. #include "include/core/SkColor.h"
  11. #include "include/core/SkColorFilter.h"
  12. #include "include/core/SkFilterQuality.h"
  13. #include "include/core/SkFont.h"
  14. #include "include/core/SkFontTypes.h"
  15. #include "include/core/SkImage.h"
  16. #include "include/core/SkImageInfo.h"
  17. #include "include/core/SkPaint.h"
  18. #include "include/core/SkPath.h"
  19. #include "include/core/SkPathMeasure.h"
  20. #include "include/core/SkPoint.h"
  21. #include "include/core/SkRSXform.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/SkSurface.h"
  29. #include "include/core/SkTextBlob.h"
  30. #include "include/core/SkTileMode.h"
  31. #include "include/core/SkTypeface.h"
  32. #include "include/core/SkTypes.h"
  33. #include "include/core/SkVertices.h"
  34. #include "include/effects/SkGradientShader.h"
  35. #include "include/private/SkTemplates.h"
  36. #include "src/core/SkAutoMalloc.h"
  37. #include "src/core/SkFontPriv.h"
  38. #include "tools/Resources.h"
  39. #include "tools/ToolUtils.h"
  40. #include <initializer_list>
  41. class DrawAtlasGM : public skiagm::GM {
  42. static sk_sp<SkImage> MakeAtlas(SkCanvas* caller, const SkRect& target) {
  43. SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
  44. auto surface(ToolUtils::makeSurface(caller, info));
  45. SkCanvas* canvas = surface->getCanvas();
  46. // draw red everywhere, but we don't expect to see it in the draw, testing the notion
  47. // that drawAtlas draws a subset-region of the atlas.
  48. canvas->clear(SK_ColorRED);
  49. SkPaint paint;
  50. paint.setBlendMode(SkBlendMode::kClear);
  51. SkRect r(target);
  52. r.inset(-1, -1);
  53. // zero out a place (with a 1-pixel border) to land our drawing.
  54. canvas->drawRect(r, paint);
  55. paint.setBlendMode(SkBlendMode::kSrcOver);
  56. paint.setColor(SK_ColorBLUE);
  57. paint.setAntiAlias(true);
  58. canvas->drawOval(target, paint);
  59. return surface->makeImageSnapshot();
  60. }
  61. public:
  62. DrawAtlasGM() {}
  63. protected:
  64. SkString onShortName() override {
  65. return SkString("draw-atlas");
  66. }
  67. SkISize onISize() override {
  68. return SkISize::Make(640, 480);
  69. }
  70. void onDraw(SkCanvas* canvas) override {
  71. const SkRect target = { 50, 50, 80, 90 };
  72. auto atlas = MakeAtlas(canvas, target);
  73. const struct {
  74. SkScalar fScale;
  75. SkScalar fDegrees;
  76. SkScalar fTx;
  77. SkScalar fTy;
  78. void apply(SkRSXform* xform) const {
  79. const SkScalar rad = SkDegreesToRadians(fDegrees);
  80. xform->fSCos = fScale * SkScalarCos(rad);
  81. xform->fSSin = fScale * SkScalarSin(rad);
  82. xform->fTx = fTx;
  83. xform->fTy = fTy;
  84. }
  85. } rec[] = {
  86. { 1, 0, 10, 10 }, // just translate
  87. { 2, 0, 110, 10 }, // scale + translate
  88. { 1, 30, 210, 10 }, // rotate + translate
  89. { 2, -30, 310, 30 }, // scale + rotate + translate
  90. };
  91. const int N = SK_ARRAY_COUNT(rec);
  92. SkRSXform xform[N];
  93. SkRect tex[N];
  94. SkColor colors[N];
  95. for (int i = 0; i < N; ++i) {
  96. rec[i].apply(&xform[i]);
  97. tex[i] = target;
  98. colors[i] = 0x80FF0000 + (i * 40 * 256);
  99. }
  100. SkPaint paint;
  101. paint.setFilterQuality(kLow_SkFilterQuality);
  102. paint.setAntiAlias(true);
  103. canvas->drawAtlas(atlas.get(), xform, tex, N, nullptr, &paint);
  104. canvas->translate(0, 100);
  105. canvas->drawAtlas(atlas.get(), xform, tex, colors, N, SkBlendMode::kSrcIn, nullptr, &paint);
  106. }
  107. private:
  108. typedef GM INHERITED;
  109. };
  110. DEF_GM( return new DrawAtlasGM; )
  111. ///////////////////////////////////////////////////////////////////////////////////////////////////
  112. static void draw_text_on_path(SkCanvas* canvas, const void* text, size_t length,
  113. const SkPoint xy[], const SkPath& path, const SkFont& font, const SkPaint& paint,
  114. float baseline_offset) {
  115. SkPathMeasure meas(path, false);
  116. int count = font.countText(text, length, SkTextEncoding::kUTF8);
  117. size_t size = count * (sizeof(SkRSXform) + sizeof(SkScalar));
  118. SkAutoSMalloc<512> storage(size);
  119. SkRSXform* xform = (SkRSXform*)storage.get();
  120. SkScalar* widths = (SkScalar*)(xform + count);
  121. // Compute a conservative bounds so we can cull the draw
  122. const SkRect fontb = SkFontPriv::GetFontBounds(font);
  123. const SkScalar max = SkTMax(SkTMax(SkScalarAbs(fontb.fLeft), SkScalarAbs(fontb.fRight)),
  124. SkTMax(SkScalarAbs(fontb.fTop), SkScalarAbs(fontb.fBottom)));
  125. const SkRect bounds = path.getBounds().makeOutset(max, max);
  126. SkAutoTArray<SkGlyphID> glyphs(count);
  127. font.textToGlyphs(text, length, SkTextEncoding::kUTF8, glyphs.get(), count);
  128. font.getWidths(glyphs.get(), count, widths);
  129. for (int i = 0; i < count; ++i) {
  130. // we want to position each character on the center of its advance
  131. const SkScalar offset = SkScalarHalf(widths[i]);
  132. SkPoint pos;
  133. SkVector tan;
  134. if (!meas.getPosTan(xy[i].x() + offset, &pos, &tan)) {
  135. pos = xy[i];
  136. tan.set(1, 0);
  137. }
  138. pos += SkVector::Make(-tan.fY, tan.fX) * baseline_offset;
  139. xform[i].fSCos = tan.x();
  140. xform[i].fSSin = tan.y();
  141. xform[i].fTx = pos.x() - tan.y() * xy[i].y() - tan.x() * offset;
  142. xform[i].fTy = pos.y() + tan.x() * xy[i].y() - tan.y() * offset;
  143. }
  144. canvas->drawTextBlob(SkTextBlob::MakeFromRSXform(glyphs.get(), count * sizeof(SkGlyphID),
  145. &xform[0], font, SkTextEncoding::kGlyphID),
  146. 0, 0, paint);
  147. if (true) {
  148. SkPaint p;
  149. p.setStyle(SkPaint::kStroke_Style);
  150. canvas->drawRect(bounds, p);
  151. }
  152. }
  153. static sk_sp<SkShader> make_shader() {
  154. SkPoint pts[2] = {{0, 0}, {220, 0}};
  155. SkColor colors[2] = {SK_ColorRED, SK_ColorBLUE};
  156. return SkGradientShader::MakeLinear(pts, colors, nullptr, 2, SkTileMode::kMirror);
  157. }
  158. static void drawTextPath(SkCanvas* canvas, bool doStroke) {
  159. const char text0[] = "ABCDFGHJKLMNOPQRSTUVWXYZ";
  160. const int N = sizeof(text0) - 1;
  161. SkPoint pos[N];
  162. SkFont font;
  163. font.setSize(100);
  164. SkPaint paint;
  165. paint.setShader(make_shader());
  166. paint.setAntiAlias(true);
  167. if (doStroke) {
  168. paint.setStyle(SkPaint::kStroke_Style);
  169. paint.setStrokeWidth(2.25f);
  170. paint.setStrokeJoin(SkPaint::kRound_Join);
  171. }
  172. SkScalar x = 0;
  173. for (int i = 0; i < N; ++i) {
  174. pos[i].set(x, 0);
  175. x += font.measureText(&text0[i], 1, SkTextEncoding::kUTF8, nullptr, &paint);
  176. }
  177. SkPath path;
  178. const float baseline_offset = -5;
  179. const SkPath::Direction dirs[] = {
  180. SkPath::kCW_Direction, SkPath::kCCW_Direction,
  181. };
  182. for (auto d : dirs) {
  183. path.reset();
  184. path.addOval(SkRect::MakeXYWH(160, 160, 540, 540), d);
  185. draw_text_on_path(canvas, text0, N, pos, path, font, paint, baseline_offset);
  186. }
  187. paint.reset();
  188. paint.setStyle(SkPaint::kStroke_Style);
  189. canvas->drawPath(path, paint);
  190. }
  191. DEF_SIMPLE_GM(drawTextRSXform, canvas, 430, 860) {
  192. canvas->scale(0.5f, 0.5f);
  193. const bool doStroke[] = { false, true };
  194. for (auto st : doStroke) {
  195. drawTextPath(canvas, st);
  196. canvas->translate(0, 860);
  197. }
  198. }
  199. // Exercise xform blob and its bounds
  200. DEF_SIMPLE_GM(blob_rsxform, canvas, 500, 100) {
  201. SkFont font;
  202. font.setTypeface(ToolUtils::create_portable_typeface());
  203. font.setSize(50);
  204. const char text[] = "CrazyXform";
  205. constexpr size_t len = sizeof(text) - 1;
  206. SkRSXform xforms[len];
  207. SkScalar scale = 1;
  208. SkScalar x = 0, y = 0;
  209. for (size_t i = 0; i < len; ++i) {
  210. scale = SkScalarSin(i * SK_ScalarPI / (len-1)) * 0.75f + 0.5f;
  211. xforms[i] = SkRSXform::Make(scale, 0, x, y);
  212. x += 50 * scale;
  213. }
  214. auto blob = SkTextBlob::MakeFromRSXform(text, len, xforms, font);
  215. SkPoint offset = { 20, 70 };
  216. SkPaint paint;
  217. paint.setColor(0xFFCCCCCC);
  218. canvas->drawRect(blob->bounds().makeOffset(offset.fX, offset.fY), paint);
  219. paint.setColor(SK_ColorBLACK);
  220. canvas->drawTextBlob(blob, offset.fX, offset.fY, paint);
  221. }
  222. static sk_sp<SkVertices> make_vertices(sk_sp<SkImage> image, const SkRect& r,
  223. SkColor color) {
  224. SkPoint pos[4];
  225. r.toQuad(pos);
  226. SkColor colors[4] = { color, color, color, color };
  227. return SkVertices::MakeCopy(SkVertices::kTriangleFan_VertexMode, 4,
  228. pos, pos, colors);
  229. }
  230. /*
  231. * drawAtlas and drawVertices have several things in common:
  232. * - can create compound "shaders", combining texture and colors
  233. * - these are combined via an explicit blendmode
  234. * - like drawImage, they only respect parts of the paint
  235. * - colorfilter, imagefilter, blendmode, alpha
  236. *
  237. * This GM produces a series of pairs of images (atlas | vertices).
  238. * Each pair should look the same, and each set shows a different combination
  239. * of alpha | colorFilter | mode
  240. */
  241. DEF_SIMPLE_GM(compare_atlas_vertices, canvas, 560, 585) {
  242. const SkRect tex = SkRect::MakeWH(128, 128);
  243. const SkRSXform xform = SkRSXform::Make(1, 0, 0, 0);
  244. const SkColor color = 0x884488CC;
  245. auto image = GetResourceAsImage("images/mandrill_128.png");
  246. auto verts = make_vertices(image, tex, color);
  247. const sk_sp<SkColorFilter> filters[] = {
  248. nullptr,
  249. SkColorFilters::Blend(0xFF00FF88, SkBlendMode::kModulate),
  250. };
  251. const SkBlendMode modes[] = {
  252. SkBlendMode::kSrcOver,
  253. SkBlendMode::kPlus,
  254. };
  255. canvas->translate(10, 10);
  256. SkPaint paint;
  257. for (SkBlendMode mode : modes) {
  258. for (float alpha : { 1.0f, 0.5f }) {
  259. paint.setAlphaf(alpha);
  260. canvas->save();
  261. for (auto cf : filters) {
  262. paint.setColorFilter(cf);
  263. canvas->drawAtlas(image, &xform, &tex, &color, 1,
  264. mode, &tex, &paint);
  265. canvas->translate(128, 0);
  266. paint.setShader(image->makeShader());
  267. canvas->drawVertices(verts, mode, paint);
  268. paint.setShader(nullptr);
  269. canvas->translate(145, 0);
  270. }
  271. canvas->restore();
  272. canvas->translate(0, 145);
  273. }
  274. }
  275. }