PageRenderTime 27ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/skia/ext/platform_canvas_unittest.cc

https://gitlab.com/0072016/Facebook-SDK-
C++ | 417 lines | 312 code | 52 blank | 53 comment | 20 complexity | 4b6425d090af1f9fc1bfa63d0a0af3cd MD5 | raw file
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. // TODO(awalker): clean up the const/non-const reference handling in this test
  5. #include "skia/ext/platform_canvas.h"
  6. #include <stdint.h>
  7. #include "base/logging.h"
  8. #include "base/memory/scoped_ptr.h"
  9. #include "build/build_config.h"
  10. #include "skia/ext/platform_device.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. #include "third_party/skia/include/core/SkBitmap.h"
  13. #include "third_party/skia/include/core/SkCanvas.h"
  14. #include "third_party/skia/include/core/SkColor.h"
  15. #include "third_party/skia/include/core/SkColorPriv.h"
  16. #include "third_party/skia/include/core/SkPixelRef.h"
  17. #if defined(OS_MACOSX)
  18. #import <ApplicationServices/ApplicationServices.h>
  19. #endif
  20. #if !defined(OS_WIN)
  21. #include <unistd.h>
  22. #endif
  23. namespace skia {
  24. namespace {
  25. #if defined(OS_WIN)
  26. void MakeOpaque(SkCanvas* canvas, int x, int y, int width, int height) {
  27. if (width <= 0 || height <= 0)
  28. return;
  29. SkRect rect;
  30. rect.setXYWH(SkIntToScalar(x), SkIntToScalar(y),
  31. SkIntToScalar(width), SkIntToScalar(height));
  32. SkPaint paint;
  33. paint.setColor(SK_ColorBLACK);
  34. paint.setXfermodeMode(SkXfermode::kDstATop_Mode);
  35. canvas->drawRect(rect, paint);
  36. }
  37. #endif
  38. bool IsOfColor(const SkBitmap& bitmap, int x, int y, uint32_t color) {
  39. // For masking out the alpha values.
  40. static uint32_t alpha_mask =
  41. static_cast<uint32_t>(SK_A32_MASK) << SK_A32_SHIFT;
  42. return (*bitmap.getAddr32(x, y) | alpha_mask) == (color | alpha_mask);
  43. }
  44. // Return true if the canvas is filled to canvas_color, and contains a single
  45. // rectangle filled to rect_color. This function ignores the alpha channel,
  46. // since Windows will sometimes clear the alpha channel when drawing, and we
  47. // will fix that up later in cases it's necessary.
  48. bool VerifyRect(const SkCanvas& canvas,
  49. uint32_t canvas_color, uint32_t rect_color,
  50. int x, int y, int w, int h) {
  51. const SkBitmap bitmap = skia::ReadPixels(const_cast<SkCanvas*>(&canvas));
  52. SkAutoLockPixels lock(bitmap);
  53. for (int cur_y = 0; cur_y < bitmap.height(); cur_y++) {
  54. for (int cur_x = 0; cur_x < bitmap.width(); cur_x++) {
  55. if (cur_x >= x && cur_x < x + w &&
  56. cur_y >= y && cur_y < y + h) {
  57. // Inside the square should be rect_color
  58. if (!IsOfColor(bitmap, cur_x, cur_y, rect_color))
  59. return false;
  60. } else {
  61. // Outside the square should be canvas_color
  62. if (!IsOfColor(bitmap, cur_x, cur_y, canvas_color))
  63. return false;
  64. }
  65. }
  66. }
  67. return true;
  68. }
  69. #if !defined(USE_AURA) && !defined(OS_MACOSX)
  70. // Return true if canvas has something that passes for a rounded-corner
  71. // rectangle. Basically, we're just checking to make sure that the pixels in the
  72. // middle are of rect_color and pixels in the corners are of canvas_color.
  73. bool VerifyRoundedRect(const SkCanvas& canvas,
  74. uint32_t canvas_color,
  75. uint32_t rect_color,
  76. int x,
  77. int y,
  78. int w,
  79. int h) {
  80. SkBaseDevice* device = skia::GetTopDevice(canvas);
  81. const SkBitmap& bitmap = device->accessBitmap(false);
  82. SkAutoLockPixels lock(bitmap);
  83. // Check corner points first. They should be of canvas_color.
  84. if (!IsOfColor(bitmap, x, y, canvas_color)) return false;
  85. if (!IsOfColor(bitmap, x + w, y, canvas_color)) return false;
  86. if (!IsOfColor(bitmap, x, y + h, canvas_color)) return false;
  87. if (!IsOfColor(bitmap, x + w, y, canvas_color)) return false;
  88. // Check middle points. They should be of rect_color.
  89. if (!IsOfColor(bitmap, (x + w / 2), y, rect_color)) return false;
  90. if (!IsOfColor(bitmap, x, (y + h / 2), rect_color)) return false;
  91. if (!IsOfColor(bitmap, x + w, (y + h / 2), rect_color)) return false;
  92. if (!IsOfColor(bitmap, (x + w / 2), y + h, rect_color)) return false;
  93. return true;
  94. }
  95. #endif
  96. // Checks whether there is a white canvas with a black square at the given
  97. // location in pixels (not in the canvas coordinate system).
  98. bool VerifyBlackRect(const SkCanvas& canvas, int x, int y, int w, int h) {
  99. return VerifyRect(canvas, SK_ColorWHITE, SK_ColorBLACK, x, y, w, h);
  100. }
  101. #if !defined(USE_AURA) // http://crbug.com/154358
  102. // Check that every pixel in the canvas is a single color.
  103. bool VerifyCanvasColor(const SkCanvas& canvas, uint32_t canvas_color) {
  104. return VerifyRect(canvas, canvas_color, 0, 0, 0, 0, 0);
  105. }
  106. #endif // !defined(USE_AURA)
  107. #if defined(OS_WIN)
  108. void DrawNativeRect(SkCanvas& canvas, int x, int y, int w, int h) {
  109. skia::ScopedPlatformPaint scoped_platform_paint(&canvas);
  110. HDC dc = scoped_platform_paint.GetPlatformSurface();
  111. RECT inner_rc;
  112. inner_rc.left = x;
  113. inner_rc.top = y;
  114. inner_rc.right = x + w;
  115. inner_rc.bottom = y + h;
  116. FillRect(dc, &inner_rc, reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)));
  117. }
  118. #elif defined(OS_MACOSX)
  119. void DrawNativeRect(SkCanvas& canvas, int x, int y, int w, int h) {
  120. skia::ScopedPlatformPaint scoped_platform_paint(&canvas);
  121. CGContextRef context = scoped_platform_paint.GetPlatformSurface();
  122. CGRect inner_rc = CGRectMake(x, y, w, h);
  123. // RGBA opaque black
  124. CGColorRef black = CGColorCreateGenericRGB(0.0, 0.0, 0.0, 1.0);
  125. CGContextSetFillColorWithColor(context, black);
  126. CGColorRelease(black);
  127. CGContextFillRect(context, inner_rc);
  128. }
  129. #else
  130. void DrawNativeRect(SkCanvas& canvas, int x, int y, int w, int h) {
  131. NOTIMPLEMENTED();
  132. }
  133. #endif
  134. // Clips the contents of the canvas to the given rectangle. This will be
  135. // intersected with any existing clip.
  136. void AddClip(SkCanvas& canvas, int x, int y, int w, int h) {
  137. SkRect rect;
  138. rect.set(SkIntToScalar(x), SkIntToScalar(y),
  139. SkIntToScalar(x + w), SkIntToScalar(y + h));
  140. canvas.clipRect(rect);
  141. }
  142. class LayerSaver {
  143. public:
  144. LayerSaver(SkCanvas& canvas, int x, int y, int w, int h)
  145. : canvas_(canvas),
  146. x_(x),
  147. y_(y),
  148. w_(w),
  149. h_(h) {
  150. SkRect bounds;
  151. bounds.set(SkIntToScalar(x_), SkIntToScalar(y_),
  152. SkIntToScalar(right()), SkIntToScalar(bottom()));
  153. canvas_.saveLayer(&bounds, NULL);
  154. canvas.clear(SkColorSetARGB(0, 0, 0, 0));
  155. }
  156. ~LayerSaver() {
  157. canvas_.restore();
  158. }
  159. int x() const { return x_; }
  160. int y() const { return y_; }
  161. int w() const { return w_; }
  162. int h() const { return h_; }
  163. // Returns the EXCLUSIVE far bounds of the layer.
  164. int right() const { return x_ + w_; }
  165. int bottom() const { return y_ + h_; }
  166. private:
  167. SkCanvas& canvas_;
  168. int x_, y_, w_, h_;
  169. };
  170. // Size used for making layers in many of the below tests.
  171. const int kLayerX = 2;
  172. const int kLayerY = 3;
  173. const int kLayerW = 9;
  174. const int kLayerH = 7;
  175. // Size used by some tests to draw a rectangle inside the layer.
  176. const int kInnerX = 4;
  177. const int kInnerY = 5;
  178. const int kInnerW = 2;
  179. const int kInnerH = 3;
  180. }
  181. // This just checks that our checking code is working properly, it just uses
  182. // regular skia primitives.
  183. TEST(PlatformCanvas, SkLayer) {
  184. // Create the canvas initialized to opaque white.
  185. sk_sp<SkCanvas> canvas(CreatePlatformCanvas(16, 16, true));
  186. canvas->drawColor(SK_ColorWHITE);
  187. // Make a layer and fill it completely to make sure that the bounds are
  188. // correct.
  189. {
  190. LayerSaver layer(*canvas, kLayerX, kLayerY, kLayerW, kLayerH);
  191. canvas->drawColor(SK_ColorBLACK);
  192. }
  193. EXPECT_TRUE(VerifyBlackRect(*canvas, kLayerX, kLayerY, kLayerW, kLayerH));
  194. }
  195. #if !defined(USE_AURA) // http://crbug.com/154358
  196. // Test native clipping.
  197. TEST(PlatformCanvas, ClipRegion) {
  198. // Initialize a white canvas
  199. sk_sp<SkCanvas> canvas(CreatePlatformCanvas(16, 16, true));
  200. canvas->drawColor(SK_ColorWHITE);
  201. EXPECT_TRUE(VerifyCanvasColor(*canvas, SK_ColorWHITE));
  202. // Test that initially the canvas has no clip region, by filling it
  203. // with a black rectangle.
  204. // Note: Don't use LayerSaver, since internally it sets a clip region.
  205. DrawNativeRect(*canvas, 0, 0, 16, 16);
  206. EXPECT_TRUE(VerifyCanvasColor(*canvas, SK_ColorBLACK));
  207. // Test that intersecting disjoint clip rectangles sets an empty clip region
  208. canvas->drawColor(SK_ColorWHITE);
  209. EXPECT_TRUE(VerifyCanvasColor(*canvas, SK_ColorWHITE));
  210. {
  211. LayerSaver layer(*canvas, 0, 0, 16, 16);
  212. AddClip(*canvas, 2, 3, 4, 5);
  213. AddClip(*canvas, 4, 9, 10, 10);
  214. DrawNativeRect(*canvas, 0, 0, 16, 16);
  215. }
  216. EXPECT_TRUE(VerifyCanvasColor(*canvas, SK_ColorWHITE));
  217. }
  218. #endif // !defined(USE_AURA)
  219. // Test the layers get filled properly by native rendering.
  220. TEST(PlatformCanvas, FillLayer) {
  221. // Create the canvas initialized to opaque white.
  222. sk_sp<SkCanvas> canvas(CreatePlatformCanvas(16, 16, true));
  223. // Make a layer and fill it completely to make sure that the bounds are
  224. // correct.
  225. canvas->drawColor(SK_ColorWHITE);
  226. {
  227. LayerSaver layer(*canvas, kLayerX, kLayerY, kLayerW, kLayerH);
  228. DrawNativeRect(*canvas, 0, 0, 100, 100);
  229. #if defined(OS_WIN)
  230. MakeOpaque(canvas.get(), 0, 0, 100, 100);
  231. #endif
  232. }
  233. EXPECT_TRUE(VerifyBlackRect(*canvas, kLayerX, kLayerY, kLayerW, kLayerH));
  234. // Make a layer and fill it partially to make sure the translation is correct.
  235. canvas->drawColor(SK_ColorWHITE);
  236. {
  237. LayerSaver layer(*canvas, kLayerX, kLayerY, kLayerW, kLayerH);
  238. DrawNativeRect(*canvas, kInnerX, kInnerY, kInnerW, kInnerH);
  239. #if defined(OS_WIN)
  240. MakeOpaque(canvas.get(), kInnerX, kInnerY, kInnerW, kInnerH);
  241. #endif
  242. }
  243. EXPECT_TRUE(VerifyBlackRect(*canvas, kInnerX, kInnerY, kInnerW, kInnerH));
  244. // Add a clip on the layer and fill to make sure clip is correct.
  245. canvas->drawColor(SK_ColorWHITE);
  246. {
  247. LayerSaver layer(*canvas, kLayerX, kLayerY, kLayerW, kLayerH);
  248. canvas->save();
  249. AddClip(*canvas, kInnerX, kInnerY, kInnerW, kInnerH);
  250. DrawNativeRect(*canvas, 0, 0, 100, 100);
  251. #if defined(OS_WIN)
  252. MakeOpaque(canvas.get(), kInnerX, kInnerY, kInnerW, kInnerH);
  253. #endif
  254. canvas->restore();
  255. }
  256. EXPECT_TRUE(VerifyBlackRect(*canvas, kInnerX, kInnerY, kInnerW, kInnerH));
  257. // Add a clip and then make the layer to make sure the clip is correct.
  258. canvas->drawColor(SK_ColorWHITE);
  259. canvas->save();
  260. AddClip(*canvas, kInnerX, kInnerY, kInnerW, kInnerH);
  261. {
  262. LayerSaver layer(*canvas, kLayerX, kLayerY, kLayerW, kLayerH);
  263. DrawNativeRect(*canvas, 0, 0, 100, 100);
  264. #if defined(OS_WIN)
  265. MakeOpaque(canvas.get(), 0, 0, 100, 100);
  266. #endif
  267. }
  268. canvas->restore();
  269. EXPECT_TRUE(VerifyBlackRect(*canvas, kInnerX, kInnerY, kInnerW, kInnerH));
  270. }
  271. #if !defined(USE_AURA) // http://crbug.com/154358
  272. // Test that translation + make layer works properly.
  273. TEST(PlatformCanvas, TranslateLayer) {
  274. // Create the canvas initialized to opaque white.
  275. sk_sp<SkCanvas> canvas(CreatePlatformCanvas(16, 16, true));
  276. // Make a layer and fill it completely to make sure that the bounds are
  277. // correct.
  278. canvas->drawColor(SK_ColorWHITE);
  279. canvas->save();
  280. canvas->translate(1, 1);
  281. {
  282. LayerSaver layer(*canvas, kLayerX, kLayerY, kLayerW, kLayerH);
  283. DrawNativeRect(*canvas, 0, 0, 100, 100);
  284. #if defined(OS_WIN)
  285. MakeOpaque(canvas.get(), 0, 0, 100, 100);
  286. #endif
  287. }
  288. canvas->restore();
  289. EXPECT_TRUE(VerifyBlackRect(*canvas, kLayerX + 1, kLayerY + 1,
  290. kLayerW, kLayerH));
  291. // Translate then make the layer.
  292. canvas->drawColor(SK_ColorWHITE);
  293. canvas->save();
  294. canvas->translate(1, 1);
  295. {
  296. LayerSaver layer(*canvas, kLayerX, kLayerY, kLayerW, kLayerH);
  297. DrawNativeRect(*canvas, kInnerX, kInnerY, kInnerW, kInnerH);
  298. #if defined(OS_WIN)
  299. MakeOpaque(canvas.get(), kInnerX, kInnerY, kInnerW, kInnerH);
  300. #endif
  301. }
  302. canvas->restore();
  303. EXPECT_TRUE(VerifyBlackRect(*canvas, kInnerX + 1, kInnerY + 1,
  304. kInnerW, kInnerH));
  305. // Make the layer then translate.
  306. canvas->drawColor(SK_ColorWHITE);
  307. canvas->save();
  308. {
  309. LayerSaver layer(*canvas, kLayerX, kLayerY, kLayerW, kLayerH);
  310. canvas->translate(1, 1);
  311. DrawNativeRect(*canvas, kInnerX, kInnerY, kInnerW, kInnerH);
  312. #if defined(OS_WIN)
  313. MakeOpaque(canvas.get(), kInnerX, kInnerY, kInnerW, kInnerH);
  314. #endif
  315. }
  316. canvas->restore();
  317. EXPECT_TRUE(VerifyBlackRect(*canvas, kInnerX + 1, kInnerY + 1,
  318. kInnerW, kInnerH));
  319. // Translate both before and after, and have a clip.
  320. canvas->drawColor(SK_ColorWHITE);
  321. canvas->save();
  322. canvas->translate(1, 1);
  323. {
  324. LayerSaver layer(*canvas, kLayerX, kLayerY, kLayerW, kLayerH);
  325. canvas->drawColor(SK_ColorWHITE);
  326. canvas->translate(1, 1);
  327. AddClip(*canvas, kInnerX + 1, kInnerY + 1, kInnerW - 1, kInnerH - 1);
  328. DrawNativeRect(*canvas, 0, 0, 100, 100);
  329. #if defined(OS_WIN)
  330. MakeOpaque(canvas.get(), kLayerX, kLayerY, kLayerW, kLayerH);
  331. #endif
  332. }
  333. canvas->restore();
  334. EXPECT_TRUE(VerifyBlackRect(*canvas, kInnerX + 3, kInnerY + 3,
  335. kInnerW - 1, kInnerH - 1));
  336. // TODO(dglazkov): Figure out why this fails on Mac (antialiased clipping?),
  337. // modify test and remove this guard.
  338. #if !defined(OS_MACOSX)
  339. // Translate both before and after, and have a path clip.
  340. canvas->drawColor(SK_ColorWHITE);
  341. canvas->save();
  342. canvas->translate(1, 1);
  343. {
  344. LayerSaver layer(*canvas, kLayerX, kLayerY, kLayerW, kLayerH);
  345. canvas->drawColor(SK_ColorWHITE);
  346. canvas->translate(1, 1);
  347. SkPath path;
  348. SkRect rect;
  349. rect.iset(kInnerX - 1, kInnerY - 1,
  350. kInnerX + kInnerW, kInnerY + kInnerH);
  351. const SkScalar kRadius = 2.0;
  352. path.addRoundRect(rect, kRadius, kRadius);
  353. canvas->clipPath(path);
  354. DrawNativeRect(*canvas, 0, 0, 100, 100);
  355. #if defined(OS_WIN)
  356. MakeOpaque(canvas.get(), kLayerX, kLayerY, kLayerW, kLayerH);
  357. #endif
  358. }
  359. canvas->restore();
  360. EXPECT_TRUE(VerifyRoundedRect(*canvas, SK_ColorWHITE, SK_ColorBLACK,
  361. kInnerX + 1, kInnerY + 1, kInnerW, kInnerH));
  362. #endif
  363. }
  364. #endif // #if !defined(USE_AURA)
  365. } // namespace skia