CanvasStateTest.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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 "include/core/SkBitmap.h"
  8. #include "include/core/SkCanvas.h"
  9. #include "include/core/SkColor.h"
  10. #include "include/core/SkImageInfo.h"
  11. #include "include/core/SkPaint.h"
  12. #include "include/core/SkRRect.h"
  13. #include "include/core/SkRect.h"
  14. #include "include/core/SkRegion.h"
  15. #include "include/core/SkScalar.h"
  16. #include "include/core/SkTypes.h"
  17. #include "include/private/SkTDArray.h"
  18. #include "include/utils/SkCanvasStateUtils.h"
  19. #include "src/core/SkCanvasPriv.h"
  20. #include "src/core/SkClipOpPriv.h"
  21. #include "src/core/SkTLazy.h"
  22. #include "tests/CanvasStateHelpers.h"
  23. #include "tests/Test.h"
  24. #include "tools/flags/CommandLineFlags.h"
  25. #include <cstring>
  26. class SkCanvasState;
  27. // dlopen and the library flag are only used for tests which require this flag.
  28. #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
  29. #include <dlfcn.h>
  30. static DEFINE_string(library, "",
  31. "Support library to use for CanvasState test. If empty (the default), "
  32. "the test will be run without crossing a library boundary. Otherwise, "
  33. "it is expected to be a full path to a shared library file, which will"
  34. " be dynamically loaded. Functions from the library will be called to "
  35. "test SkCanvasState. Instructions for generating the library are in "
  36. "gyp/canvas_state_lib.gyp");
  37. // This class calls dlopen on the library passed in to the command line flag library, and handles
  38. // calling dlclose when it goes out of scope.
  39. class OpenLibResult {
  40. public:
  41. // If the flag library was passed to this run of the test, attempt to open it using dlopen and
  42. // report whether it succeeded.
  43. OpenLibResult(skiatest::Reporter* reporter) {
  44. if (FLAGS_library.count() == 1) {
  45. fHandle = dlopen(FLAGS_library[0], RTLD_LAZY | RTLD_LOCAL);
  46. REPORTER_ASSERT(reporter, fHandle != nullptr, "Failed to open library!");
  47. } else {
  48. fHandle = nullptr;
  49. }
  50. }
  51. // Automatically call dlclose when going out of scope.
  52. ~OpenLibResult() {
  53. if (fHandle) {
  54. dlclose(fHandle);
  55. }
  56. }
  57. // Pointer to the shared library object.
  58. void* handle() { return fHandle; }
  59. private:
  60. void* fHandle;
  61. };
  62. DEF_TEST(CanvasState_test_complex_layers, reporter) {
  63. const int WIDTH = 400;
  64. const int HEIGHT = 400;
  65. const int SPACER = 10;
  66. SkRect rect = SkRect::MakeXYWH(SkIntToScalar(SPACER), SkIntToScalar(SPACER),
  67. SkIntToScalar(WIDTH-(2*SPACER)),
  68. SkIntToScalar((HEIGHT-(2*SPACER)) / 7));
  69. const SkColorType colorTypes[] = {
  70. kRGB_565_SkColorType, kN32_SkColorType
  71. };
  72. const int layerAlpha[] = { 255, 255, 0 };
  73. const SkCanvas::SaveLayerFlags flags[] = {
  74. static_cast<SkCanvas::SaveLayerFlags>(SkCanvasPriv::kDontClipToLayer_SaveLayerFlag),
  75. 0,
  76. static_cast<SkCanvas::SaveLayerFlags>(SkCanvasPriv::kDontClipToLayer_SaveLayerFlag),
  77. };
  78. REPORTER_ASSERT(reporter, sizeof(layerAlpha) == sizeof(flags));
  79. bool (*drawFn)(SkCanvasState* state, float l, float t,
  80. float r, float b, int32_t s);
  81. OpenLibResult openLibResult(reporter);
  82. if (openLibResult.handle() != nullptr) {
  83. *(void**) (&drawFn) = dlsym(openLibResult.handle(),
  84. "complex_layers_draw_from_canvas_state");
  85. } else {
  86. drawFn = complex_layers_draw_from_canvas_state;
  87. }
  88. REPORTER_ASSERT(reporter, drawFn);
  89. if (!drawFn) {
  90. return;
  91. }
  92. for (size_t i = 0; i < SK_ARRAY_COUNT(colorTypes); ++i) {
  93. SkBitmap bitmaps[2];
  94. for (int j = 0; j < 2; ++j) {
  95. bitmaps[j].allocPixels(SkImageInfo::Make(WIDTH, HEIGHT,
  96. colorTypes[i],
  97. kPremul_SkAlphaType));
  98. SkCanvas canvas(bitmaps[j]);
  99. canvas.drawColor(SK_ColorRED);
  100. for (size_t k = 0; k < SK_ARRAY_COUNT(layerAlpha); ++k) {
  101. SkTLazy<SkPaint> paint;
  102. if (layerAlpha[k] != 0xFF) {
  103. paint.init()->setAlpha(layerAlpha[k]);
  104. }
  105. // draw a rect within the layer's bounds and again outside the layer's bounds
  106. canvas.saveLayer(SkCanvas::SaveLayerRec(&rect, paint.getMaybeNull(), flags[k]));
  107. if (j) {
  108. // Capture from the first Skia.
  109. SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
  110. REPORTER_ASSERT(reporter, state);
  111. // And draw to it in the second Skia.
  112. bool success = complex_layers_draw_from_canvas_state(state,
  113. rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, SPACER);
  114. REPORTER_ASSERT(reporter, success);
  115. // And release it in the *first* Skia.
  116. SkCanvasStateUtils::ReleaseCanvasState(state);
  117. } else {
  118. // Draw in the first Skia.
  119. complex_layers_draw(&canvas, rect.fLeft, rect.fTop,
  120. rect.fRight, rect.fBottom, SPACER);
  121. }
  122. canvas.restore();
  123. // translate the canvas for the next iteration
  124. canvas.translate(0, 2*(rect.height() + SPACER));
  125. }
  126. }
  127. // now we memcmp the two bitmaps
  128. REPORTER_ASSERT(reporter, bitmaps[0].computeByteSize() == bitmaps[1].computeByteSize());
  129. REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
  130. bitmaps[1].getPixels(),
  131. bitmaps[0].computeByteSize()));
  132. }
  133. }
  134. #endif
  135. ////////////////////////////////////////////////////////////////////////////////
  136. #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
  137. DEF_TEST(CanvasState_test_complex_clips, reporter) {
  138. const int WIDTH = 400;
  139. const int HEIGHT = 400;
  140. const int SPACER = 10;
  141. SkIRect layerRect = SkIRect::MakeWH(WIDTH, HEIGHT / 4);
  142. layerRect.inset(2*SPACER, 2*SPACER);
  143. SkIRect clipRect = layerRect;
  144. clipRect.fRight = clipRect.fLeft + (clipRect.width() / 2) - (2*SPACER);
  145. clipRect.outset(SPACER, SPACER);
  146. SkIRect regionBounds = clipRect;
  147. regionBounds.offset(clipRect.width() + (2*SPACER), 0);
  148. SkIRect regionInterior = regionBounds;
  149. regionInterior.inset(SPACER*3, SPACER*3);
  150. SkRegion clipRegion;
  151. clipRegion.setRect(regionBounds);
  152. clipRegion.op(regionInterior, SkRegion::kDifference_Op);
  153. const SkRegion::Op clipOps[] = { SkRegion::kIntersect_Op,
  154. SkRegion::kIntersect_Op,
  155. SkRegion::kReplace_Op,
  156. };
  157. const SkCanvas::SaveLayerFlags flags[] = {
  158. static_cast<SkCanvas::SaveLayerFlags>(SkCanvasPriv::kDontClipToLayer_SaveLayerFlag),
  159. 0,
  160. static_cast<SkCanvas::SaveLayerFlags>(SkCanvasPriv::kDontClipToLayer_SaveLayerFlag),
  161. };
  162. REPORTER_ASSERT(reporter, sizeof(clipOps) == sizeof(flags));
  163. bool (*drawFn)(SkCanvasState* state, int32_t l, int32_t t,
  164. int32_t r, int32_t b, int32_t clipOp,
  165. int32_t regionRects, int32_t* rectCoords);
  166. OpenLibResult openLibResult(reporter);
  167. if (openLibResult.handle() != nullptr) {
  168. *(void**) (&drawFn) = dlsym(openLibResult.handle(),
  169. "complex_clips_draw_from_canvas_state");
  170. } else {
  171. drawFn = complex_clips_draw_from_canvas_state;
  172. }
  173. REPORTER_ASSERT(reporter, drawFn);
  174. if (!drawFn) {
  175. return;
  176. }
  177. SkBitmap bitmaps[2];
  178. for (int i = 0; i < 2; ++i) {
  179. bitmaps[i].allocN32Pixels(WIDTH, HEIGHT);
  180. SkCanvas canvas(bitmaps[i]);
  181. canvas.drawColor(SK_ColorRED);
  182. SkRegion localRegion = clipRegion;
  183. SkPaint paint;
  184. paint.setAlpha(128);
  185. for (size_t j = 0; j < SK_ARRAY_COUNT(flags); ++j) {
  186. SkRect layerBounds = SkRect::Make(layerRect);
  187. canvas.saveLayer(SkCanvas::SaveLayerRec(&layerBounds, &paint, flags[j]));
  188. if (i) {
  189. SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
  190. REPORTER_ASSERT(reporter, state);
  191. SkRegion::Iterator iter(localRegion);
  192. SkTDArray<int32_t> rectCoords;
  193. for (; !iter.done(); iter.next()) {
  194. const SkIRect& rect = iter.rect();
  195. *rectCoords.append() = rect.fLeft;
  196. *rectCoords.append() = rect.fTop;
  197. *rectCoords.append() = rect.fRight;
  198. *rectCoords.append() = rect.fBottom;
  199. }
  200. bool success = drawFn(state, clipRect.fLeft, clipRect.fTop,
  201. clipRect.fRight, clipRect.fBottom, clipOps[j],
  202. rectCoords.count() / 4, rectCoords.begin());
  203. REPORTER_ASSERT(reporter, success);
  204. SkCanvasStateUtils::ReleaseCanvasState(state);
  205. } else {
  206. complex_clips_draw(&canvas, clipRect.fLeft, clipRect.fTop,
  207. clipRect.fRight, clipRect.fBottom, clipOps[j],
  208. localRegion);
  209. }
  210. canvas.restore();
  211. // translate the canvas and region for the next iteration
  212. canvas.translate(0, SkIntToScalar(2*(layerRect.height() + (SPACER))));
  213. localRegion.translate(0, 2*(layerRect.height() + SPACER));
  214. }
  215. }
  216. // now we memcmp the two bitmaps
  217. REPORTER_ASSERT(reporter, bitmaps[0].computeByteSize() == bitmaps[1].computeByteSize());
  218. REPORTER_ASSERT(reporter, !memcmp(bitmaps[0].getPixels(),
  219. bitmaps[1].getPixels(),
  220. bitmaps[0].computeByteSize()));
  221. }
  222. #endif
  223. ////////////////////////////////////////////////////////////////////////////////
  224. DEF_TEST(CanvasState_test_soft_clips, reporter) {
  225. SkBitmap bitmap;
  226. bitmap.allocN32Pixels(10, 10);
  227. SkCanvas canvas(bitmap);
  228. SkRRect roundRect;
  229. roundRect.setOval(SkRect::MakeWH(5, 5));
  230. canvas.clipRRect(roundRect, kIntersect_SkClipOp, true);
  231. SkCanvasState* state = SkCanvasStateUtils::CaptureCanvasState(&canvas);
  232. REPORTER_ASSERT(reporter, !state);
  233. }
  234. DEF_TEST(CanvasState_test_saveLayer_clip, reporter) {
  235. #ifdef SK_SUPPORT_LEGACY_CLIPTOLAYERFLAG
  236. static_assert(SkCanvas::kDontClipToLayer_Legacy_SaveLayerFlag ==
  237. SkCanvasPriv::kDontClipToLayer_SaveLayerFlag, "");
  238. #endif
  239. const int WIDTH = 100;
  240. const int HEIGHT = 100;
  241. const int LAYER_WIDTH = 50;
  242. const int LAYER_HEIGHT = 50;
  243. SkBitmap bitmap;
  244. bitmap.allocN32Pixels(WIDTH, HEIGHT);
  245. SkCanvas canvas(bitmap);
  246. SkRect bounds = SkRect::MakeWH(SkIntToScalar(LAYER_WIDTH), SkIntToScalar(LAYER_HEIGHT));
  247. canvas.clipRect(SkRect::MakeWH(SkIntToScalar(WIDTH), SkIntToScalar(HEIGHT)));
  248. SkIRect devClip;
  249. // Check that saveLayer without the kClipToLayer_SaveFlag leaves the clip unchanged.
  250. canvas.saveLayer(SkCanvas::SaveLayerRec(&bounds, nullptr,
  251. (SkCanvas::SaveLayerFlags) SkCanvasPriv::kDontClipToLayer_SaveLayerFlag));
  252. devClip = canvas.getDeviceClipBounds();
  253. REPORTER_ASSERT(reporter, canvas.isClipRect());
  254. REPORTER_ASSERT(reporter, devClip.width() == WIDTH);
  255. REPORTER_ASSERT(reporter, devClip.height() == HEIGHT);
  256. canvas.restore();
  257. // Check that saveLayer with the kClipToLayer_SaveFlag sets the clip
  258. // stack to the layer bounds.
  259. canvas.saveLayer(&bounds, nullptr);
  260. devClip = canvas.getDeviceClipBounds();
  261. REPORTER_ASSERT(reporter, canvas.isClipRect());
  262. REPORTER_ASSERT(reporter, devClip.width() == LAYER_WIDTH);
  263. REPORTER_ASSERT(reporter, devClip.height() == LAYER_HEIGHT);
  264. canvas.restore();
  265. }