lattice.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*
  2. * Copyright 2016 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/SkBitmap.h"
  9. #include "include/core/SkBlendMode.h"
  10. #include "include/core/SkCanvas.h"
  11. #include "include/core/SkColor.h"
  12. #include "include/core/SkImage.h"
  13. #include "include/core/SkImageInfo.h"
  14. #include "include/core/SkPaint.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/SkSurface.h"
  21. #include "include/private/SkMalloc.h"
  22. #include "tools/ToolUtils.h"
  23. static sk_sp<SkSurface> make_surface(SkCanvas* root, int N, int padLeft, int padTop,
  24. int padRight, int padBottom) {
  25. SkImageInfo info = SkImageInfo::MakeN32Premul(N + padLeft + padRight, N + padTop + padBottom);
  26. return ToolUtils::makeSurface(root, info);
  27. }
  28. static sk_sp<SkImage> make_image(SkCanvas* root, int* xDivs, int* yDivs, int padLeft, int padTop,
  29. int padRight, int padBottom) {
  30. const int kCap = 28;
  31. const int kMid = 8;
  32. const int kSize = 2*kCap + 3*kMid;
  33. auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom));
  34. SkCanvas* canvas = surface->getCanvas();
  35. canvas->translate((float) padLeft, (float) padTop);
  36. SkRect r = SkRect::MakeWH(SkIntToScalar(kSize), SkIntToScalar(kSize));
  37. const SkScalar strokeWidth = SkIntToScalar(6);
  38. const SkScalar radius = SkIntToScalar(kCap) - strokeWidth/2;
  39. xDivs[0] = kCap + padLeft;
  40. yDivs[0] = kCap + padTop;
  41. xDivs[1] = kCap + kMid + padLeft;
  42. yDivs[1] = kCap + kMid + padTop;
  43. xDivs[2] = kCap + 2 * kMid + padLeft;
  44. yDivs[2] = kCap + 2 * kMid + padTop;
  45. xDivs[3] = kCap + 3 * kMid + padLeft;
  46. yDivs[3] = kCap + 3 * kMid + padTop;
  47. SkPaint paint;
  48. paint.setAntiAlias(true);
  49. paint.setColor(0xFFFFFF00);
  50. canvas->drawRoundRect(r, radius, radius, paint);
  51. r.setXYWH(SkIntToScalar(kCap), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
  52. paint.setColor(0x8800FF00);
  53. canvas->drawRect(r, paint);
  54. r.setXYWH(SkIntToScalar(kCap + kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
  55. paint.setColor(0x880000FF);
  56. canvas->drawRect(r, paint);
  57. r.setXYWH(SkIntToScalar(kCap + 2*kMid), 0, SkIntToScalar(kMid), SkIntToScalar(kSize));
  58. paint.setColor(0x88FF00FF);
  59. canvas->drawRect(r, paint);
  60. r.setXYWH(0, SkIntToScalar(kCap), SkIntToScalar(kSize), SkIntToScalar(kMid));
  61. paint.setColor(0x8800FF00);
  62. canvas->drawRect(r, paint);
  63. r.setXYWH(0, SkIntToScalar(kCap + kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
  64. paint.setColor(0x880000FF);
  65. canvas->drawRect(r, paint);
  66. r.setXYWH(0, SkIntToScalar(kCap + 2*kMid), SkIntToScalar(kSize), SkIntToScalar(kMid));
  67. paint.setColor(0x88FF00FF);
  68. canvas->drawRect(r, paint);
  69. return surface->makeImageSnapshot();
  70. }
  71. static void image_to_bitmap(const SkImage* image, SkBitmap* bm) {
  72. SkImageInfo info = SkImageInfo::MakeN32Premul(image->width(), image->height());
  73. bm->allocPixels(info);
  74. image->readPixels(info, bm->getPixels(), bm->rowBytes(), 0, 0);
  75. }
  76. /**
  77. * This is similar to NinePatchStretchGM, but it also tests "ninepatch" images with more
  78. * than nine patches.
  79. */
  80. class LatticeGM : public skiagm::GM {
  81. public:
  82. LatticeGM() {}
  83. protected:
  84. SkString onShortName() override {
  85. return SkString("lattice");
  86. }
  87. SkISize onISize() override {
  88. return SkISize::Make(800, 800);
  89. }
  90. void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom) {
  91. canvas->save();
  92. int xDivs[5];
  93. int yDivs[5];
  94. xDivs[0] = padLeft;
  95. yDivs[0] = padTop;
  96. SkBitmap bitmap;
  97. sk_sp<SkImage> image = make_image(canvas, xDivs + 1, yDivs + 1, padLeft, padTop,
  98. padRight, padBottom);
  99. image_to_bitmap(image.get(), &bitmap);
  100. const SkSize size[] = {
  101. { 50, 50, }, // shrink in both axes
  102. { 50, 200, }, // shrink in X
  103. { 200, 50, }, // shrink in Y
  104. { 200, 200, },
  105. };
  106. canvas->drawImage(image, 10, 10, nullptr);
  107. SkScalar x = SkIntToScalar(100);
  108. SkScalar y = SkIntToScalar(100);
  109. SkCanvas::Lattice lattice;
  110. lattice.fXCount = 4;
  111. lattice.fXDivs = xDivs + 1;
  112. lattice.fYCount = 4;
  113. lattice.fYDivs = yDivs + 1;
  114. lattice.fRectTypes = nullptr;
  115. lattice.fColors = nullptr;
  116. SkIRect bounds = SkIRect::MakeLTRB(padLeft, padTop,
  117. image->width() - padRight, image->height() - padBottom);
  118. lattice.fBounds = (bounds == SkIRect::MakeWH(image->width(), image->height())) ?
  119. nullptr : &bounds;
  120. for (int iy = 0; iy < 2; ++iy) {
  121. for (int ix = 0; ix < 2; ++ix) {
  122. int i = ix * 2 + iy;
  123. SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
  124. size[i].width(), size[i].height());
  125. canvas->drawBitmapLattice(bitmap, lattice, r);
  126. }
  127. }
  128. // Provide hints about 3 solid color rects. These colors match
  129. // what was already in the bitmap.
  130. int fixedColorX[3] = {2, 4, 1};
  131. int fixedColorY[3] = {1, 1, 2};
  132. SkColor fixedColor[3] = {SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK};
  133. const SkImageInfo info = SkImageInfo::Make(1, 1, kBGRA_8888_SkColorType,
  134. kUnpremul_SkAlphaType);
  135. for (int rectNum = 0; rectNum < 3; rectNum++) {
  136. int srcX = xDivs[fixedColorX[rectNum]-1];
  137. int srcY = yDivs[fixedColorY[rectNum]-1];
  138. image->readPixels(info, &fixedColor[rectNum], 4, srcX, srcY);
  139. }
  140. // Include the degenerate first div. While normally the first patch is "scalable",
  141. // this will mean that the first non-degenerate patch is "fixed".
  142. lattice.fXCount = 5;
  143. lattice.fXDivs = xDivs;
  144. lattice.fYCount = 5;
  145. lattice.fYDivs = yDivs;
  146. // Let's skip a few rects.
  147. SkCanvas::Lattice::RectType flags[36];
  148. sk_bzero(flags, 36 * sizeof(SkCanvas::Lattice::RectType));
  149. flags[4] = SkCanvas::Lattice::kTransparent;
  150. flags[9] = SkCanvas::Lattice::kTransparent;
  151. flags[12] = SkCanvas::Lattice::kTransparent;
  152. flags[19] = SkCanvas::Lattice::kTransparent;
  153. for (int rectNum = 0; rectNum < 3; rectNum++) {
  154. flags[fixedColorY[rectNum]*6 + fixedColorX[rectNum]]
  155. = SkCanvas::Lattice::kFixedColor;
  156. }
  157. lattice.fRectTypes = flags;
  158. SkColor colors[36];
  159. sk_bzero(colors, 36 * sizeof(SkColor));
  160. for (int rectNum = 0; rectNum < 3; rectNum++) {
  161. colors[fixedColorY[rectNum]*6 + fixedColorX[rectNum]]
  162. = fixedColor[rectNum];
  163. }
  164. lattice.fColors = colors;
  165. canvas->translate(400, 0);
  166. for (int iy = 0; iy < 2; ++iy) {
  167. for (int ix = 0; ix < 2; ++ix) {
  168. int i = ix * 2 + iy;
  169. SkRect r = SkRect::MakeXYWH(x + ix * 60, y + iy * 60,
  170. size[i].width(), size[i].height());
  171. canvas->drawImageLattice(image.get(), lattice, r);
  172. }
  173. }
  174. canvas->restore();
  175. }
  176. void onDraw(SkCanvas* canvas) override {
  177. this->onDrawHelper(canvas, 0, 0, 0, 0);
  178. canvas->translate(0.0f, 400.0f);
  179. this->onDrawHelper(canvas, 3, 7, 4, 11);
  180. }
  181. private:
  182. typedef skiagm::GM INHERITED;
  183. };
  184. DEF_GM( return new LatticeGM; )
  185. // LatticeGM2 exercises code paths that draw fixed color and 1x1 rectangles.
  186. class LatticeGM2 : public skiagm::GM {
  187. public:
  188. LatticeGM2() {}
  189. SkString onShortName() override {
  190. return SkString("lattice2");
  191. }
  192. SkISize onISize() override {
  193. return SkISize::Make(800, 800);
  194. }
  195. sk_sp<SkImage> makeImage(SkCanvas* root, int padLeft, int padTop, int padRight, int padBottom) {
  196. const int kSize = 80;
  197. auto surface(make_surface(root, kSize, padLeft, padTop, padRight, padBottom));
  198. SkCanvas* canvas = surface->getCanvas();
  199. SkPaint paint;
  200. paint.setAntiAlias(false);
  201. SkRect r;
  202. //first line
  203. r.setXYWH(0, 0, 4, 1); //4x1 green rect
  204. paint.setColor(0xFF00FF00);
  205. canvas->drawRect(r, paint);
  206. r.setXYWH(4, 0, 1, 1); //1x1 blue pixel -> draws as rectangle
  207. paint.setColor(0xFF0000FF);
  208. canvas->drawRect(r, paint);
  209. r.setXYWH(5, 0, kSize-5, 1); //the rest of the line is red
  210. paint.setColor(0xFFFF0000);
  211. canvas->drawRect(r, paint);
  212. //second line -> draws as fixed color rectangles
  213. r.setXYWH(0, 1, 4, 1); //4x1 red rect
  214. paint.setColor(0xFFFF0000);
  215. canvas->drawRect(r, paint);
  216. r.setXYWH(4, 1, 1, 1); //1x1 blue pixel with alpha
  217. paint.setColor(0x880000FF);
  218. canvas->drawRect(r, paint);
  219. r.setXYWH(5, 1, kSize-5, 1); //the rest of the line is green
  220. paint.setColor(0xFF00FF00);
  221. canvas->drawRect(r, paint);
  222. //third line - does not draw, because it is transparent
  223. r.setXYWH(0, 2, 4, kSize-2); //4x78 green rect
  224. paint.setColor(0xFF00FF00);
  225. canvas->drawRect(r, paint);
  226. r.setXYWH(4, 2, 1, kSize-2); //1x78 red pixel with alpha
  227. paint.setColor(0x88FF0000);
  228. canvas->drawRect(r, paint);
  229. r.setXYWH(5, 2, kSize-5, kSize-2); //the rest of the image is blue
  230. paint.setColor(0xFF0000FF);
  231. canvas->drawRect(r, paint);
  232. return surface->makeImageSnapshot();
  233. }
  234. void onDrawHelper(SkCanvas* canvas, int padLeft, int padTop, int padRight, int padBottom,
  235. SkPaint& paint) {
  236. int xDivs[2] = {4, 5};
  237. int yDivs[2] = {1, 2};
  238. canvas->save();
  239. sk_sp<SkImage> image = makeImage(canvas, padLeft, padTop, padRight, padBottom);
  240. canvas->drawImage(image, 10, 10, nullptr);
  241. SkCanvas::Lattice lattice;
  242. lattice.fXCount = 2;
  243. lattice.fXDivs = xDivs;
  244. lattice.fYCount = 2;
  245. lattice.fYDivs = yDivs;
  246. lattice.fBounds = nullptr;
  247. SkCanvas::Lattice::RectType flags[9];
  248. sk_bzero(flags, 9 * sizeof(SkCanvas::Lattice::RectType));
  249. flags[3] = SkCanvas::Lattice::kFixedColor;
  250. flags[4] = SkCanvas::Lattice::kFixedColor;
  251. flags[5] = SkCanvas::Lattice::kFixedColor;
  252. flags[6] = SkCanvas::Lattice::kTransparent;
  253. flags[7] = SkCanvas::Lattice::kTransparent;
  254. flags[8] = SkCanvas::Lattice::kTransparent;
  255. lattice.fRectTypes = flags;
  256. SkColor colors[9] = {SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK,
  257. 0xFFFF0000, 0x880000FF, 0xFF00FF00,
  258. SK_ColorBLACK, SK_ColorBLACK, SK_ColorBLACK};
  259. lattice.fColors = colors;
  260. paint.setColor(0xFFFFFFFF);
  261. canvas->drawImageLattice(image.get(), lattice,
  262. SkRect::MakeXYWH(100, 100, 200, 200), &paint);
  263. //draw the same content with alpha
  264. canvas->translate(400, 0);
  265. paint.setColor(0x80000FFF);
  266. canvas->drawImageLattice(image.get(), lattice,
  267. SkRect::MakeXYWH(100, 100, 200, 200), &paint);
  268. canvas->restore();
  269. }
  270. void onDraw(SkCanvas* canvas) override {
  271. //draw a rectangle in the background with transparent pixels
  272. SkPaint paint;
  273. paint.setColor(0x7F123456);
  274. paint.setBlendMode(SkBlendMode::kSrc);
  275. canvas->drawRect( SkRect::MakeXYWH(300, 0, 300, 800), paint);
  276. //draw image lattice with kSrcOver blending
  277. paint.setBlendMode(SkBlendMode::kSrcOver);
  278. this->onDrawHelper(canvas, 0, 0, 0, 0, paint);
  279. //draw image lattice with kSrcATop blending
  280. canvas->translate(0.0f, 400.0f);
  281. paint.setBlendMode(SkBlendMode::kSrcATop);
  282. this->onDrawHelper(canvas, 0, 0, 0, 0, paint);
  283. }
  284. private:
  285. typedef skiagm::GM INHERITED;
  286. };
  287. DEF_GM( return new LatticeGM2; )
  288. // Code paths that incorporate the paint color when drawing the lattice (using an alpha image)
  289. DEF_SIMPLE_GM_BG(lattice_alpha, canvas, 120, 120, SK_ColorWHITE) {
  290. auto surface = ToolUtils::makeSurface(canvas, SkImageInfo::MakeA8(100, 100));
  291. surface->getCanvas()->clear(0);
  292. surface->getCanvas()->drawCircle(50, 50, 50, SkPaint());
  293. auto image = surface->makeImageSnapshot();
  294. int divs[] = { 20, 40, 60, 80 };
  295. SkCanvas::Lattice lattice;
  296. lattice.fXCount = 4;
  297. lattice.fXDivs = divs;
  298. lattice.fYCount = 4;
  299. lattice.fYDivs = divs;
  300. lattice.fRectTypes = nullptr;
  301. lattice.fColors = nullptr;
  302. lattice.fBounds = nullptr;
  303. SkPaint paint;
  304. paint.setColor(SK_ColorMAGENTA);
  305. canvas->drawImageLattice(image.get(), lattice, SkRect::MakeWH(120, 120), &paint);
  306. }