nine_patch_layer_impl_unittest.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. // Copyright 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. #include <stddef.h>
  5. #include <algorithm>
  6. #include <memory>
  7. #include <utility>
  8. #include "base/numerics/safe_conversions.h"
  9. #include "cc/layers/append_quads_data.h"
  10. #include "cc/layers/nine_patch_layer_impl.h"
  11. #include "cc/resources/ui_resource_bitmap.h"
  12. #include "cc/resources/ui_resource_client.h"
  13. #include "cc/test/fake_impl_task_runner_provider.h"
  14. #include "cc/test/fake_layer_tree_frame_sink.h"
  15. #include "cc/test/fake_ui_resource_layer_tree_host_impl.h"
  16. #include "cc/test/layer_tree_impl_test_base.h"
  17. #include "cc/trees/single_thread_proxy.h"
  18. #include "components/viz/common/quads/texture_draw_quad.h"
  19. #include "testing/gmock/include/gmock/gmock.h"
  20. #include "testing/gtest/include/gtest/gtest.h"
  21. #include "ui/gfx/geometry/rect_conversions.h"
  22. #include "ui/gfx/geometry/transform.h"
  23. namespace cc {
  24. namespace {
  25. gfx::Rect ToRoundedIntRect(const gfx::RectF& rect_f) {
  26. return gfx::Rect(base::ClampRound(rect_f.x()), base::ClampRound(rect_f.y()),
  27. base::ClampRound(rect_f.width()),
  28. base::ClampRound(rect_f.height()));
  29. }
  30. void NinePatchLayerLayoutTest(const gfx::Size& bitmap_size,
  31. const gfx::Rect& aperture_rect,
  32. const gfx::Size& layer_size,
  33. const gfx::Rect& border,
  34. bool fill_center,
  35. size_t expected_quad_size) {
  36. auto render_pass = viz::CompositorRenderPass::Create();
  37. gfx::Rect visible_layer_rect(layer_size);
  38. gfx::Rect expected_remaining(border.x(), border.y(),
  39. layer_size.width() - border.width(),
  40. layer_size.height() - border.height());
  41. FakeImplTaskRunnerProvider task_runner_provider;
  42. TestTaskGraphRunner task_graph_runner;
  43. std::unique_ptr<LayerTreeFrameSink> layer_tree_frame_sink =
  44. FakeLayerTreeFrameSink::Create3d();
  45. FakeUIResourceLayerTreeHostImpl host_impl(&task_runner_provider,
  46. &task_graph_runner);
  47. host_impl.SetVisible(true);
  48. host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
  49. std::unique_ptr<NinePatchLayerImpl> layer =
  50. NinePatchLayerImpl::Create(host_impl.active_tree(), 1);
  51. layer->draw_properties().visible_layer_rect = visible_layer_rect;
  52. layer->SetBounds(layer_size);
  53. SetupRootProperties(layer.get());
  54. UIResourceId uid = 1;
  55. bool is_opaque = false;
  56. UIResourceBitmap bitmap(bitmap_size, is_opaque);
  57. host_impl.CreateUIResource(uid, bitmap);
  58. layer->SetUIResourceId(uid);
  59. layer->SetImageBounds(bitmap_size);
  60. layer->SetLayout(aperture_rect, border, gfx::Rect(), fill_center, false);
  61. host_impl.active_tree()->SetRootLayerForTesting(std::move(layer));
  62. UpdateDrawProperties(host_impl.active_tree());
  63. AppendQuadsData data;
  64. host_impl.active_tree()->root_layer()->AppendQuads(render_pass.get(), &data);
  65. // Verify quad rects
  66. const auto& quads = render_pass->quad_list;
  67. EXPECT_EQ(expected_quad_size, quads.size());
  68. Region layer_remaining(visible_layer_rect);
  69. for (auto iter = quads.cbegin(); iter != quads.cend(); ++iter) {
  70. gfx::Rect quad_rect = iter->rect;
  71. EXPECT_TRUE(visible_layer_rect.Contains(quad_rect)) << iter.index();
  72. EXPECT_TRUE(layer_remaining.Contains(quad_rect)) << iter.index();
  73. EXPECT_EQ(iter->needs_blending,
  74. !iter->shared_quad_state->are_contents_opaque);
  75. layer_remaining.Subtract(Region(quad_rect));
  76. }
  77. // Check if the left-over quad is the same size as the mapped aperture quad in
  78. // layer space.
  79. if (!fill_center) {
  80. EXPECT_EQ(expected_remaining, layer_remaining.bounds());
  81. } else {
  82. EXPECT_TRUE(layer_remaining.bounds().IsEmpty());
  83. }
  84. // Verify UV rects
  85. gfx::Rect bitmap_rect(bitmap_size);
  86. Region tex_remaining(bitmap_rect);
  87. for (auto* quad : quads) {
  88. const viz::TextureDrawQuad* tex_quad =
  89. viz::TextureDrawQuad::MaterialCast(quad);
  90. gfx::RectF tex_rect =
  91. gfx::BoundingRect(tex_quad->uv_top_left, tex_quad->uv_bottom_right);
  92. tex_rect.Scale(bitmap_size.width(), bitmap_size.height());
  93. tex_remaining.Subtract(Region(ToRoundedIntRect(tex_rect)));
  94. }
  95. if (!fill_center) {
  96. EXPECT_EQ(aperture_rect, tex_remaining.bounds());
  97. Region aperture_region(aperture_rect);
  98. EXPECT_EQ(aperture_region, tex_remaining);
  99. } else {
  100. EXPECT_TRUE(layer_remaining.bounds().IsEmpty());
  101. }
  102. host_impl.DeleteUIResource(uid);
  103. }
  104. void NinePatchLayerLayoutTestWithOcclusion(const gfx::Size& bitmap_size,
  105. const gfx::Rect& aperture_rect,
  106. const gfx::Size& layer_size,
  107. const gfx::Rect& border,
  108. const gfx::Rect& occlusion,
  109. bool fill_center,
  110. size_t expected_quad_size) {
  111. auto render_pass = viz::CompositorRenderPass::Create();
  112. gfx::Rect visible_layer_rect(layer_size);
  113. int border_left = std::min(border.x(), occlusion.x()),
  114. border_top = std::min(border.y(), occlusion.y()),
  115. border_right = std::min(border.width() - border.x(),
  116. layer_size.width() - occlusion.right()),
  117. border_bottom = std::min(border.height() - border.y(),
  118. layer_size.height() - occlusion.bottom());
  119. gfx::Rect expected_layer_remaining(
  120. border_left, border_top, layer_size.width() - border_left - border_right,
  121. layer_size.height() - border_top - border_bottom);
  122. float ratio_left = border_left == 0 ? 0 : (aperture_rect.x() / border.x()),
  123. ratio_top = border_top == 0 ? 0 : (aperture_rect.y() / border.y()),
  124. ratio_right = border_right == 0
  125. ? 0
  126. : ((bitmap_size.width() - aperture_rect.right()) /
  127. (border.width() - border.x())),
  128. ratio_bottom = border_bottom == 0
  129. ? 0
  130. : ((bitmap_size.height() - aperture_rect.bottom()) /
  131. (border.height() - border.y()));
  132. int image_remaining_left = border_left * ratio_left,
  133. image_remaining_top = border_top * ratio_top,
  134. image_remaining_right = border_right * ratio_right,
  135. image_remaining_bottom = border_bottom * ratio_bottom;
  136. gfx::Rect expected_tex_remaining(
  137. image_remaining_left, image_remaining_top,
  138. bitmap_size.width() - image_remaining_right - image_remaining_left,
  139. bitmap_size.height() - image_remaining_bottom - image_remaining_top);
  140. FakeImplTaskRunnerProvider task_runner_provider;
  141. TestTaskGraphRunner task_graph_runner;
  142. std::unique_ptr<LayerTreeFrameSink> layer_tree_frame_sink =
  143. FakeLayerTreeFrameSink::Create3d();
  144. FakeUIResourceLayerTreeHostImpl host_impl(&task_runner_provider,
  145. &task_graph_runner);
  146. host_impl.SetVisible(true);
  147. host_impl.InitializeFrameSink(layer_tree_frame_sink.get());
  148. std::unique_ptr<NinePatchLayerImpl> layer =
  149. NinePatchLayerImpl::Create(host_impl.active_tree(), 1);
  150. layer->draw_properties().visible_layer_rect = visible_layer_rect;
  151. layer->SetBounds(layer_size);
  152. SetupRootProperties(layer.get());
  153. UIResourceId uid = 1;
  154. bool is_opaque = false;
  155. UIResourceBitmap bitmap(bitmap_size, is_opaque);
  156. host_impl.CreateUIResource(uid, bitmap);
  157. layer->SetUIResourceId(uid);
  158. layer->SetImageBounds(bitmap_size);
  159. layer->SetLayout(aperture_rect, border, occlusion, false, false);
  160. host_impl.active_tree()->SetRootLayerForTesting(std::move(layer));
  161. UpdateDrawProperties(host_impl.active_tree());
  162. AppendQuadsData data;
  163. host_impl.active_tree()->root_layer()->AppendQuads(render_pass.get(), &data);
  164. // Verify quad rects
  165. const auto& quads = render_pass->quad_list;
  166. EXPECT_EQ(expected_quad_size, quads.size());
  167. Region layer_remaining(visible_layer_rect);
  168. for (auto iter = quads.cbegin(); iter != quads.cend(); ++iter) {
  169. gfx::Rect quad_rect = iter->rect;
  170. EXPECT_TRUE(visible_layer_rect.Contains(quad_rect)) << iter.index();
  171. EXPECT_TRUE(layer_remaining.Contains(quad_rect)) << iter.index();
  172. EXPECT_EQ(iter->needs_blending,
  173. !iter->shared_quad_state->are_contents_opaque);
  174. layer_remaining.Subtract(Region(quad_rect));
  175. }
  176. // Check if the left-over quad is the same size as the mapped aperture quad in
  177. // layer space.
  178. EXPECT_EQ(expected_layer_remaining, layer_remaining.bounds());
  179. // Verify UV rects
  180. gfx::Rect bitmap_rect(bitmap_size);
  181. Region tex_remaining(bitmap_rect);
  182. for (auto* quad : quads) {
  183. const viz::TextureDrawQuad* tex_quad =
  184. viz::TextureDrawQuad::MaterialCast(quad);
  185. gfx::RectF tex_rect =
  186. gfx::BoundingRect(tex_quad->uv_top_left, tex_quad->uv_bottom_right);
  187. tex_rect.Scale(bitmap_size.width(), bitmap_size.height());
  188. tex_remaining.Subtract(Region(ToRoundedIntRect(tex_rect)));
  189. }
  190. EXPECT_EQ(expected_tex_remaining, tex_remaining.bounds());
  191. Region aperture_region(expected_tex_remaining);
  192. EXPECT_EQ(aperture_region, tex_remaining);
  193. host_impl.DeleteUIResource(uid);
  194. }
  195. TEST(NinePatchLayerImplTest, VerifyDrawQuads) {
  196. // Input is a 100x100 bitmap with a 40x50 aperture at x=20, y=30.
  197. // The bounds of the layer are set to 400x400.
  198. gfx::Size bitmap_size(100, 100);
  199. gfx::Size layer_size(400, 500);
  200. gfx::Rect aperture_rect(20, 30, 40, 50);
  201. gfx::Rect border(40, 40, 80, 80);
  202. bool fill_center = false;
  203. size_t expected_quad_size = 8;
  204. NinePatchLayerLayoutTest(bitmap_size, aperture_rect, layer_size, border,
  205. fill_center, expected_quad_size);
  206. // The bounds of the layer are set to less than the bitmap size.
  207. bitmap_size = gfx::Size(100, 100);
  208. layer_size = gfx::Size(40, 50);
  209. aperture_rect = gfx::Rect(20, 30, 40, 50);
  210. border = gfx::Rect(10, 10, 25, 15);
  211. fill_center = true;
  212. expected_quad_size = 9;
  213. NinePatchLayerLayoutTest(bitmap_size, aperture_rect, layer_size, border,
  214. fill_center, expected_quad_size);
  215. // Layer and image sizes are equal.
  216. bitmap_size = gfx::Size(100, 100);
  217. layer_size = gfx::Size(100, 100);
  218. aperture_rect = gfx::Rect(20, 30, 40, 50);
  219. border = gfx::Rect(20, 30, 40, 50);
  220. fill_center = true;
  221. expected_quad_size = 9;
  222. NinePatchLayerLayoutTest(bitmap_size, aperture_rect, layer_size, border,
  223. fill_center, expected_quad_size);
  224. }
  225. TEST(NinePatchLayerImplTest, VerifyDrawQuadsWithOcclusion) {
  226. // Occlusion removed part of the border and leaves us with 12 patches.
  227. gfx::Size bitmap_size(100, 100);
  228. gfx::Rect aperture_rect(30, 30, 40, 40);
  229. gfx::Size layer_size(400, 400);
  230. gfx::Rect occlusion(20, 20, 360, 360);
  231. gfx::Rect border(30, 30, 60, 60);
  232. size_t expected_quad_size = 12;
  233. NinePatchLayerLayoutTestWithOcclusion(bitmap_size, aperture_rect, layer_size,
  234. border, occlusion, false,
  235. expected_quad_size);
  236. bitmap_size = gfx::Size(100, 100);
  237. aperture_rect = gfx::Rect(20, 30, 60, 40);
  238. layer_size = gfx::Size(400, 400);
  239. occlusion = gfx::Rect(10, 10, 380, 380);
  240. border = gfx::Rect(20, 30, 40, 60);
  241. expected_quad_size = 12;
  242. NinePatchLayerLayoutTestWithOcclusion(bitmap_size, aperture_rect, layer_size,
  243. border, occlusion, false,
  244. expected_quad_size);
  245. // All borders are empty, so nothing should be drawn.
  246. bitmap_size = gfx::Size(100, 100);
  247. aperture_rect = gfx::Rect(0, 0, 100, 100);
  248. layer_size = gfx::Size(400, 400);
  249. occlusion = gfx::Rect(0, 0, 400, 400);
  250. border = gfx::Rect(0, 0, 0, 0);
  251. expected_quad_size = 0;
  252. NinePatchLayerLayoutTestWithOcclusion(bitmap_size, aperture_rect, layer_size,
  253. border, occlusion, false,
  254. expected_quad_size);
  255. // Right border is empty, we should have no quads on the right side.
  256. bitmap_size = gfx::Size(100, 100);
  257. aperture_rect = gfx::Rect(20, 30, 80, 40);
  258. layer_size = gfx::Size(400, 400);
  259. occlusion = gfx::Rect(10, 10, 390, 380);
  260. border = gfx::Rect(20, 30, 20, 60);
  261. expected_quad_size = 7;
  262. NinePatchLayerLayoutTestWithOcclusion(bitmap_size, aperture_rect, layer_size,
  263. border, occlusion, false,
  264. expected_quad_size);
  265. }
  266. TEST(NinePatchLayerImplTest, VerifyDrawQuadsWithEmptyPatches) {
  267. // The top component of the 9-patch is empty, so there should be no quads for
  268. // the top three components.
  269. gfx::Size bitmap_size(100, 100);
  270. gfx::Size layer_size(100, 100);
  271. gfx::Rect aperture_rect(10, 0, 80, 90);
  272. gfx::Rect border(10, 0, 20, 10);
  273. bool fill_center = false;
  274. size_t expected_quad_size = 5;
  275. NinePatchLayerLayoutTest(bitmap_size, aperture_rect, layer_size, border,
  276. fill_center, expected_quad_size);
  277. // The top and left components of the 9-patch are empty, so there should be no
  278. // quads for the left and top components.
  279. bitmap_size = gfx::Size(100, 100);
  280. layer_size = gfx::Size(100, 100);
  281. aperture_rect = gfx::Rect(0, 0, 90, 90);
  282. border = gfx::Rect(0, 0, 10, 10);
  283. fill_center = false;
  284. expected_quad_size = 3;
  285. NinePatchLayerLayoutTest(bitmap_size, aperture_rect, layer_size, border,
  286. fill_center, expected_quad_size);
  287. // The aperture is the size of the bitmap and the center doesn't draw.
  288. bitmap_size = gfx::Size(100, 100);
  289. layer_size = gfx::Size(100, 100);
  290. aperture_rect = gfx::Rect(0, 0, 100, 100);
  291. border = gfx::Rect(0, 0, 0, 0);
  292. fill_center = false;
  293. expected_quad_size = 0;
  294. NinePatchLayerLayoutTest(bitmap_size, aperture_rect, layer_size, border,
  295. fill_center, expected_quad_size);
  296. // The aperture is the size of the bitmap and the center does draw.
  297. bitmap_size = gfx::Size(100, 100);
  298. layer_size = gfx::Size(100, 100);
  299. aperture_rect = gfx::Rect(0, 0, 100, 100);
  300. border = gfx::Rect(0, 0, 0, 0);
  301. fill_center = true;
  302. expected_quad_size = 1;
  303. NinePatchLayerLayoutTest(bitmap_size, aperture_rect, layer_size, border,
  304. fill_center, expected_quad_size);
  305. }
  306. TEST(NinePatchLayerImplTest, Occlusion) {
  307. gfx::Size layer_size(1000, 1000);
  308. gfx::Size viewport_size(1000, 1000);
  309. LayerTreeImplTestBase impl;
  310. SkBitmap sk_bitmap;
  311. sk_bitmap.allocN32Pixels(10, 10);
  312. sk_bitmap.setImmutable();
  313. UIResourceId uid = 5;
  314. UIResourceBitmap bitmap(sk_bitmap);
  315. impl.host_impl()->CreateUIResource(uid, bitmap);
  316. NinePatchLayerImpl* nine_patch_layer_impl =
  317. impl.AddLayer<NinePatchLayerImpl>();
  318. nine_patch_layer_impl->SetBounds(layer_size);
  319. nine_patch_layer_impl->SetDrawsContent(true);
  320. nine_patch_layer_impl->SetUIResourceId(uid);
  321. nine_patch_layer_impl->SetImageBounds(gfx::Size(10, 10));
  322. CopyProperties(impl.root_layer(), nine_patch_layer_impl);
  323. gfx::Rect aperture = gfx::Rect(3, 3, 4, 4);
  324. gfx::Rect border = gfx::Rect(300, 300, 400, 400);
  325. nine_patch_layer_impl->SetLayout(aperture, border, gfx::Rect(), true, false);
  326. impl.CalcDrawProps(viewport_size);
  327. {
  328. SCOPED_TRACE("No occlusion");
  329. gfx::Rect occluded;
  330. impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, occluded);
  331. VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect(layer_size));
  332. EXPECT_EQ(9u, impl.quad_list().size());
  333. }
  334. {
  335. SCOPED_TRACE("Full occlusion");
  336. gfx::Rect occluded(nine_patch_layer_impl->visible_layer_rect());
  337. impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, occluded);
  338. VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
  339. EXPECT_EQ(impl.quad_list().size(), 0u);
  340. }
  341. {
  342. SCOPED_TRACE("Partial occlusion");
  343. gfx::Rect occluded(0, 0, 500, 1000);
  344. impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, occluded);
  345. size_t partially_occluded_count = 0;
  346. VerifyQuadsAreOccluded(impl.quad_list(), occluded,
  347. &partially_occluded_count);
  348. // The layer outputs nine quads, three of which are partially occluded, and
  349. // three fully occluded.
  350. EXPECT_EQ(6u, impl.quad_list().size());
  351. EXPECT_EQ(3u, partially_occluded_count);
  352. }
  353. }
  354. TEST(NinePatchLayerImplTest, OpaqueRect) {
  355. gfx::Size layer_size(1000, 1000);
  356. gfx::Size viewport_size(1000, 1000);
  357. LayerTreeImplTestBase impl;
  358. SkBitmap sk_bitmap_opaque;
  359. sk_bitmap_opaque.allocN32Pixels(10, 10);
  360. sk_bitmap_opaque.setImmutable();
  361. sk_bitmap_opaque.setAlphaType(kOpaque_SkAlphaType);
  362. UIResourceId uid_opaque = 6;
  363. UIResourceBitmap bitmap_opaque(sk_bitmap_opaque);
  364. impl.host_impl()->CreateUIResource(uid_opaque, bitmap_opaque);
  365. SkBitmap sk_bitmap_alpha;
  366. sk_bitmap_alpha.allocN32Pixels(10, 10);
  367. sk_bitmap_alpha.setImmutable();
  368. sk_bitmap_alpha.setAlphaType(kUnpremul_SkAlphaType);
  369. UIResourceId uid_alpha = 7;
  370. UIResourceBitmap bitmap_alpha(sk_bitmap_alpha);
  371. impl.host_impl()->CreateUIResource(uid_alpha, bitmap_alpha);
  372. NinePatchLayerImpl* nine_patch_layer_impl =
  373. impl.AddLayer<NinePatchLayerImpl>();
  374. nine_patch_layer_impl->SetBounds(layer_size);
  375. nine_patch_layer_impl->SetDrawsContent(true);
  376. CopyProperties(impl.root_layer(), nine_patch_layer_impl);
  377. impl.CalcDrawProps(viewport_size);
  378. {
  379. SCOPED_TRACE("Use opaque image");
  380. nine_patch_layer_impl->SetUIResourceId(uid_opaque);
  381. nine_patch_layer_impl->SetImageBounds(gfx::Size(10, 10));
  382. gfx::Rect aperture = gfx::Rect(3, 3, 4, 4);
  383. gfx::Rect border = gfx::Rect(300, 300, 400, 400);
  384. nine_patch_layer_impl->SetLayout(aperture, border, gfx::Rect(), true,
  385. false);
  386. impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, gfx::Rect());
  387. const auto& quad_list = impl.quad_list();
  388. for (auto it = quad_list.BackToFrontBegin();
  389. it != quad_list.BackToFrontEnd(); ++it)
  390. EXPECT_FALSE(it->ShouldDrawWithBlending());
  391. }
  392. {
  393. SCOPED_TRACE("Use tranparent image");
  394. nine_patch_layer_impl->SetUIResourceId(uid_alpha);
  395. impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, gfx::Rect());
  396. const auto& quad_list = impl.quad_list();
  397. for (auto it = quad_list.BackToFrontBegin();
  398. it != quad_list.BackToFrontEnd(); ++it)
  399. EXPECT_TRUE(it->ShouldDrawWithBlending());
  400. }
  401. }
  402. } // namespace
  403. } // namespace cc