paint_info_unittest.cc 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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/views/paint_info.h"
  5. #include <memory>
  6. #include <vector>
  7. #include "base/memory/ref_counted.h"
  8. #include "cc/base/region.h"
  9. #include "testing/gtest/include/gtest/gtest.h"
  10. #include "ui/compositor/compositor_switches.h"
  11. #include "ui/compositor/paint_context.h"
  12. #include "ui/gfx/geometry/rect.h"
  13. #include "ui/gfx/geometry/size.h"
  14. namespace views {
  15. namespace {
  16. using PaintInfos = std::vector<std::unique_ptr<PaintInfo>>;
  17. // Device scale factors
  18. constexpr float DSF100 = 1.f;
  19. constexpr float DSF125 = 1.25f;
  20. constexpr float DSF150 = 1.5f;
  21. constexpr float DSF160 = 1.6f;
  22. constexpr float DSF166 = 1.66f;
  23. const std::vector<float> kDsfList = {DSF100, DSF125, DSF150, DSF160, DSF166};
  24. constexpr gfx::Size kLayerSize(123, 456);
  25. // ___________
  26. // | 1 |
  27. // |___________|
  28. // | 3 | 4 | 5 | <-- 2 (encapsulates 3, 4 and 5)
  29. // |___|___|___|
  30. // | 7 | 8 | <-- 6 (encapsulates 7 and 8)
  31. // |_______|___|
  32. //
  33. // |r_0| encapsulates 1, 2 and 6.
  34. const gfx::Rect r_0(kLayerSize);
  35. constexpr gfx::Rect r_1(0, 0, 123, 152);
  36. constexpr gfx::Rect r_2(0, 152, 123, 152);
  37. constexpr gfx::Rect r_3(0, 0, 41, 152);
  38. constexpr gfx::Rect r_4(41, 0, 41, 152);
  39. constexpr gfx::Rect r_5(82, 0, 41, 152);
  40. constexpr gfx::Rect r_6(0, 304, 123, 152);
  41. constexpr gfx::Rect r_7(0, 0, 82, 152);
  42. constexpr gfx::Rect r_8(82, 0, 41, 152);
  43. // Verifies that the child recording bounds completely cover the parent
  44. // recording bounds.
  45. void VerifyChildBoundsCoversParent(const PaintInfo* parent_paint_info,
  46. const std::vector<PaintInfo*>& info_list) {
  47. cc::Region remaining(gfx::Rect(parent_paint_info->paint_recording_size()));
  48. int times_empty = 0;
  49. for (auto* const paint_info : info_list) {
  50. const gfx::Rect& child_recording_bounds =
  51. paint_info->paint_recording_bounds() -
  52. parent_paint_info->paint_recording_bounds().OffsetFromOrigin();
  53. EXPECT_TRUE(remaining.Contains(child_recording_bounds))
  54. << "Remaining: " << remaining.ToString()
  55. << " paint recording bounds: " << child_recording_bounds.ToString();
  56. remaining.Subtract(child_recording_bounds);
  57. times_empty += remaining.IsEmpty();
  58. }
  59. EXPECT_EQ(times_empty, 1);
  60. }
  61. void VerifyPixelCanvasCornerScaling(const PaintInfos& info_list) {
  62. // child 1, child 2 and child 6 should completely cover child 0.
  63. std::vector<PaintInfo*> child_info_list;
  64. child_info_list.push_back(info_list[1].get());
  65. child_info_list.push_back(info_list[2].get());
  66. child_info_list.push_back(info_list[6].get());
  67. VerifyChildBoundsCoversParent(info_list[0].get(), child_info_list);
  68. child_info_list.clear();
  69. // Child 3,4 and 5 should completely cover child 2.
  70. child_info_list.push_back(info_list[3].get());
  71. child_info_list.push_back(info_list[4].get());
  72. child_info_list.push_back(info_list[5].get());
  73. VerifyChildBoundsCoversParent(info_list[2].get(), child_info_list);
  74. child_info_list.clear();
  75. // Child 7 and 8 should completely cover child 6.
  76. child_info_list.push_back(info_list[7].get());
  77. child_info_list.push_back(info_list[8].get());
  78. VerifyChildBoundsCoversParent(info_list[6].get(), child_info_list);
  79. child_info_list.clear();
  80. }
  81. void VerifyPixelSizesAreSameAsDIPSize(const PaintInfos& info_list) {
  82. EXPECT_EQ(info_list[0]->paint_recording_size(), r_0.size());
  83. EXPECT_EQ(info_list[1]->paint_recording_size(), r_1.size());
  84. EXPECT_EQ(info_list[2]->paint_recording_size(), r_2.size());
  85. EXPECT_EQ(info_list[3]->paint_recording_size(), r_3.size());
  86. EXPECT_EQ(info_list[4]->paint_recording_size(), r_4.size());
  87. EXPECT_EQ(info_list[5]->paint_recording_size(), r_5.size());
  88. EXPECT_EQ(info_list[6]->paint_recording_size(), r_6.size());
  89. EXPECT_EQ(info_list[7]->paint_recording_size(), r_7.size());
  90. EXPECT_EQ(info_list[8]->paint_recording_size(), r_8.size());
  91. }
  92. } // namespace
  93. class PaintInfoTest : public ::testing::Test {
  94. public:
  95. PaintInfoTest() = default;
  96. ~PaintInfoTest() override = default;
  97. // ___________
  98. // | 1 |
  99. // |___________|
  100. // | 3 | 4 | 5 | <-- 2 (encapsulates 3, 4 and 5)
  101. // |___|___|___|
  102. // | 7 | 8 | <-- 6 (encapsulates 7 and 8)
  103. // |_______|___|
  104. //
  105. // |r_0| encapsulates 1, 2 and 6.
  106. //
  107. // Returns the following arrangement of paint recording bounds for the given
  108. // |dsf|
  109. PaintInfos GetPaintInfoSetup(const ui::PaintContext& context) {
  110. PaintInfos info_list(9);
  111. info_list[0].reset(new PaintInfo(context, kLayerSize));
  112. info_list[1].reset(
  113. new PaintInfo(*info_list[0], r_1, r_0.size(),
  114. PaintInfo::ScaleType::kScaleWithEdgeSnapping, false));
  115. info_list[2].reset(
  116. new PaintInfo(*info_list[0], r_2, r_0.size(),
  117. PaintInfo::ScaleType::kScaleWithEdgeSnapping, false));
  118. info_list[3].reset(
  119. new PaintInfo(*info_list[2], r_3, r_2.size(),
  120. PaintInfo::ScaleType::kScaleWithEdgeSnapping, false));
  121. info_list[4].reset(
  122. new PaintInfo(*info_list[2], r_4, r_2.size(),
  123. PaintInfo::ScaleType::kScaleWithEdgeSnapping, false));
  124. info_list[5].reset(
  125. new PaintInfo(*info_list[2], r_5, r_2.size(),
  126. PaintInfo::ScaleType::kScaleWithEdgeSnapping, false));
  127. info_list[6].reset(
  128. new PaintInfo(*info_list[0], r_6, r_0.size(),
  129. PaintInfo::ScaleType::kScaleWithEdgeSnapping, false));
  130. info_list[7].reset(
  131. new PaintInfo(*info_list[6], r_7, r_6.size(),
  132. PaintInfo::ScaleType::kScaleWithEdgeSnapping, false));
  133. info_list[8].reset(
  134. new PaintInfo(*info_list[6], r_8, r_6.size(),
  135. PaintInfo::ScaleType::kScaleWithEdgeSnapping, false));
  136. return info_list;
  137. }
  138. void VerifyInvalidationRects(float dsf, bool pixel_canvas_enabled) {
  139. std::vector<gfx::Rect> invalidation_rects = {
  140. gfx::Rect(0, 0, 123, 41), // Intersects with 0 & 1.
  141. gfx::Rect(0, 76, 60, 152), // Intersects 0, 1, 2, 3 & 4.
  142. gfx::Rect(41, 152, 41, 152), // Intersects with 0, 2 & 4.
  143. gfx::Rect(80, 320, 4, 4), // Intersects with 0, 6, 7 & 8.
  144. gfx::Rect(40, 151, 43, 154), // Intersects all
  145. gfx::Rect(82, 304, 1, 1), // Intersects with 0, 6 & 8.
  146. gfx::Rect(81, 303, 2, 2) // Intersects with 0, 2, 4, 5, 6, 7, 8
  147. };
  148. std::vector<std::vector<int>> repaint_indices = {
  149. std::vector<int>{0, 1},
  150. std::vector<int>{0, 1, 2, 3, 4},
  151. std::vector<int>{0, 2, 4},
  152. std::vector<int>{0, 6, 7, 8},
  153. std::vector<int>{0, 1, 2, 3, 4, 5, 6, 7, 8},
  154. std::vector<int>{0, 6, 8},
  155. std::vector<int>{0, 2, 4, 5, 6, 7, 8}};
  156. PaintInfos info_list;
  157. EXPECT_EQ(repaint_indices.size(), invalidation_rects.size());
  158. for (size_t i = 0; i < invalidation_rects.size(); i++) {
  159. ui::PaintContext context(nullptr, dsf, invalidation_rects[i],
  160. pixel_canvas_enabled);
  161. info_list = GetPaintInfoSetup(context);
  162. for (int repaint_index : repaint_indices[i]) {
  163. EXPECT_TRUE(info_list[repaint_index]->context().IsRectInvalid(
  164. gfx::Rect(info_list[repaint_index]->paint_recording_size())));
  165. }
  166. info_list.clear();
  167. }
  168. }
  169. };
  170. TEST_F(PaintInfoTest, CornerScalingPixelCanvasEnabled) {
  171. PaintInfos info_list;
  172. for (float dsf : kDsfList) {
  173. ui::PaintContext context(nullptr, dsf, gfx::Rect(), true);
  174. info_list = GetPaintInfoSetup(context);
  175. VerifyPixelCanvasCornerScaling(info_list);
  176. info_list.clear();
  177. }
  178. // More accurate testing for 1.25 dsf
  179. ui::PaintContext context(nullptr, DSF125, gfx::Rect(), true);
  180. info_list = GetPaintInfoSetup(context);
  181. VerifyPixelCanvasCornerScaling(info_list);
  182. EXPECT_EQ(info_list[0]->paint_recording_size(), gfx::Size(154, 570));
  183. EXPECT_EQ(info_list[1]->paint_recording_size(), gfx::Size(154, 190));
  184. EXPECT_EQ(info_list[2]->paint_recording_bounds(),
  185. gfx::Rect(0, 190, 154, 190));
  186. EXPECT_EQ(info_list[3]->paint_recording_size(), gfx::Size(51, 190));
  187. EXPECT_EQ(info_list[4]->paint_recording_bounds(),
  188. gfx::Rect(51, 190, 52, 190));
  189. EXPECT_EQ(info_list[5]->paint_recording_bounds(),
  190. gfx::Rect(103, 190, 51, 190));
  191. EXPECT_EQ(info_list[6]->paint_recording_bounds(),
  192. gfx::Rect(0, 380, 154, 190));
  193. EXPECT_EQ(info_list[7]->paint_recording_size(), gfx::Size(103, 190));
  194. EXPECT_EQ(info_list[8]->paint_recording_bounds(),
  195. gfx::Rect(103, 380, 51, 190));
  196. }
  197. TEST_F(PaintInfoTest, ScalingWithPixelCanvasDisabled) {
  198. for (float dsf : kDsfList) {
  199. ui::PaintContext context(nullptr, dsf, gfx::Rect(), false);
  200. PaintInfos info_list = GetPaintInfoSetup(context);
  201. VerifyPixelCanvasCornerScaling(info_list);
  202. VerifyPixelSizesAreSameAsDIPSize(info_list);
  203. info_list.clear();
  204. }
  205. }
  206. TEST_F(PaintInfoTest, Invalidation) {
  207. for (float dsf : kDsfList) {
  208. VerifyInvalidationRects(dsf, false);
  209. VerifyInvalidationRects(dsf, true);
  210. }
  211. }
  212. // Make sure the PaintInfo used for view's layer uses the
  213. // corderedbounds.
  214. TEST_F(PaintInfoTest, LayerPaintInfo) {
  215. const gfx::Rect kViewBounds(15, 20, 7, 13);
  216. struct TestData {
  217. const float dsf;
  218. const gfx::Size size;
  219. };
  220. const TestData kTestData[6]{
  221. {1.0f, {7, 13}}, // rounded enclosing (if these scaling is appleid)
  222. {1.25f, {9, 16}}, // 9x16 10x17
  223. {1.5f, {10, 20}}, // 11x20 11x20
  224. {1.6f, {11, 21}}, // 11x21 12x21
  225. {1.75f, {13, 23}}, // 12x23 13x23
  226. {2.f, {14, 26}}, // 14x26 14x26
  227. };
  228. for (const TestData& data : kTestData) {
  229. SCOPED_TRACE(testing::Message() << "dsf:" << data.dsf);
  230. ui::PaintContext context(nullptr, data.dsf, gfx::Rect(), true);
  231. PaintInfo parent_paint_info(context, gfx::Size());
  232. PaintInfo paint_info = PaintInfo::CreateChildPaintInfo(
  233. parent_paint_info, kViewBounds, gfx::Size(),
  234. PaintInfo::ScaleType::kScaleWithEdgeSnapping, true);
  235. EXPECT_EQ(gfx::Rect(data.size), paint_info.paint_recording_bounds());
  236. }
  237. }
  238. } // namespace views