paint_manager_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. // Copyright 2022 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 "pdf/paint_manager.h"
  5. #include <utility>
  6. #include "base/files/file_path.h"
  7. #include "base/run_loop.h"
  8. #include "base/strings/string_piece.h"
  9. #include "cc/test/pixel_comparator.h"
  10. #include "cc/test/pixel_test_utils.h"
  11. #include "pdf/paint_ready_rect.h"
  12. #include "pdf/test/test_helpers.h"
  13. #include "testing/gmock/include/gmock/gmock.h"
  14. #include "testing/gtest/include/gtest/gtest.h"
  15. #include "third_party/skia/include/core/SkBitmap.h"
  16. #include "third_party/skia/include/core/SkCanvas.h"
  17. #include "third_party/skia/include/core/SkColor.h"
  18. #include "third_party/skia/include/core/SkImage.h"
  19. #include "third_party/skia/include/core/SkRect.h"
  20. #include "third_party/skia/include/core/SkRefCnt.h"
  21. #include "third_party/skia/include/core/SkSurface.h"
  22. #include "ui/gfx/geometry/rect.h"
  23. #include "ui/gfx/geometry/size.h"
  24. #include "ui/gfx/geometry/skia_conversions.h"
  25. namespace chrome_pdf {
  26. namespace {
  27. using ::testing::_;
  28. using ::testing::NiceMock;
  29. base::FilePath GetTestDataFilePath(base::StringPiece filename) {
  30. return base::FilePath(FILE_PATH_LITERAL("paint_manager"))
  31. .AppendASCII(filename);
  32. }
  33. class FakeClient : public PaintManager::Client {
  34. public:
  35. MOCK_METHOD(void, InvalidatePluginContainer, (), (override));
  36. MOCK_METHOD(void,
  37. OnPaint,
  38. (const std::vector<gfx::Rect>& paint_rects,
  39. std::vector<PaintReadyRect>& ready,
  40. std::vector<gfx::Rect>& pending),
  41. (override));
  42. MOCK_METHOD(void, UpdateSnapshot, (sk_sp<SkImage> snapshot), (override));
  43. MOCK_METHOD(void, UpdateScale, (float scale), (override));
  44. MOCK_METHOD(void,
  45. UpdateLayerTransform,
  46. (float scale, const gfx::Vector2dF& translate),
  47. (override));
  48. };
  49. class PaintManagerTest : public testing::Test {
  50. protected:
  51. void WaitForOnPaint() {
  52. base::RunLoop run_loop;
  53. EXPECT_CALL(client_, OnPaint).WillOnce([&run_loop] { run_loop.Quit(); });
  54. run_loop.Run();
  55. }
  56. sk_sp<SkImage> WaitForFlush(
  57. const std::vector<gfx::Rect>& expected_paint_rects,
  58. std::vector<PaintReadyRect> fake_ready,
  59. std::vector<gfx::Rect> fake_pending) {
  60. EXPECT_CALL(client_, OnPaint(expected_paint_rects, _, _))
  61. .WillOnce([&fake_ready, &fake_pending](
  62. const std::vector<gfx::Rect>& paint_rects,
  63. std::vector<PaintReadyRect>& ready,
  64. std::vector<gfx::Rect>& pending) {
  65. ready = std::move(fake_ready);
  66. pending = std::move(fake_pending);
  67. });
  68. sk_sp<SkImage> saved_snapshot;
  69. base::RunLoop run_loop;
  70. EXPECT_CALL(client_, UpdateSnapshot)
  71. .WillOnce([&saved_snapshot, &run_loop](sk_sp<SkImage> snapshot) {
  72. saved_snapshot = std::move(snapshot);
  73. run_loop.Quit();
  74. });
  75. run_loop.Run();
  76. return saved_snapshot;
  77. }
  78. void TestPaintImage(const gfx::Size& plugin_size,
  79. const gfx::Size& source_size,
  80. const gfx::Rect& paint_rect,
  81. const gfx::Rect& overlapped_rect) {
  82. // Paint `paint_rect` from `source_size` image over a magenta background.
  83. paint_manager_.SetSize(plugin_size, 1.0f);
  84. sk_sp<SkImage> snapshot = WaitForFlush(
  85. /*expected_paint_rects=*/{{gfx::Rect(plugin_size)}},
  86. /*fake_ready=*/
  87. {
  88. {gfx::Rect(plugin_size),
  89. CreateSkiaImageForTesting(plugin_size, SK_ColorMAGENTA)},
  90. {paint_rect, CreateSkiaImageForTesting(source_size, SK_ColorRED)},
  91. },
  92. /*fake_pending=*/{});
  93. ASSERT_TRUE(snapshot);
  94. // Check if snapshot has `overlapped_rect` painted red.
  95. snapshot = snapshot->makeSubset(
  96. SkIRect::MakeWH(plugin_size.width(), plugin_size.height()));
  97. ASSERT_TRUE(snapshot);
  98. SkBitmap snapshot_bitmap;
  99. ASSERT_TRUE(snapshot->asLegacyBitmap(&snapshot_bitmap));
  100. sk_sp<SkSurface> expected_surface =
  101. CreateSkiaSurfaceForTesting(plugin_size, SK_ColorMAGENTA);
  102. expected_surface->getCanvas()->clipIRect(
  103. gfx::RectToSkIRect(overlapped_rect));
  104. expected_surface->getCanvas()->clear(SK_ColorRED);
  105. SkBitmap expected_bitmap;
  106. ASSERT_TRUE(expected_surface->makeImageSnapshot()->asLegacyBitmap(
  107. &expected_bitmap));
  108. EXPECT_TRUE(
  109. cc::MatchesBitmap(snapshot_bitmap, expected_bitmap,
  110. cc::ExactPixelComparator(/*discard_alpha=*/false)));
  111. }
  112. void TestScroll(const gfx::Vector2d& scroll_amount,
  113. const gfx::Rect& expected_paint_rect,
  114. base::StringPiece expected_png) {
  115. // Paint non-uniform initial image.
  116. gfx::Size plugin_size = paint_manager_.GetEffectiveSize();
  117. ASSERT_GE(plugin_size.width(), 4);
  118. ASSERT_GE(plugin_size.height(), 4);
  119. sk_sp<SkSurface> initial_surface =
  120. CreateSkiaSurfaceForTesting(plugin_size, SK_ColorRED);
  121. initial_surface->getCanvas()->clipIRect(SkIRect::MakeLTRB(
  122. 1, 1, plugin_size.width() - 1, plugin_size.height() - 2));
  123. initial_surface->getCanvas()->clear(SK_ColorGREEN);
  124. paint_manager_.Invalidate();
  125. ASSERT_TRUE(WaitForFlush(
  126. /*expected_paint_rects=*/{gfx::Rect(plugin_size)},
  127. /*fake_ready=*/
  128. {{gfx::Rect(plugin_size), initial_surface->makeImageSnapshot()}},
  129. /*fake_pending=*/{}));
  130. // Scroll by `scroll_amount`, painting `expected_paint_rect` magenta.
  131. paint_manager_.ScrollRect(gfx::Rect(plugin_size), scroll_amount);
  132. sk_sp<SkImage> snapshot = WaitForFlush(
  133. /*expected_paint_rects=*/{expected_paint_rect},
  134. /*fake_ready=*/
  135. {{expected_paint_rect,
  136. CreateSkiaImageForTesting(plugin_size, SK_ColorMAGENTA)}},
  137. /*fake_pending=*/{});
  138. ASSERT_TRUE(snapshot);
  139. // Compare snapshot to `expected_png`.
  140. snapshot = snapshot->makeSubset(
  141. SkIRect::MakeWH(plugin_size.width(), plugin_size.height()));
  142. ASSERT_TRUE(snapshot);
  143. EXPECT_TRUE(
  144. MatchesPngFile(snapshot.get(), GetTestDataFilePath(expected_png)));
  145. }
  146. NiceMock<FakeClient> client_;
  147. PaintManager paint_manager_{&client_};
  148. };
  149. TEST_F(PaintManagerTest, GetNewContextSizeWhenGrowingBelowMaximum) {
  150. EXPECT_EQ(gfx::Size(450, 350),
  151. PaintManager::GetNewContextSize({450, 350}, {450, 349}));
  152. EXPECT_EQ(gfx::Size(450, 350),
  153. PaintManager::GetNewContextSize({450, 350}, {449, 350}));
  154. }
  155. TEST_F(PaintManagerTest, GetNewContextSizeWhenGrowingAboveMaximum) {
  156. EXPECT_EQ(gfx::Size(501, 400),
  157. PaintManager::GetNewContextSize({450, 350}, {451, 350}));
  158. EXPECT_EQ(gfx::Size(500, 401),
  159. PaintManager::GetNewContextSize({450, 350}, {450, 351}));
  160. }
  161. TEST_F(PaintManagerTest, GetNewContextSizeWhenShrinkingAboveMinimum) {
  162. EXPECT_EQ(gfx::Size(450, 350),
  163. PaintManager::GetNewContextSize({450, 350}, {350, 251}));
  164. EXPECT_EQ(gfx::Size(450, 350),
  165. PaintManager::GetNewContextSize({450, 350}, {351, 250}));
  166. }
  167. TEST_F(PaintManagerTest, GetNewContextSizeWhenShrinkingBelowMinimum) {
  168. EXPECT_EQ(gfx::Size(399, 300),
  169. PaintManager::GetNewContextSize({450, 350}, {349, 250}));
  170. EXPECT_EQ(gfx::Size(400, 299),
  171. PaintManager::GetNewContextSize({450, 350}, {350, 249}));
  172. }
  173. TEST_F(PaintManagerTest, Create) {
  174. EXPECT_EQ(gfx::Size(0, 0), paint_manager_.GetEffectiveSize());
  175. EXPECT_EQ(1.0f, paint_manager_.GetEffectiveDeviceScale());
  176. }
  177. TEST_F(PaintManagerTest, SetSizeWithoutPaint) {
  178. EXPECT_CALL(client_, InvalidatePluginContainer).Times(0);
  179. paint_manager_.SetSize({400, 300}, 2.0f);
  180. EXPECT_EQ(gfx::Size(400, 300), paint_manager_.GetEffectiveSize());
  181. EXPECT_EQ(2.0f, paint_manager_.GetEffectiveDeviceScale());
  182. }
  183. TEST_F(PaintManagerTest, SetSizeWithPaint) {
  184. paint_manager_.SetSize({400, 300}, 2.0f);
  185. EXPECT_CALL(client_, InvalidatePluginContainer);
  186. EXPECT_CALL(client_, UpdateScale(0.5f));
  187. WaitForOnPaint();
  188. }
  189. TEST_F(PaintManagerTest, SetTransformWithoutSurface) {
  190. EXPECT_CALL(client_, UpdateLayerTransform).Times(0);
  191. paint_manager_.SetTransform(0.25f, {150, 50}, {-4, 8},
  192. /*schedule_flush=*/true);
  193. }
  194. TEST_F(PaintManagerTest, SetTransformWithSurface) {
  195. paint_manager_.SetSize({400, 300}, 2.0f);
  196. WaitForOnPaint();
  197. EXPECT_CALL(client_,
  198. UpdateLayerTransform(0.25f, gfx::Vector2dF(116.5f, 29.5f)));
  199. paint_manager_.SetTransform(0.25f, {150, 50}, {-4, 8},
  200. /*schedule_flush=*/true);
  201. WaitForOnPaint();
  202. }
  203. TEST_F(PaintManagerTest, ClearTransform) {
  204. paint_manager_.SetSize({400, 300}, 2.0f);
  205. WaitForOnPaint();
  206. EXPECT_CALL(client_, UpdateLayerTransform(1.0f, gfx::Vector2dF()));
  207. paint_manager_.ClearTransform();
  208. }
  209. TEST_F(PaintManagerTest, DoPaintFirst) {
  210. paint_manager_.SetSize({400, 300}, 2.0f);
  211. sk_sp<SkImage> snapshot =
  212. WaitForFlush(/*expected_paint_rects=*/{{0, 0, 400, 300}},
  213. /*fake_ready=*/
  214. {{{25, 50, 200, 100},
  215. CreateSkiaImageForTesting({200, 100}, SK_ColorGRAY)}},
  216. /*fake_pending=*/{});
  217. EXPECT_TRUE(MatchesPngFile(snapshot.get(),
  218. GetTestDataFilePath("do_paint_first.png")));
  219. }
  220. TEST_F(PaintManagerTest, PaintImage) {
  221. // Painted area is within the plugin area and the source image.
  222. TestPaintImage(/*plugin_size=*/{20, 20}, /*source_size=*/{15, 15},
  223. /*paint_rect=*/{0, 0, 10, 10},
  224. /*overlapped_rect=*/{0, 0, 10, 10});
  225. // Painted area straddles the plugin area and the source image.
  226. TestPaintImage(/*plugin_size=*/{50, 30}, /*source_size=*/{30, 50},
  227. /*paint_rect=*/{10, 10, 30, 30},
  228. /*overlapped_rect=*/{10, 10, 20, 20});
  229. // Painted area is outside the plugin area.
  230. TestPaintImage(/*plugin_size=*/{10, 10}, /*source_size=*/{30, 30},
  231. /*paint_rect=*/{10, 10, 10, 10},
  232. /*overlapped_rect=*/{0, 0, 0, 0});
  233. // Painted area is outside the source image.
  234. TestPaintImage(/*plugin_size=*/{15, 15}, /*source_size=*/{5, 5},
  235. /*paint_rect=*/{10, 10, 5, 5},
  236. /*overlapped_rect=*/{0, 0, 0, 0});
  237. }
  238. TEST_F(PaintManagerTest, Scroll) {
  239. paint_manager_.SetSize({4, 5}, 1.0f);
  240. TestScroll(/*scroll_amount=*/{1, 0}, /*expected_paint_rect=*/{0, 0, 1, 5},
  241. "scroll_right.png");
  242. TestScroll(/*scroll_amount=*/{-2, 0}, /*expected_paint_rect=*/{2, 0, 2, 5},
  243. "scroll_left.png");
  244. TestScroll(/*scroll_amount=*/{0, 3}, /*expected_paint_rect=*/{0, 0, 4, 3},
  245. "scroll_down.png");
  246. TestScroll(/*scroll_amount=*/{0, -3}, /*expected_paint_rect=*/{0, 2, 4, 3},
  247. "scroll_up.png");
  248. }
  249. TEST_F(PaintManagerTest, ScrollIgnored) {
  250. paint_manager_.SetSize({4, 5}, 1.0f);
  251. // Scroll to the edge of the plugin area.
  252. TestScroll(/*scroll_amount=*/{4, 0}, /*expected_paint_rect=*/{0, 0, 4, 5},
  253. "scroll_ignored.png");
  254. TestScroll(/*scroll_amount=*/{-4, 0}, /*expected_paint_rect=*/{0, 0, 4, 5},
  255. "scroll_ignored.png");
  256. TestScroll(/*scroll_amount=*/{0, 5}, /*expected_paint_rect=*/{0, 0, 4, 5},
  257. "scroll_ignored.png");
  258. TestScroll(/*scroll_amount=*/{0, -5}, /*expected_paint_rect=*/{0, 0, 4, 5},
  259. "scroll_ignored.png");
  260. // Scroll outside of the plugin area.
  261. TestScroll(/*scroll_amount=*/{5, 0}, /*expected_paint_rect=*/{0, 0, 4, 5},
  262. "scroll_ignored.png");
  263. TestScroll(/*scroll_amount=*/{-7, 0}, /*expected_paint_rect=*/{0, 0, 4, 5},
  264. "scroll_ignored.png");
  265. TestScroll(/*scroll_amount=*/{0, 8}, /*expected_paint_rect=*/{0, 0, 4, 5},
  266. "scroll_ignored.png");
  267. TestScroll(/*scroll_amount=*/{0, -9}, /*expected_paint_rect=*/{0, 0, 4, 5},
  268. "scroll_ignored.png");
  269. }
  270. } // namespace
  271. } // namespace chrome_pdf