paint_vector_icon_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // Copyright 2017 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. #include "ui/gfx/paint_vector_icon.h"
  5. #include <gtest/gtest.h>
  6. #include <vector>
  7. #include "base/i18n/rtl.h"
  8. #include "cc/paint/paint_record.h"
  9. #include "cc/paint/paint_recorder.h"
  10. #include "third_party/skia/include/core/SkCanvas.h"
  11. #include "third_party/skia/include/core/SkPath.h"
  12. #include "ui/gfx/canvas.h"
  13. #include "ui/gfx/vector_icon_types.h"
  14. namespace gfx {
  15. namespace {
  16. SkColor GetColorAtTopLeft(const Canvas& canvas) {
  17. return canvas.GetBitmap().getColor(0, 0);
  18. }
  19. class MockCanvas : public SkCanvas {
  20. public:
  21. MockCanvas(int width, int height) : SkCanvas(width, height) {}
  22. MockCanvas(const MockCanvas&) = delete;
  23. MockCanvas& operator=(const MockCanvas&) = delete;
  24. // SkCanvas overrides:
  25. void onDrawPath(const SkPath& path, const SkPaint& paint) override {
  26. paths_.push_back(path);
  27. }
  28. const std::vector<SkPath>& paths() const { return paths_; }
  29. private:
  30. std::vector<SkPath> paths_;
  31. };
  32. // Tests that a relative move to command (R_MOVE_TO) after a close command
  33. // (CLOSE) uses the correct starting point. See crbug.com/697497
  34. TEST(VectorIconTest, RelativeMoveToAfterClose) {
  35. cc::PaintRecorder recorder;
  36. Canvas canvas(recorder.beginRecording(100, 100), 1.0f);
  37. const PathElement elements[] = {
  38. MOVE_TO, 4, 5, LINE_TO, 10, 11, CLOSE,
  39. // This move should use (4, 5) as the start point rather than (10, 11).
  40. R_MOVE_TO, 20, 21, R_LINE_TO, 50, 51};
  41. const VectorIconRep rep_list[] = {{elements, std::size(elements)}};
  42. const VectorIcon icon(rep_list, 1u, nullptr);
  43. PaintVectorIcon(&canvas, icon, 100, SK_ColorMAGENTA);
  44. sk_sp<cc::PaintRecord> record = recorder.finishRecordingAsPicture();
  45. MockCanvas mock(100, 100);
  46. record->Playback(&mock);
  47. ASSERT_EQ(1U, mock.paths().size());
  48. SkPoint last_point;
  49. EXPECT_TRUE(mock.paths()[0].getLastPt(&last_point));
  50. EXPECT_EQ(SkIntToScalar(74), last_point.x());
  51. EXPECT_EQ(SkIntToScalar(77), last_point.y());
  52. }
  53. TEST(VectorIconTest, FlipsInRtl) {
  54. // Set the locale to a rtl language otherwise FLIPS_IN_RTL will do nothing.
  55. base::i18n::SetICUDefaultLocale("he");
  56. ASSERT_TRUE(base::i18n::IsRTL());
  57. const int canvas_size = 20;
  58. const SkColor color = SK_ColorWHITE;
  59. Canvas canvas(gfx::Size(canvas_size, canvas_size), 1.0f, true);
  60. // Create a 20x20 square icon which has FLIPS_IN_RTL, and CANVAS_DIMENSIONS
  61. // are twice as large as |canvas|.
  62. const PathElement elements[] = {CANVAS_DIMENSIONS,
  63. 2 * canvas_size,
  64. FLIPS_IN_RTL,
  65. MOVE_TO,
  66. 10,
  67. 10,
  68. R_H_LINE_TO,
  69. 20,
  70. R_V_LINE_TO,
  71. 20,
  72. R_H_LINE_TO,
  73. -20,
  74. CLOSE};
  75. const VectorIconRep rep_list[] = {{elements, std::size(elements)}};
  76. const VectorIcon icon(rep_list, 1u, nullptr);
  77. PaintVectorIcon(&canvas, icon, canvas_size, color);
  78. // Count the number of pixels in the canvas.
  79. auto bitmap = canvas.GetBitmap();
  80. int colored_pixel_count = 0;
  81. for (int i = 0; i < bitmap.width(); ++i) {
  82. for (int j = 0; j < bitmap.height(); ++j) {
  83. if (bitmap.getColor(i, j) == color)
  84. colored_pixel_count++;
  85. }
  86. }
  87. // Verify that the amount of colored pixels on the canvas bitmap should be a
  88. // quarter of the original icon, since each side should be scaled down by a
  89. // factor of two.
  90. EXPECT_EQ(100, colored_pixel_count);
  91. }
  92. TEST(VectorIconTest, CorrectSizePainted) {
  93. // Create a set of 5 icons reps, sized {48, 32, 24, 20, 16} for the test icon.
  94. // Color each of them differently so they can be differentiated (the parts of
  95. // an icon painted with PATH_COLOR_ARGB will not be overwritten by the color
  96. // provided to it at creation time).
  97. const SkColor kPath48Color = SK_ColorRED;
  98. const PathElement elements48[] = {CANVAS_DIMENSIONS,
  99. 48,
  100. PATH_COLOR_ARGB,
  101. 0xFF,
  102. SkColorGetR(kPath48Color),
  103. SkColorGetG(kPath48Color),
  104. SkColorGetB(kPath48Color),
  105. MOVE_TO,
  106. 0,
  107. 0,
  108. H_LINE_TO,
  109. 48,
  110. V_LINE_TO,
  111. 48,
  112. H_LINE_TO,
  113. 0,
  114. V_LINE_TO,
  115. 0,
  116. CLOSE};
  117. const SkColor kPath32Color = SK_ColorGREEN;
  118. const PathElement elements32[] = {CANVAS_DIMENSIONS,
  119. 32,
  120. PATH_COLOR_ARGB,
  121. 0xFF,
  122. SkColorGetR(kPath32Color),
  123. SkColorGetG(kPath32Color),
  124. SkColorGetB(kPath32Color),
  125. MOVE_TO,
  126. 0,
  127. 0,
  128. H_LINE_TO,
  129. 32,
  130. V_LINE_TO,
  131. 32,
  132. H_LINE_TO,
  133. 0,
  134. V_LINE_TO,
  135. 0,
  136. CLOSE};
  137. const SkColor kPath24Color = SK_ColorBLUE;
  138. const PathElement elements24[] = {CANVAS_DIMENSIONS,
  139. 24,
  140. PATH_COLOR_ARGB,
  141. 0xFF,
  142. SkColorGetR(kPath24Color),
  143. SkColorGetG(kPath24Color),
  144. SkColorGetB(kPath24Color),
  145. MOVE_TO,
  146. 0,
  147. 0,
  148. H_LINE_TO,
  149. 24,
  150. V_LINE_TO,
  151. 24,
  152. H_LINE_TO,
  153. 0,
  154. V_LINE_TO,
  155. 0,
  156. CLOSE};
  157. const SkColor kPath20Color = SK_ColorYELLOW;
  158. const PathElement elements20[] = {CANVAS_DIMENSIONS,
  159. 20,
  160. PATH_COLOR_ARGB,
  161. 0xFF,
  162. SkColorGetR(kPath20Color),
  163. SkColorGetG(kPath20Color),
  164. SkColorGetB(kPath20Color),
  165. MOVE_TO,
  166. 0,
  167. 0,
  168. H_LINE_TO,
  169. 20,
  170. V_LINE_TO,
  171. 20,
  172. H_LINE_TO,
  173. 0,
  174. V_LINE_TO,
  175. 0,
  176. CLOSE};
  177. const SkColor kPath16Color = SK_ColorCYAN;
  178. const PathElement elements16[] = {CANVAS_DIMENSIONS,
  179. 16,
  180. PATH_COLOR_ARGB,
  181. 0xFF,
  182. SkColorGetR(kPath16Color),
  183. SkColorGetG(kPath16Color),
  184. SkColorGetB(kPath16Color),
  185. MOVE_TO,
  186. 0,
  187. 0,
  188. H_LINE_TO,
  189. 16,
  190. V_LINE_TO,
  191. 16,
  192. H_LINE_TO,
  193. 0,
  194. V_LINE_TO,
  195. 0,
  196. CLOSE};
  197. // VectorIconReps are always sorted in descending order of size.
  198. const VectorIconRep rep_list[] = {{elements48, std::size(elements48)},
  199. {elements32, std::size(elements32)},
  200. {elements24, std::size(elements24)},
  201. {elements20, std::size(elements20)},
  202. {elements16, std::size(elements16)}};
  203. const VectorIcon icon(rep_list, 5u, nullptr);
  204. // Test exact sizes paint the correctly sized icon, including the largest and
  205. // smallest icon.
  206. Canvas canvas_100(gfx::Size(100, 100), 1.0, true);
  207. PaintVectorIcon(&canvas_100, icon, 48, SK_ColorBLACK);
  208. EXPECT_EQ(kPath48Color, GetColorAtTopLeft(canvas_100));
  209. PaintVectorIcon(&canvas_100, icon, 32, SK_ColorBLACK);
  210. EXPECT_EQ(kPath32Color, GetColorAtTopLeft(canvas_100));
  211. PaintVectorIcon(&canvas_100, icon, 16, SK_ColorBLACK);
  212. EXPECT_EQ(kPath16Color, GetColorAtTopLeft(canvas_100));
  213. // The largest icon may be upscaled to a size larger than what it was
  214. // designed for.
  215. PaintVectorIcon(&canvas_100, icon, 50, SK_ColorBLACK);
  216. EXPECT_EQ(kPath48Color, GetColorAtTopLeft(canvas_100));
  217. // Other requests will be satisfied by downscaling.
  218. PaintVectorIcon(&canvas_100, icon, 27, SK_ColorBLACK);
  219. EXPECT_EQ(kPath32Color, GetColorAtTopLeft(canvas_100));
  220. PaintVectorIcon(&canvas_100, icon, 8, SK_ColorBLACK);
  221. EXPECT_EQ(kPath16Color, GetColorAtTopLeft(canvas_100));
  222. // Except in cases where an exact divisor is found.
  223. PaintVectorIcon(&canvas_100, icon, 40, SK_ColorBLACK);
  224. EXPECT_EQ(kPath20Color, GetColorAtTopLeft(canvas_100));
  225. PaintVectorIcon(&canvas_100, icon, 64, SK_ColorBLACK);
  226. EXPECT_EQ(kPath32Color, GetColorAtTopLeft(canvas_100));
  227. // Test icons at a scale factor < 100%, still with an exact size, paint the
  228. // correctly sized icon.
  229. Canvas canvas_75(gfx::Size(100, 100), 0.75, true);
  230. PaintVectorIcon(&canvas_75, icon, 32, SK_ColorBLACK); // 32 * 0.75 = 24.
  231. EXPECT_EQ(kPath24Color, GetColorAtTopLeft(canvas_75));
  232. // Test icons at a scale factor > 100%, still with an exact size, paint the
  233. // correctly sized icon.
  234. Canvas canvas_125(gfx::Size(100, 100), 1.25, true);
  235. PaintVectorIcon(&canvas_125, icon, 16, SK_ColorBLACK); // 16 * 1.25 = 20.
  236. EXPECT_EQ(kPath20Color, GetColorAtTopLeft(canvas_125));
  237. // Inexact sizes at scale factors < 100%.
  238. PaintVectorIcon(&canvas_75, icon, 12, SK_ColorBLACK); // 12 * 0.75 = 9.
  239. EXPECT_EQ(kPath16Color, GetColorAtTopLeft(canvas_75));
  240. PaintVectorIcon(&canvas_75, icon, 28, SK_ColorBLACK); // 28 * 0.75 = 21.
  241. EXPECT_EQ(kPath24Color, GetColorAtTopLeft(canvas_75));
  242. // Inexact sizes at scale factors > 100%.
  243. PaintVectorIcon(&canvas_125, icon, 12, SK_ColorBLACK); // 12 * 1.25 = 15.
  244. EXPECT_EQ(kPath16Color, GetColorAtTopLeft(canvas_125));
  245. PaintVectorIcon(&canvas_125, icon, 28, SK_ColorBLACK); // 28 * 1.25 = 35.
  246. EXPECT_EQ(kPath48Color, GetColorAtTopLeft(canvas_125));
  247. // Painting without a requested size will default to the smallest icon rep.
  248. PaintVectorIcon(&canvas_100, icon, SK_ColorBLACK);
  249. EXPECT_EQ(kPath16Color, GetColorAtTopLeft(canvas_100));
  250. // But doing this in another scale factor should assume the smallest icon rep
  251. // size, then scale it up by the DSF.
  252. PaintVectorIcon(&canvas_125, icon, SK_ColorBLACK); // 16 * 1.25 = 20.
  253. EXPECT_EQ(kPath20Color, GetColorAtTopLeft(canvas_125));
  254. }
  255. } // namespace
  256. } // namespace gfx