scrollbar_layer_unittest.cc 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507
  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 <memory>
  6. #include <unordered_map>
  7. #include "base/memory/raw_ptr.h"
  8. #include "base/threading/thread_task_runner_handle.h"
  9. #include "cc/animation/animation_host.h"
  10. #include "cc/input/scrollbar_animation_controller.h"
  11. #include "cc/layers/append_quads_data.h"
  12. #include "cc/layers/painted_overlay_scrollbar_layer.h"
  13. #include "cc/layers/painted_scrollbar_layer.h"
  14. #include "cc/layers/painted_scrollbar_layer_impl.h"
  15. #include "cc/layers/scrollbar_layer_base.h"
  16. #include "cc/layers/solid_color_scrollbar_layer.h"
  17. #include "cc/layers/solid_color_scrollbar_layer_impl.h"
  18. #include "cc/resources/ui_resource_manager.h"
  19. #include "cc/test/fake_impl_task_runner_provider.h"
  20. #include "cc/test/fake_layer_tree_host.h"
  21. #include "cc/test/fake_layer_tree_host_client.h"
  22. #include "cc/test/fake_layer_tree_host_impl.h"
  23. #include "cc/test/fake_painted_scrollbar_layer.h"
  24. #include "cc/test/fake_scrollbar.h"
  25. #include "cc/test/layer_tree_impl_test_base.h"
  26. #include "cc/test/layer_tree_test.h"
  27. #include "cc/test/mock_occlusion_tracker.h"
  28. #include "cc/test/stub_layer_tree_host_single_thread_client.h"
  29. #include "cc/test/test_task_graph_runner.h"
  30. #include "cc/trees/effect_node.h"
  31. #include "cc/trees/layer_tree_host.h"
  32. #include "cc/trees/layer_tree_impl.h"
  33. #include "cc/trees/occlusion_tracker.h"
  34. #include "cc/trees/scroll_node.h"
  35. #include "cc/trees/single_thread_proxy.h"
  36. #include "cc/trees/tree_synchronizer.h"
  37. #include "components/viz/common/quads/solid_color_draw_quad.h"
  38. #include "components/viz/test/test_context_provider.h"
  39. #include "components/viz/test/test_gles2_interface.h"
  40. #include "testing/gmock/include/gmock/gmock.h"
  41. #include "testing/gtest/include/gtest/gtest.h"
  42. namespace cc {
  43. class FakeResourceTrackingUIResourceManager : public UIResourceManager {
  44. public:
  45. FakeResourceTrackingUIResourceManager()
  46. : next_id_(1),
  47. total_ui_resource_created_(0),
  48. total_ui_resource_deleted_(0) {}
  49. ~FakeResourceTrackingUIResourceManager() override = default;
  50. UIResourceId CreateUIResource(UIResourceClient* content) override {
  51. total_ui_resource_created_++;
  52. UIResourceId nid = next_id_++;
  53. ui_resource_bitmap_map_.insert(
  54. std::make_pair(nid, content->GetBitmap(nid, false)));
  55. return nid;
  56. }
  57. // Deletes a UI resource. May safely be called more than once.
  58. void DeleteUIResource(UIResourceId id) override {
  59. auto iter = ui_resource_bitmap_map_.find(id);
  60. if (iter != ui_resource_bitmap_map_.end()) {
  61. ui_resource_bitmap_map_.erase(iter);
  62. total_ui_resource_deleted_++;
  63. }
  64. }
  65. size_t UIResourceCount() { return ui_resource_bitmap_map_.size(); }
  66. int TotalUIResourceDeleted() { return total_ui_resource_deleted_; }
  67. int TotalUIResourceCreated() { return total_ui_resource_created_; }
  68. gfx::Size ui_resource_size(UIResourceId id) {
  69. auto iter = ui_resource_bitmap_map_.find(id);
  70. if (iter != ui_resource_bitmap_map_.end())
  71. return iter->second.GetSize();
  72. return gfx::Size();
  73. }
  74. UIResourceBitmap* ui_resource_bitmap(UIResourceId id) {
  75. auto iter = ui_resource_bitmap_map_.find(id);
  76. if (iter != ui_resource_bitmap_map_.end())
  77. return &iter->second;
  78. return nullptr;
  79. }
  80. private:
  81. using UIResourceBitmapMap =
  82. std::unordered_map<UIResourceId, UIResourceBitmap>;
  83. UIResourceBitmapMap ui_resource_bitmap_map_;
  84. StubLayerTreeHostSingleThreadClient single_thread_client_;
  85. int next_id_;
  86. int total_ui_resource_created_;
  87. int total_ui_resource_deleted_;
  88. };
  89. class BaseScrollbarLayerTest : public testing::Test {
  90. public:
  91. explicit BaseScrollbarLayerTest(
  92. LayerTreeSettings::ScrollbarAnimator animator) {
  93. layer_tree_settings_.single_thread_proxy_scheduler = false;
  94. layer_tree_settings_.use_zero_copy = true;
  95. layer_tree_settings_.scrollbar_animator = animator;
  96. layer_tree_settings_.scrollbar_fade_delay = base::Milliseconds(20);
  97. layer_tree_settings_.scrollbar_fade_duration = base::Milliseconds(20);
  98. animation_host_ = AnimationHost::CreateForTesting(ThreadInstance::MAIN);
  99. LayerTreeHost::InitParams params;
  100. params.client = &fake_client_;
  101. params.settings = &layer_tree_settings_;
  102. params.task_graph_runner = &task_graph_runner_;
  103. params.mutator_host = animation_host_.get();
  104. std::unique_ptr<FakeResourceTrackingUIResourceManager>
  105. fake_ui_resource_manager =
  106. std::make_unique<FakeResourceTrackingUIResourceManager>();
  107. fake_ui_resource_manager_ = fake_ui_resource_manager.get();
  108. layer_tree_host_ = std::make_unique<FakeLayerTreeHost>(
  109. &fake_client_, std::move(params), CompositorMode::SINGLE_THREADED);
  110. layer_tree_host_->SetUIResourceManagerForTesting(
  111. std::move(fake_ui_resource_manager));
  112. layer_tree_host_->InitializeSingleThreaded(
  113. &single_thread_client_, base::ThreadTaskRunnerHandle::Get());
  114. layer_tree_host_->SetVisible(true);
  115. fake_client_.SetLayerTreeHost(layer_tree_host_.get());
  116. }
  117. protected:
  118. raw_ptr<FakeResourceTrackingUIResourceManager> fake_ui_resource_manager_;
  119. FakeLayerTreeHostClient fake_client_;
  120. StubLayerTreeHostSingleThreadClient single_thread_client_;
  121. TestTaskGraphRunner task_graph_runner_;
  122. LayerTreeSettings layer_tree_settings_;
  123. std::unique_ptr<AnimationHost> animation_host_;
  124. std::unique_ptr<FakeLayerTreeHost> layer_tree_host_;
  125. };
  126. class ScrollbarLayerTest : public BaseScrollbarLayerTest {
  127. public:
  128. ScrollbarLayerTest()
  129. : BaseScrollbarLayerTest(LayerTreeSettings::ANDROID_OVERLAY) {}
  130. };
  131. class AuraScrollbarLayerTest : public BaseScrollbarLayerTest {
  132. public:
  133. AuraScrollbarLayerTest()
  134. : BaseScrollbarLayerTest(LayerTreeSettings::AURA_OVERLAY) {}
  135. };
  136. class FakePaintedOverlayScrollbar : public FakeScrollbar {
  137. public:
  138. FakePaintedOverlayScrollbar() {
  139. set_should_paint(true);
  140. set_has_thumb(true);
  141. set_is_overlay(true);
  142. }
  143. bool UsesNinePatchThumbResource() const override { return true; }
  144. gfx::Size NinePatchThumbCanvasSize() const override {
  145. return gfx::Size(3, 3);
  146. }
  147. gfx::Rect NinePatchThumbAperture() const override {
  148. return gfx::Rect(1, 1, 1, 1);
  149. }
  150. private:
  151. ~FakePaintedOverlayScrollbar() override = default;
  152. };
  153. // Test that a painted overlay scrollbar will repaint and recrate its resource
  154. // after its been disposed, even if Blink doesn't think it requires a repaint.
  155. // crbug.com/704656.
  156. TEST_F(ScrollbarLayerTest, RepaintOverlayWhenResourceDisposed) {
  157. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  158. scoped_refptr<Layer> content_layer = Layer::Create();
  159. auto fake_scrollbar = base::MakeRefCounted<FakePaintedOverlayScrollbar>();
  160. scoped_refptr<PaintedOverlayScrollbarLayer> scrollbar_layer =
  161. PaintedOverlayScrollbarLayer::Create(fake_scrollbar);
  162. scrollbar_layer->SetScrollElementId(layer_tree_root->element_id());
  163. // Setup.
  164. {
  165. layer_tree_root->AddChild(content_layer);
  166. layer_tree_root->AddChild(scrollbar_layer);
  167. layer_tree_host_->SetRootLayer(layer_tree_root);
  168. scrollbar_layer->SetIsDrawable(true);
  169. scrollbar_layer->SetBounds(gfx::Size(100, 100));
  170. layer_tree_root->SetBounds(gfx::Size(100, 200));
  171. content_layer->SetBounds(gfx::Size(100, 200));
  172. }
  173. // First call to update should create a resource. The scrollbar itself thinks
  174. // it needs a repaint.
  175. {
  176. fake_scrollbar->set_needs_repaint_thumb(true);
  177. EXPECT_EQ(0u, fake_ui_resource_manager_->UIResourceCount());
  178. EXPECT_TRUE(scrollbar_layer->Update());
  179. EXPECT_EQ(1u, fake_ui_resource_manager_->UIResourceCount());
  180. }
  181. // Now the scrollbar has been painted and nothing else has changed, calling
  182. // Update() shouldn't have an effect.
  183. {
  184. fake_scrollbar->set_needs_repaint_thumb(false);
  185. EXPECT_FALSE(scrollbar_layer->Update());
  186. EXPECT_EQ(1u, fake_ui_resource_manager_->UIResourceCount());
  187. }
  188. // Detach and reattach the LayerTreeHost (this can happen during tree
  189. // reconstruction). This should cause the UIResource for the scrollbar to be
  190. // disposed but the scrollbar itself hasn't changed so it reports that no
  191. // repaint is needed. An Update should cause us to recreate the resource
  192. // though.
  193. {
  194. scrollbar_layer->SetLayerTreeHost(nullptr);
  195. scrollbar_layer->SetLayerTreeHost(layer_tree_host_.get());
  196. EXPECT_EQ(0u, fake_ui_resource_manager_->UIResourceCount());
  197. EXPECT_TRUE(scrollbar_layer->Update());
  198. EXPECT_EQ(1u, fake_ui_resource_manager_->UIResourceCount());
  199. }
  200. }
  201. TEST_F(ScrollbarLayerTest, SetNeedsDisplayDoesNotRequireUpdate) {
  202. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  203. scoped_refptr<Layer> content_layer = Layer::Create();
  204. scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
  205. FakePaintedScrollbarLayer::Create(true, true,
  206. layer_tree_root->element_id());
  207. // Setup.
  208. {
  209. layer_tree_root->AddChild(content_layer);
  210. layer_tree_root->AddChild(scrollbar_layer);
  211. layer_tree_host_->SetRootLayer(layer_tree_root);
  212. scrollbar_layer->SetIsDrawable(true);
  213. scrollbar_layer->SetBounds(gfx::Size(100, 100));
  214. layer_tree_root->SetBounds(gfx::Size(100, 200));
  215. content_layer->SetBounds(gfx::Size(100, 200));
  216. }
  217. layer_tree_host_->UpdateLayers();
  218. // Simulate commit to compositor thread.
  219. scrollbar_layer->PushPropertiesTo(
  220. scrollbar_layer->CreateLayerImpl(layer_tree_host_->active_tree()).get(),
  221. *layer_tree_host_->GetPendingCommitState(),
  222. layer_tree_host_->GetThreadUnsafeCommitState());
  223. scrollbar_layer->fake_scrollbar()->set_needs_repaint_thumb(false);
  224. scrollbar_layer->fake_scrollbar()->set_needs_repaint_track(false);
  225. EXPECT_FALSE(scrollbar_layer->Update());
  226. // Opacity changes should cause an update.
  227. {
  228. scrollbar_layer->fake_scrollbar()->set_thumb_opacity(0.3f);
  229. EXPECT_TRUE(scrollbar_layer->Update());
  230. }
  231. // Needing a thumb repaint should cause an update.
  232. {
  233. scrollbar_layer->fake_scrollbar()->set_needs_repaint_thumb(true);
  234. EXPECT_TRUE(scrollbar_layer->Update());
  235. scrollbar_layer->fake_scrollbar()->set_needs_repaint_thumb(false);
  236. EXPECT_FALSE(scrollbar_layer->Update());
  237. }
  238. // Needing a track repaint should cause an update.
  239. {
  240. scrollbar_layer->fake_scrollbar()->set_needs_repaint_track(true);
  241. EXPECT_TRUE(scrollbar_layer->Update());
  242. scrollbar_layer->fake_scrollbar()->set_needs_repaint_track(false);
  243. EXPECT_FALSE(scrollbar_layer->Update());
  244. }
  245. // A scroll will cause |SetNeedsDisplay| to be called, but the scrollbar parts
  246. // are used for invalidation, rather than the scrollbar layer itself. This
  247. // should not cause an update. This is important for performance as an update
  248. // will cause a commit on every scroll offset change.
  249. {
  250. scrollbar_layer->SetNeedsDisplay();
  251. EXPECT_FALSE(scrollbar_layer->Update());
  252. }
  253. }
  254. class FakeNinePatchScrollbar : public FakeScrollbar {
  255. public:
  256. FakeNinePatchScrollbar() {
  257. set_should_paint(true);
  258. set_has_thumb(true);
  259. set_is_overlay(true);
  260. }
  261. bool UsesNinePatchThumbResource() const override { return true; }
  262. private:
  263. ~FakeNinePatchScrollbar() override = default;
  264. };
  265. TEST_F(ScrollbarLayerTest, ScrollElementIdPushedAcrossCommit) {
  266. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  267. scoped_refptr<Layer> layer_a = Layer::Create();
  268. scoped_refptr<Layer> layer_b = Layer::Create();
  269. layer_a->SetElementId(LayerIdToElementIdForTesting(layer_a->id()));
  270. layer_b->SetElementId(LayerIdToElementIdForTesting(layer_b->id()));
  271. scoped_refptr<PaintedScrollbarLayer> painted_scrollbar_layer =
  272. PaintedScrollbarLayer::Create(base::MakeRefCounted<FakeScrollbar>());
  273. painted_scrollbar_layer->SetScrollElementId(layer_a->element_id());
  274. scoped_refptr<PaintedOverlayScrollbarLayer> painted_overlay_scrollbar_layer =
  275. PaintedOverlayScrollbarLayer::Create(
  276. base::MakeRefCounted<FakeNinePatchScrollbar>());
  277. painted_overlay_scrollbar_layer->SetScrollElementId(layer_a->element_id());
  278. scoped_refptr<SolidColorScrollbarLayer> solid_color_scrollbar_layer =
  279. SolidColorScrollbarLayer::Create(ScrollbarOrientation::VERTICAL, 1, 1,
  280. false);
  281. solid_color_scrollbar_layer->SetScrollElementId(layer_a->element_id());
  282. layer_tree_host_->SetRootLayer(layer_tree_root);
  283. layer_tree_root->AddChild(layer_a);
  284. layer_tree_root->AddChild(layer_b);
  285. layer_tree_root->AddChild(painted_scrollbar_layer);
  286. layer_tree_root->AddChild(painted_overlay_scrollbar_layer);
  287. layer_tree_root->AddChild(solid_color_scrollbar_layer);
  288. layer_tree_host_->UpdateLayers();
  289. LayerImpl* layer_impl_tree_root =
  290. layer_tree_host_->CommitAndCreateLayerImplTree();
  291. ScrollbarLayerImplBase* painted_scrollbar_layer_impl =
  292. static_cast<ScrollbarLayerImplBase*>(
  293. layer_impl_tree_root->layer_tree_impl()->LayerById(
  294. painted_scrollbar_layer->id()));
  295. ScrollbarLayerImplBase* painted_overlay_scrollbar_layer_impl =
  296. static_cast<ScrollbarLayerImplBase*>(
  297. layer_impl_tree_root->layer_tree_impl()->LayerById(
  298. painted_overlay_scrollbar_layer->id()));
  299. ScrollbarLayerImplBase* solid_color_scrollbar_layer_impl =
  300. static_cast<ScrollbarLayerImplBase*>(
  301. layer_impl_tree_root->layer_tree_impl()->LayerById(
  302. solid_color_scrollbar_layer->id()));
  303. ASSERT_EQ(painted_scrollbar_layer_impl->scroll_element_id_,
  304. layer_a->element_id());
  305. ASSERT_EQ(painted_overlay_scrollbar_layer_impl->scroll_element_id_,
  306. layer_a->element_id());
  307. ASSERT_EQ(solid_color_scrollbar_layer_impl->scroll_element_id_,
  308. layer_a->element_id());
  309. painted_scrollbar_layer->SetScrollElementId(layer_b->element_id());
  310. painted_overlay_scrollbar_layer->SetScrollElementId(layer_b->element_id());
  311. solid_color_scrollbar_layer->SetScrollElementId(layer_b->element_id());
  312. ASSERT_TRUE(layer_tree_host_->needs_commit());
  313. // WillCommit(_, true) here will ensure that
  314. // layer_tree_host_->active_commit_state() is populated, which is required
  315. // during FinishCommitOnImplThread().
  316. auto& unsafe_state = layer_tree_host_->GetThreadUnsafeCommitState();
  317. auto completion_event_ptr = std::make_unique<CompletionEvent>(
  318. base::WaitableEvent::ResetPolicy::MANUAL);
  319. auto* completion_event = completion_event_ptr.get();
  320. std::unique_ptr<CommitState> commit_state =
  321. layer_tree_host_->WillCommit(std::move(completion_event_ptr),
  322. /*has_updates=*/true);
  323. {
  324. DebugScopedSetImplThread scoped_impl_thread(
  325. layer_tree_host_->GetTaskRunnerProvider());
  326. layer_tree_host_->host_impl()->FinishCommit(*commit_state, unsafe_state);
  327. completion_event->Signal();
  328. }
  329. layer_tree_host_->CommitComplete({base::TimeTicks(), base::TimeTicks::Now()});
  330. EXPECT_EQ(painted_scrollbar_layer_impl->scroll_element_id_,
  331. layer_b->element_id());
  332. EXPECT_EQ(painted_overlay_scrollbar_layer_impl->scroll_element_id_,
  333. layer_b->element_id());
  334. EXPECT_EQ(solid_color_scrollbar_layer_impl->scroll_element_id_,
  335. layer_b->element_id());
  336. }
  337. TEST_F(ScrollbarLayerTest, ScrollOffsetSynchronization) {
  338. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  339. scoped_refptr<Layer> scroll_layer = Layer::Create();
  340. scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
  341. scoped_refptr<Layer> content_layer = Layer::Create();
  342. scoped_refptr<PaintedScrollbarLayer> scrollbar_layer =
  343. PaintedScrollbarLayer::Create(base::MakeRefCounted<FakeScrollbar>());
  344. scrollbar_layer->SetScrollElementId(scroll_layer->element_id());
  345. // Choose bounds to give max_scroll_offset = (30, 50).
  346. layer_tree_root->SetBounds(gfx::Size(70, 150));
  347. scroll_layer->SetScrollOffset(gfx::PointF(10, 20));
  348. scroll_layer->SetBounds(gfx::Size(100, 200));
  349. scroll_layer->SetScrollable(gfx::Size(70, 150));
  350. content_layer->SetBounds(gfx::Size(100, 200));
  351. layer_tree_host_->SetRootLayer(layer_tree_root);
  352. layer_tree_root->AddChild(scroll_layer);
  353. scroll_layer->AddChild(content_layer);
  354. layer_tree_root->AddChild(scrollbar_layer);
  355. layer_tree_host_->UpdateLayers();
  356. LayerImpl* layer_impl_tree_root =
  357. layer_tree_host_->CommitAndCreateLayerImplTree();
  358. ScrollbarLayerImplBase* cc_scrollbar_layer =
  359. static_cast<PaintedScrollbarLayerImpl*>(
  360. layer_impl_tree_root->layer_tree_impl()->LayerById(
  361. scrollbar_layer->id()));
  362. layer_impl_tree_root->layer_tree_impl()->UpdateScrollbarGeometries();
  363. EXPECT_EQ(10.f, cc_scrollbar_layer->current_pos());
  364. EXPECT_EQ(30, cc_scrollbar_layer->scroll_layer_length() -
  365. cc_scrollbar_layer->clip_layer_length());
  366. layer_tree_root->SetBounds(gfx::Size(700, 1500));
  367. scroll_layer->SetScrollable(gfx::Size(700, 1500));
  368. scroll_layer->SetBounds(gfx::Size(1000, 2000));
  369. scroll_layer->SetScrollOffset(gfx::PointF(100, 200));
  370. content_layer->SetBounds(gfx::Size(1000, 2000));
  371. layer_tree_host_->UpdateLayers();
  372. layer_impl_tree_root = layer_tree_host_->CommitAndCreateLayerImplTree();
  373. layer_impl_tree_root->layer_tree_impl()->UpdateScrollbarGeometries();
  374. EXPECT_EQ(100.f, cc_scrollbar_layer->current_pos());
  375. EXPECT_EQ(300, cc_scrollbar_layer->scroll_layer_length() -
  376. cc_scrollbar_layer->clip_layer_length());
  377. LayerImpl* scroll_layer_impl =
  378. layer_impl_tree_root->layer_tree_impl()->LayerById(scroll_layer->id());
  379. scroll_layer_impl->ScrollBy(gfx::Vector2d(12, 34));
  380. layer_impl_tree_root->layer_tree_impl()->UpdateScrollbarGeometries();
  381. EXPECT_EQ(112.f, cc_scrollbar_layer->current_pos());
  382. EXPECT_EQ(300, cc_scrollbar_layer->scroll_layer_length() -
  383. cc_scrollbar_layer->clip_layer_length());
  384. }
  385. #define UPDATE_AND_EXTRACT_LAYER_POINTERS() \
  386. do { \
  387. scrollbar_layer->UpdateInternalContentScale(); \
  388. scrollbar_layer->UpdateThumbAndTrackGeometry(); \
  389. root_layer_impl = layer_tree_host_->CommitAndCreateLayerImplTree(); \
  390. root_layer_impl->layer_tree_impl()->UpdateScrollbarGeometries(); \
  391. scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( \
  392. root_layer_impl->layer_tree_impl()->LayerById(scrollbar_layer->id())); \
  393. } while (false)
  394. TEST_F(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
  395. scoped_refptr<Layer> root_layer = Layer::Create();
  396. scoped_refptr<Layer> content_layer = Layer::Create();
  397. scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
  398. FakePaintedScrollbarLayer::Create(false, true, root_layer->element_id());
  399. // Give the root layer a size that will result in MaxScrollOffset = (80, 0).
  400. root_layer->SetScrollable(gfx::Size(20, 50));
  401. root_layer->SetBounds(gfx::Size(100, 50));
  402. content_layer->SetBounds(gfx::Size(100, 50));
  403. layer_tree_host_->SetRootLayer(root_layer);
  404. root_layer->AddChild(content_layer);
  405. root_layer->AddChild(scrollbar_layer);
  406. root_layer->SetScrollOffset(gfx::PointF(0, 0));
  407. scrollbar_layer->SetBounds(gfx::Size(70, 10));
  408. // The track_rect should be relative to the scrollbar's origin.
  409. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(10, 10, 50, 10));
  410. scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(4, 10));
  411. LayerImpl* root_layer_impl = nullptr;
  412. PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
  413. layer_tree_host_->BuildPropertyTreesForTesting();
  414. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  415. EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
  416. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  417. scrollbar_layer->fake_scrollbar()->set_has_thumb(false);
  418. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  419. EXPECT_EQ(gfx::Rect(10, 0, 0, 0).ToString(),
  420. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  421. }
  422. TEST_F(ScrollbarLayerTest, ThumbRect) {
  423. scoped_refptr<Layer> root_layer = Layer::Create();
  424. root_layer->SetElementId(LayerIdToElementIdForTesting(root_layer->id()));
  425. scoped_refptr<Layer> content_layer = Layer::Create();
  426. scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
  427. FakePaintedScrollbarLayer::Create(false, true, root_layer->element_id());
  428. // Give the root layer a size that will result in MaxScrollOffset = (80, 0).
  429. root_layer->SetScrollable(gfx::Size(20, 50));
  430. root_layer->SetBounds(gfx::Size(100, 50));
  431. content_layer->SetBounds(gfx::Size(100, 50));
  432. layer_tree_host_->SetRootLayer(root_layer);
  433. root_layer->AddChild(content_layer);
  434. root_layer->AddChild(scrollbar_layer);
  435. root_layer->SetScrollOffset(gfx::PointF(0, 0));
  436. scrollbar_layer->SetBounds(gfx::Size(70, 10));
  437. // The track_rect should be relative to the scrollbar's origin.
  438. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(10, 10, 50, 10));
  439. scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(4, 10));
  440. layer_tree_host_->UpdateLayers();
  441. LayerImpl* root_layer_impl = nullptr;
  442. PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
  443. // Thumb is at the edge of the scrollbar (should be inset to
  444. // the start of the track within the scrollbar layer's
  445. // position).
  446. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  447. EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
  448. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  449. // Under-scroll (thumb position should clamp and be unchanged).
  450. root_layer->SetScrollOffset(gfx::PointF(-5, 0));
  451. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  452. EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
  453. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  454. // Over-scroll (thumb position should clamp on the far side).
  455. root_layer->SetScrollOffset(gfx::PointF(85, 0));
  456. layer_tree_host_->UpdateLayers();
  457. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  458. EXPECT_EQ(gfx::Rect(56, 0, 4, 10).ToString(),
  459. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  460. // Change thumb thickness and length.
  461. scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(6, 4));
  462. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  463. EXPECT_EQ(gfx::Rect(54, 0, 6, 4).ToString(),
  464. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  465. // Shrink the scrollbar layer to cover only the track.
  466. scrollbar_layer->SetBounds(gfx::Size(50, 10));
  467. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 10, 50, 10));
  468. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  469. EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
  470. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  471. // Shrink the track in the non-scrolling dimension so that it only covers the
  472. // middle third of the scrollbar layer (this does not affect the thumb
  473. // position).
  474. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 12, 50, 6));
  475. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  476. EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
  477. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  478. }
  479. TEST_F(ScrollbarLayerTest, ThumbRectForOverlayLeftSideVerticalScrollbar) {
  480. scoped_refptr<Layer> root_layer = Layer::Create();
  481. // Create an overlay left side vertical scrollbar.
  482. scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
  483. FakePaintedScrollbarLayer::Create(false, true,
  484. ScrollbarOrientation::VERTICAL, true,
  485. true, root_layer->element_id());
  486. root_layer->SetScrollable(gfx::Size(20, 50));
  487. root_layer->SetBounds(gfx::Size(50, 100));
  488. layer_tree_host_->SetRootLayer(root_layer);
  489. root_layer->AddChild(scrollbar_layer);
  490. root_layer->SetScrollOffset(gfx::PointF(0, 0));
  491. scrollbar_layer->SetBounds(gfx::Size(10, 20));
  492. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 10, 20));
  493. scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(10, 4));
  494. layer_tree_host_->UpdateLayers();
  495. LayerImpl* root_layer_impl = nullptr;
  496. PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
  497. // Thumb is at the edge of the scrollbar (should be inset to
  498. // the start of the track within the scrollbar layer's
  499. // position).
  500. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  501. EXPECT_EQ(gfx::Rect(0, 0, 10, 4).ToString(),
  502. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  503. // Change thumb thickness scale factor.
  504. scrollbar_layer_impl->SetThumbThicknessScaleFactor(0.5);
  505. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  506. // For overlay scrollbars thumb_rect.width = thumb_thickness *
  507. // thumb_thickness_scale_factor.
  508. EXPECT_EQ(gfx::Rect(0, 0, 5, 4).ToString(),
  509. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  510. // Change thumb thickness and length.
  511. scrollbar_layer->fake_scrollbar()->set_thumb_size(gfx::Size(4, 6));
  512. UPDATE_AND_EXTRACT_LAYER_POINTERS();
  513. // For left side vertical scrollbars thumb_rect.x = bounds.width() -
  514. // thumb_thickness.
  515. EXPECT_EQ(gfx::Rect(6, 0, 2, 6).ToString(),
  516. scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
  517. }
  518. TEST_F(ScrollbarLayerTest, SolidColorDrawQuads) {
  519. const int kThumbThickness = 3;
  520. const int kTrackStart = 1;
  521. const int kTrackLength = 100;
  522. ScrollbarLayerImplBase* scrollbar_layer_impl = nullptr;
  523. {
  524. scoped_refptr<Layer> root = Layer::Create();
  525. scoped_refptr<Layer> child = Layer::Create();
  526. scoped_refptr<ScrollbarLayerBase> scrollbar_layer =
  527. SolidColorScrollbarLayer::Create(ScrollbarOrientation::HORIZONTAL,
  528. kThumbThickness, kTrackStart, false);
  529. root->AddChild(child);
  530. root->AddChild(scrollbar_layer);
  531. layer_tree_host_->SetRootLayer(root);
  532. layer_tree_host_->BuildPropertyTreesForTesting();
  533. auto* root_impl = layer_tree_host_->CommitAndCreateLayerImplTree();
  534. scrollbar_layer_impl = static_cast<SolidColorScrollbarLayerImpl*>(
  535. root_impl->layer_tree_impl()->LayerById(scrollbar_layer->id()));
  536. }
  537. scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
  538. scrollbar_layer_impl->SetCurrentPos(10.f);
  539. scrollbar_layer_impl->SetClipLayerLength(200 / 3.f);
  540. scrollbar_layer_impl->SetScrollLayerLength(100 + 200 / 3.f);
  541. // Thickness should be overridden to 3.
  542. {
  543. auto render_pass = viz::CompositorRenderPass::Create();
  544. AppendQuadsData data;
  545. scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
  546. const auto& quads = render_pass->quad_list;
  547. ASSERT_EQ(1u, quads.size());
  548. EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material);
  549. EXPECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect);
  550. }
  551. // For solid color scrollbars, position and size should reflect the
  552. // current viewport state.
  553. scrollbar_layer_impl->SetClipLayerLength(25.f);
  554. scrollbar_layer_impl->SetScrollLayerLength(125.f);
  555. {
  556. auto render_pass = viz::CompositorRenderPass::Create();
  557. AppendQuadsData data;
  558. scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
  559. const auto& quads = render_pass->quad_list;
  560. ASSERT_EQ(1u, quads.size());
  561. EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material);
  562. EXPECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect);
  563. }
  564. // We shouldn't attempt div-by-zero when the maximum is zero.
  565. scrollbar_layer_impl->SetCurrentPos(0.f);
  566. scrollbar_layer_impl->SetClipLayerLength(125.f);
  567. scrollbar_layer_impl->SetScrollLayerLength(125.f);
  568. {
  569. auto render_pass = viz::CompositorRenderPass::Create();
  570. AppendQuadsData data;
  571. scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
  572. const auto& quads = render_pass->quad_list;
  573. ASSERT_EQ(1u, quads.size());
  574. EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material);
  575. EXPECT_EQ(gfx::Rect(1, 0, 98, 3), quads.front()->rect);
  576. }
  577. }
  578. TEST_F(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
  579. const int kThumbThickness = 3;
  580. const int kTrackStart = 0;
  581. const int kTrackLength = 10;
  582. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  583. scoped_refptr<Layer> scroll_layer = Layer::Create();
  584. scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
  585. scoped_refptr<Layer> child1 = Layer::Create();
  586. const bool kIsLeftSideVerticalScrollbar = false;
  587. scoped_refptr<SolidColorScrollbarLayer> child2 =
  588. SolidColorScrollbarLayer::Create(ScrollbarOrientation::HORIZONTAL,
  589. kThumbThickness, kTrackStart,
  590. kIsLeftSideVerticalScrollbar);
  591. child2->SetScrollElementId(scroll_layer->element_id());
  592. scroll_layer->AddChild(child1);
  593. scroll_layer->InsertChild(child2, 1);
  594. layer_tree_root->AddChild(scroll_layer);
  595. layer_tree_host_->SetRootLayer(layer_tree_root);
  596. // Choose layer bounds to give max_scroll_offset = (8, 8).
  597. layer_tree_root->SetBounds(gfx::Size(2, 2));
  598. scroll_layer->SetScrollable(gfx::Size(2, 2));
  599. scroll_layer->SetBounds(gfx::Size(10, 10));
  600. layer_tree_host_->UpdateLayers();
  601. LayerImpl* layer_impl_tree_root =
  602. layer_tree_host_->CommitAndCreateLayerImplTree();
  603. LayerImpl* scroll_layer_impl =
  604. layer_impl_tree_root->layer_tree_impl()->LayerById(scroll_layer->id());
  605. auto* scrollbar_layer_impl = static_cast<ScrollbarLayerImplBase*>(
  606. scroll_layer_impl->layer_tree_impl()->LayerById(child2->id()));
  607. scroll_layer_impl->ScrollBy(gfx::Vector2dF(4.f, 0.f));
  608. scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
  609. scrollbar_layer_impl->SetCurrentPos(4.f);
  610. DCHECK(layer_tree_host_->active_tree()->ScrollbarGeometriesNeedUpdate());
  611. layer_tree_host_->active_tree()->UpdateScrollbarGeometries();
  612. {
  613. auto render_pass = viz::CompositorRenderPass::Create();
  614. AppendQuadsData data;
  615. scrollbar_layer_impl->AppendQuads(render_pass.get(), &data);
  616. const auto& quads = render_pass->quad_list;
  617. ASSERT_EQ(1u, quads.size());
  618. EXPECT_EQ(viz::DrawQuad::Material::kSolidColor, quads.front()->material);
  619. EXPECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect);
  620. }
  621. }
  622. TEST_F(ScrollbarLayerTest, ScrollbarLayerOpacity) {
  623. const int kThumbThickness = 3;
  624. const int kTrackStart = 0;
  625. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  626. scoped_refptr<Layer> scroll_layer = Layer::Create();
  627. scroll_layer->SetElementId(ElementId(200));
  628. scoped_refptr<Layer> child1 = Layer::Create();
  629. scoped_refptr<SolidColorScrollbarLayer> scrollbar_layer;
  630. const bool kIsLeftSideVerticalScrollbar = false;
  631. scrollbar_layer = SolidColorScrollbarLayer::Create(
  632. ScrollbarOrientation::HORIZONTAL, kThumbThickness, kTrackStart,
  633. kIsLeftSideVerticalScrollbar);
  634. scrollbar_layer->SetScrollElementId(scroll_layer->element_id());
  635. scrollbar_layer->SetElementId(ElementId(300));
  636. scroll_layer->AddChild(child1);
  637. scroll_layer->InsertChild(scrollbar_layer, 1);
  638. layer_tree_root->AddChild(scroll_layer);
  639. layer_tree_host_->SetRootLayer(layer_tree_root);
  640. // Choose layer bounds to give max_scroll_offset = (8, 8).
  641. layer_tree_root->SetBounds(gfx::Size(2, 2));
  642. scroll_layer->SetBounds(gfx::Size(10, 10));
  643. // Building property trees twice shouldn't change the size of
  644. // PropertyTrees::always_use_active_tree_opacity_effect_ids.
  645. layer_tree_host_->BuildPropertyTreesForTesting();
  646. layer_tree_host_->property_trees()->set_needs_rebuild(true);
  647. layer_tree_host_->BuildPropertyTreesForTesting();
  648. // A solid color scrollbar layer's opacity is initialized to 0 on main thread
  649. layer_tree_host_->UpdateLayers();
  650. const EffectNode* node =
  651. layer_tree_host_->property_trees()->effect_tree().Node(
  652. scrollbar_layer->effect_tree_index());
  653. EXPECT_EQ(node->opacity, 0.f);
  654. // This tests that the initial opacity(0) of the scrollbar gets pushed onto
  655. // the pending tree and then onto the active tree.
  656. LayerTreeHostImpl* host_impl = layer_tree_host_->host_impl();
  657. host_impl->CreatePendingTree();
  658. LayerImpl* layer_impl_tree_root =
  659. layer_tree_host_->CommitAndCreatePendingTree();
  660. LayerTreeImpl* layer_tree_impl = layer_impl_tree_root->layer_tree_impl();
  661. EXPECT_TRUE(layer_tree_impl->IsPendingTree());
  662. node = layer_tree_impl->property_trees()->effect_tree().Node(
  663. scrollbar_layer->effect_tree_index());
  664. EXPECT_EQ(node->opacity, 0.f);
  665. host_impl->ActivateSyncTree();
  666. layer_tree_impl = host_impl->active_tree();
  667. node = layer_tree_impl->property_trees()->effect_tree().Node(
  668. scrollbar_layer->effect_tree_index());
  669. EXPECT_EQ(node->opacity, 0.f);
  670. // This tests that activation does not change the opacity of scrollbar layer.
  671. ScrollbarLayerImplBase* scrollbar_layer_impl =
  672. static_cast<ScrollbarLayerImplBase*>(
  673. layer_tree_impl->LayerById(scrollbar_layer->id()));
  674. scrollbar_layer_impl->SetOverlayScrollbarLayerOpacityAnimated(0.25f);
  675. host_impl->CreatePendingTree();
  676. layer_impl_tree_root = layer_tree_host_->CommitAndCreatePendingTree();
  677. layer_tree_impl = layer_impl_tree_root->layer_tree_impl();
  678. EXPECT_TRUE(layer_tree_impl->IsPendingTree());
  679. node = layer_tree_impl->property_trees()->effect_tree().Node(
  680. scrollbar_layer->effect_tree_index());
  681. EXPECT_EQ(node->opacity, 0.f);
  682. host_impl->ActivateSyncTree();
  683. layer_tree_impl = host_impl->active_tree();
  684. node = layer_tree_impl->property_trees()->effect_tree().Node(
  685. scrollbar_layer->effect_tree_index());
  686. EXPECT_EQ(node->opacity, 0.25f);
  687. }
  688. TEST_F(AuraScrollbarLayerTest, ScrollbarLayerPushProperties) {
  689. // Pushing changed bounds of scroll layer can lead to calling
  690. // OnOpacityAnimated on scrollbar layer which means OnOpacityAnimated should
  691. // be independent of scrollbar layer's properties as scrollbar layer can push
  692. // its properties after scroll layer.
  693. const int kThumbThickness = 3;
  694. const int kTrackStart = 0;
  695. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  696. scoped_refptr<Layer> scroll_layer = Layer::Create();
  697. scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
  698. scoped_refptr<Layer> child1 = Layer::Create();
  699. const bool kIsLeftSideVerticalScrollbar = false;
  700. scoped_refptr<SolidColorScrollbarLayer> scrollbar_layer =
  701. SolidColorScrollbarLayer::Create(ScrollbarOrientation::HORIZONTAL,
  702. kThumbThickness, kTrackStart,
  703. kIsLeftSideVerticalScrollbar);
  704. scrollbar_layer->SetScrollElementId(scroll_layer->element_id());
  705. scroll_layer->AddChild(child1);
  706. scroll_layer->InsertChild(scrollbar_layer, 1);
  707. layer_tree_root->AddChild(scroll_layer);
  708. layer_tree_host_->SetRootLayer(layer_tree_root);
  709. layer_tree_root->SetBounds(gfx::Size(2, 2));
  710. scroll_layer->SetBounds(gfx::Size(10, 10));
  711. scroll_layer->SetScrollable(layer_tree_root->bounds());
  712. layer_tree_host_->UpdateLayers();
  713. LayerTreeHostImpl* host_impl = layer_tree_host_->host_impl();
  714. host_impl->CreatePendingTree();
  715. layer_tree_host_->CommitAndCreatePendingTree();
  716. host_impl->ActivateSyncTree();
  717. EXPECT_TRUE(host_impl->ScrollbarAnimationControllerForElementId(
  718. scroll_layer->element_id()));
  719. scroll_layer->SetBounds(gfx::Size(20, 20));
  720. scroll_layer->SetForceRenderSurfaceForTesting(true);
  721. layer_tree_host_->UpdateLayers();
  722. host_impl->CreatePendingTree();
  723. layer_tree_host_->CommitAndCreatePendingTree();
  724. host_impl->ActivateSyncTree();
  725. const EffectNode* node =
  726. host_impl->active_tree()->property_trees()->effect_tree().Node(
  727. scrollbar_layer->effect_tree_index());
  728. EXPECT_EQ(node->opacity, 1.f);
  729. }
  730. TEST_F(ScrollbarLayerTest, SubPixelCanScrollOrientation) {
  731. gfx::Size viewport_size(980, 980);
  732. LayerTreeImplTestBase impl;
  733. LayerImpl* scroll_layer = impl.AddLayer<LayerImpl>();
  734. scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
  735. const int kTrackStart = 0;
  736. const int kThumbThickness = 10;
  737. const bool kIsLeftSideVerticalScrollbar = false;
  738. SolidColorScrollbarLayerImpl* scrollbar_layer =
  739. impl.AddLayer<SolidColorScrollbarLayerImpl>(
  740. ScrollbarOrientation::HORIZONTAL, kThumbThickness, kTrackStart,
  741. kIsLeftSideVerticalScrollbar);
  742. scrollbar_layer->SetScrollElementId(scroll_layer->element_id());
  743. scroll_layer->SetBounds(gfx::Size(980, 980));
  744. CopyProperties(impl.root_layer(), scroll_layer);
  745. CreateTransformNode(scroll_layer);
  746. CreateScrollNode(scroll_layer, gfx::Size(980, 980));
  747. CopyProperties(scroll_layer, scrollbar_layer);
  748. DCHECK(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  749. impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
  750. impl.CalcDrawProps(viewport_size);
  751. // Fake clip layer length to scrollbar to mock rounding error.
  752. scrollbar_layer->SetClipLayerLength(979.999939f);
  753. impl.CalcDrawProps(viewport_size);
  754. EXPECT_FALSE(scrollbar_layer->CanScrollOrientation());
  755. // Fake clip layer length to scrollable.
  756. scrollbar_layer->SetClipLayerLength(979.0f);
  757. impl.CalcDrawProps(viewport_size);
  758. EXPECT_TRUE(scrollbar_layer->CanScrollOrientation());
  759. }
  760. TEST_F(ScrollbarLayerTest, LayerChangesAffectingScrollbarGeometries) {
  761. LayerTreeImplTestBase impl;
  762. SetupViewport(impl.root_layer(), gfx::Size(), gfx::Size(900, 900));
  763. auto* scroll_layer = impl.OuterViewportScrollLayer();
  764. EXPECT_FALSE(GetScrollNode(scroll_layer)->scrollable);
  765. const int kTrackStart = 0;
  766. const int kThumbThickness = 10;
  767. const bool kIsLeftSideVerticalScrollbar = false;
  768. SolidColorScrollbarLayerImpl* scrollbar_layer =
  769. impl.AddLayer<SolidColorScrollbarLayerImpl>(
  770. ScrollbarOrientation::HORIZONTAL, kThumbThickness, kTrackStart,
  771. kIsLeftSideVerticalScrollbar);
  772. scrollbar_layer->SetScrollElementId(scroll_layer->element_id());
  773. EXPECT_TRUE(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  774. impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
  775. GetScrollNode(scroll_layer)->container_bounds = gfx::Size(900, 900);
  776. scroll_layer->SetBounds(gfx::Size(900, 900));
  777. scroll_layer->UpdateScrollable();
  778. EXPECT_FALSE(GetScrollNode(scroll_layer)->scrollable);
  779. // If the scroll layer is not scrollable, the bounds and the container bounds
  780. // do not affect scrollbar geometries.
  781. EXPECT_FALSE(
  782. impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  783. // Changing scrollable to true should require an update.
  784. GetScrollNode(scroll_layer)->scrollable = true;
  785. scroll_layer->UpdateScrollable();
  786. EXPECT_TRUE(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  787. impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
  788. scroll_layer->SetBounds(gfx::Size(980, 980));
  789. // Changes to the bounds should also require an update.
  790. EXPECT_TRUE(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  791. impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
  792. // Changes to the container bounds should require an update.
  793. GetScrollNode(scroll_layer)->container_bounds = gfx::Size(500, 500);
  794. scroll_layer->UpdateScrollable();
  795. EXPECT_TRUE(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  796. impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
  797. // Not changing the current value should not require an update.
  798. scroll_layer->SetBounds(gfx::Size(980, 980));
  799. EXPECT_FALSE(
  800. impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  801. scroll_layer->UpdateScrollable();
  802. EXPECT_FALSE(
  803. impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  804. // Changing scrollable to false should require an update.
  805. GetScrollNode(scroll_layer)->scrollable = false;
  806. scroll_layer->UpdateScrollable();
  807. EXPECT_TRUE(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  808. impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
  809. }
  810. TEST_F(ScrollbarLayerTest, UpdateScrollbarGeometriesScrollNodeOnContainer) {
  811. LayerTreeImplTestBase impl;
  812. LayerImpl* scroll_layer = impl.AddLayer<LayerImpl>();
  813. scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
  814. scroll_layer->SetBounds(gfx::Size(100, 100));
  815. CopyProperties(impl.root_layer(), scroll_layer);
  816. CreateTransformNode(scroll_layer);
  817. // In CompositeAfterPaint, the scroll node is associated with the scroll
  818. // container layer. Its |container_bounds| is the same as the bounds of the
  819. // layer, and its |bounds| is the bounds of the scrolling contents.
  820. CreateScrollNode(scroll_layer, gfx::Size(100, 100)).bounds =
  821. gfx::Size(1000, 1000);
  822. EXPECT_TRUE(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  823. impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
  824. GetScrollNode(scroll_layer)->bounds = gfx::Size(1000, 2000);
  825. scroll_layer->UpdateScrollable();
  826. EXPECT_TRUE(impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  827. impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
  828. scroll_layer->UpdateScrollable();
  829. EXPECT_FALSE(
  830. impl.host_impl()->active_tree()->ScrollbarGeometriesNeedUpdate());
  831. impl.host_impl()->active_tree()->UpdateScrollbarGeometries();
  832. }
  833. TEST_F(AuraScrollbarLayerTest, ScrollbarLayerCreateAfterSetScrollable) {
  834. // Scrollbar Layer can be created after SetScrollable is called and in a
  835. // separate commit. Ensure we do not missing the DidRequestShowFromMainThread
  836. // call.
  837. const int kThumbThickness = 3;
  838. const int kTrackStart = 0;
  839. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  840. scoped_refptr<Layer> scroll_layer = Layer::Create();
  841. scroll_layer->SetElementId(LayerIdToElementIdForTesting(scroll_layer->id()));
  842. scoped_refptr<Layer> child1 = Layer::Create();
  843. const bool kIsLeftSideVerticalScrollbar = false;
  844. scroll_layer->AddChild(child1);
  845. layer_tree_root->AddChild(scroll_layer);
  846. layer_tree_host_->SetRootLayer(layer_tree_root);
  847. layer_tree_root->SetBounds(gfx::Size(2, 2));
  848. scroll_layer->SetBounds(gfx::Size(10, 10));
  849. scroll_layer->SetScrollable(layer_tree_root->bounds());
  850. layer_tree_host_->UpdateLayers();
  851. LayerTreeHostImpl* host_impl = layer_tree_host_->host_impl();
  852. host_impl->CreatePendingTree();
  853. layer_tree_host_->CommitAndCreatePendingTree();
  854. host_impl->ActivateSyncTree();
  855. scoped_refptr<SolidColorScrollbarLayer> scrollbar_layer =
  856. SolidColorScrollbarLayer::Create(ScrollbarOrientation::HORIZONTAL,
  857. kThumbThickness, kTrackStart,
  858. kIsLeftSideVerticalScrollbar);
  859. scrollbar_layer->SetScrollElementId(scroll_layer->element_id());
  860. scroll_layer->InsertChild(scrollbar_layer, 1);
  861. layer_tree_host_->UpdateLayers();
  862. host_impl->CreatePendingTree();
  863. layer_tree_host_->CommitAndCreatePendingTree();
  864. host_impl->ActivateSyncTree();
  865. EXPECT_TRUE(host_impl->ScrollbarAnimationControllerForElementId(
  866. scroll_layer->element_id()));
  867. const EffectNode* node =
  868. host_impl->active_tree()->property_trees()->effect_tree().Node(
  869. scrollbar_layer->effect_tree_index());
  870. EXPECT_EQ(node->opacity, 1.f);
  871. }
  872. class ScrollbarLayerSolidColorThumbTest : public testing::Test {
  873. public:
  874. ScrollbarLayerSolidColorThumbTest() {
  875. LayerTreeSettings layer_tree_settings;
  876. host_impl_ = std::make_unique<FakeLayerTreeHostImpl>(
  877. layer_tree_settings, &task_runner_provider_, &task_graph_runner_);
  878. const int kThumbThickness = 3;
  879. const int kTrackStart = 0;
  880. const bool kIsLeftSideVerticalScrollbar = false;
  881. horizontal_scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create(
  882. host_impl_->active_tree(), 1, ScrollbarOrientation::HORIZONTAL,
  883. kThumbThickness, kTrackStart, kIsLeftSideVerticalScrollbar);
  884. vertical_scrollbar_layer_ = SolidColorScrollbarLayerImpl::Create(
  885. host_impl_->active_tree(), 2, ScrollbarOrientation::VERTICAL,
  886. kThumbThickness, kTrackStart, kIsLeftSideVerticalScrollbar);
  887. }
  888. protected:
  889. FakeImplTaskRunnerProvider task_runner_provider_;
  890. TestTaskGraphRunner task_graph_runner_;
  891. std::unique_ptr<FakeLayerTreeHostImpl> host_impl_;
  892. std::unique_ptr<SolidColorScrollbarLayerImpl> horizontal_scrollbar_layer_;
  893. std::unique_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer_;
  894. };
  895. TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbLength) {
  896. horizontal_scrollbar_layer_->SetCurrentPos(0);
  897. // Simple case - one third of the scrollable area is visible, so the thumb
  898. // should be one third as long as the track.
  899. horizontal_scrollbar_layer_->SetClipLayerLength(5.f);
  900. horizontal_scrollbar_layer_->SetScrollLayerLength(15.f);
  901. horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
  902. EXPECT_EQ(33, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
  903. // The thumb's length should never be less than its thickness.
  904. horizontal_scrollbar_layer_->SetClipLayerLength(0.01f);
  905. horizontal_scrollbar_layer_->SetScrollLayerLength(15.f);
  906. horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
  907. EXPECT_EQ(3, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
  908. }
  909. TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbPosition) {
  910. horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
  911. horizontal_scrollbar_layer_->SetCurrentPos(0.f);
  912. horizontal_scrollbar_layer_->SetClipLayerLength(12.f);
  913. horizontal_scrollbar_layer_->SetScrollLayerLength(112.f);
  914. EXPECT_EQ(0, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
  915. EXPECT_EQ(10, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
  916. horizontal_scrollbar_layer_->SetCurrentPos(100);
  917. // The thumb is 10px long and the track is 100px, so the maximum thumb
  918. // position is 90px.
  919. EXPECT_EQ(90, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
  920. horizontal_scrollbar_layer_->SetCurrentPos(80);
  921. // The scroll position is 80% of the maximum, so the thumb's position should
  922. // be at 80% of its maximum or 72px.
  923. EXPECT_EQ(72, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
  924. }
  925. TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) {
  926. SolidColorScrollbarLayerImpl* layers[2] =
  927. { horizontal_scrollbar_layer_.get(), vertical_scrollbar_layer_.get() };
  928. for (size_t i = 0; i < 2; ++i) {
  929. layers[i]->SetCurrentPos(25.f);
  930. layers[i]->SetClipLayerLength(25.f);
  931. layers[i]->SetScrollLayerLength(125.f);
  932. }
  933. layers[0]->SetBounds(gfx::Size(100, 3));
  934. layers[1]->SetBounds(gfx::Size(3, 100));
  935. EXPECT_EQ(gfx::Rect(20, 0, 20, 3),
  936. horizontal_scrollbar_layer_->ComputeThumbQuadRect());
  937. EXPECT_EQ(gfx::Rect(0, 20, 3, 20),
  938. vertical_scrollbar_layer_->ComputeThumbQuadRect());
  939. horizontal_scrollbar_layer_->SetVerticalAdjust(10.f);
  940. vertical_scrollbar_layer_->SetVerticalAdjust(10.f);
  941. // The vertical adjustment factor has two effects:
  942. // 1.) Moves the horizontal scrollbar down
  943. // 2.) Increases the vertical scrollbar's effective track length which both
  944. // increases the thumb's length and its position within the track.
  945. EXPECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f),
  946. horizontal_scrollbar_layer_->ComputeThumbQuadRect());
  947. EXPECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f),
  948. vertical_scrollbar_layer_->ComputeThumbQuadRect());
  949. }
  950. class ScrollbarLayerTestResourceCreationAndRelease : public ScrollbarLayerTest {
  951. public:
  952. void TestResourceUpload(int num_updates,
  953. size_t expected_resources,
  954. int expected_created,
  955. int expected_deleted,
  956. bool use_solid_color_scrollbar) {
  957. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  958. scoped_refptr<Layer> content_layer = Layer::Create();
  959. scoped_refptr<ScrollbarLayerBase> scrollbar_layer;
  960. if (use_solid_color_scrollbar) {
  961. const int kThumbThickness = 3;
  962. const int kTrackStart = 0;
  963. const bool kIsLeftSideVerticalScrollbar = false;
  964. scrollbar_layer = SolidColorScrollbarLayer::Create(
  965. ScrollbarOrientation::HORIZONTAL, kThumbThickness, kTrackStart,
  966. kIsLeftSideVerticalScrollbar);
  967. } else {
  968. auto scrollbar = base::MakeRefCounted<FakeScrollbar>();
  969. scrollbar->set_has_thumb(true);
  970. scrollbar_layer = PaintedScrollbarLayer::Create(std::move(scrollbar));
  971. }
  972. scrollbar_layer->SetScrollElementId(layer_tree_root->element_id());
  973. layer_tree_root->AddChild(content_layer);
  974. layer_tree_root->AddChild(scrollbar_layer);
  975. layer_tree_host_->SetRootLayer(layer_tree_root);
  976. UpdateDrawProperties(layer_tree_host_.get());
  977. scrollbar_layer->SetIsDrawable(true);
  978. scrollbar_layer->SetBounds(gfx::Size(100, 100));
  979. layer_tree_root->SetScrollable(gfx::Size(100, 200));
  980. layer_tree_root->SetScrollOffset(gfx::PointF(10, 20));
  981. layer_tree_root->SetBounds(gfx::Size(100, 200));
  982. content_layer->SetBounds(gfx::Size(100, 200));
  983. testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
  984. EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
  985. for (int update_counter = 0; update_counter < num_updates; update_counter++)
  986. scrollbar_layer->Update();
  987. // A non-solid-color scrollbar should have requested two textures.
  988. EXPECT_EQ(expected_resources, fake_ui_resource_manager_->UIResourceCount());
  989. EXPECT_EQ(expected_created,
  990. fake_ui_resource_manager_->TotalUIResourceCreated());
  991. EXPECT_EQ(expected_deleted,
  992. fake_ui_resource_manager_->TotalUIResourceDeleted());
  993. testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
  994. }
  995. };
  996. TEST_F(ScrollbarLayerTestResourceCreationAndRelease, ResourceUpload) {
  997. bool use_solid_color_scrollbars = false;
  998. TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
  999. int num_updates[3] = {1, 5, 10};
  1000. int created = 0;
  1001. int deleted = 0;
  1002. for (int j = 0; j < 3; j++) {
  1003. created += num_updates[j] * 2;
  1004. deleted = created - 2;
  1005. TestResourceUpload(num_updates[j], 2, created, deleted,
  1006. use_solid_color_scrollbars);
  1007. }
  1008. }
  1009. TEST_F(ScrollbarLayerTestResourceCreationAndRelease,
  1010. SolidColorNoResourceUpload) {
  1011. bool use_solid_color_scrollbars = true;
  1012. TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
  1013. TestResourceUpload(1, 0, 0, 0, use_solid_color_scrollbars);
  1014. }
  1015. TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
  1016. gfx::Point scrollbar_location(0, 185);
  1017. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  1018. scoped_refptr<Layer> content_layer = Layer::Create();
  1019. scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
  1020. FakePaintedScrollbarLayer::Create(false, true,
  1021. layer_tree_root->element_id());
  1022. layer_tree_root->AddChild(content_layer);
  1023. layer_tree_root->AddChild(scrollbar_layer);
  1024. layer_tree_host_->SetRootLayer(layer_tree_root);
  1025. UpdateDrawProperties(layer_tree_host_.get());
  1026. scrollbar_layer->SetIsDrawable(true);
  1027. scrollbar_layer->SetBounds(gfx::Size(100, 15));
  1028. scrollbar_layer->SetPosition(gfx::PointF(scrollbar_location));
  1029. layer_tree_root->SetBounds(gfx::Size(100, 200));
  1030. content_layer->SetBounds(gfx::Size(100, 200));
  1031. testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
  1032. EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
  1033. size_t resource_count;
  1034. int expected_created, expected_deleted;
  1035. resource_count = 2;
  1036. expected_created = 2;
  1037. expected_deleted = 0;
  1038. EXPECT_TRUE(scrollbar_layer->Update());
  1039. EXPECT_NE(0, scrollbar_layer->track_resource_id());
  1040. EXPECT_NE(0, scrollbar_layer->thumb_resource_id());
  1041. EXPECT_EQ(resource_count, fake_ui_resource_manager_->UIResourceCount());
  1042. EXPECT_EQ(expected_created,
  1043. fake_ui_resource_manager_->TotalUIResourceCreated());
  1044. EXPECT_EQ(expected_deleted,
  1045. fake_ui_resource_manager_->TotalUIResourceDeleted());
  1046. resource_count = 0;
  1047. expected_created = 2;
  1048. expected_deleted = 2;
  1049. scrollbar_layer->SetBounds(gfx::Size(0, 0));
  1050. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0));
  1051. EXPECT_TRUE(scrollbar_layer->Update());
  1052. EXPECT_EQ(0, scrollbar_layer->track_resource_id());
  1053. EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
  1054. EXPECT_EQ(resource_count, fake_ui_resource_manager_->UIResourceCount());
  1055. EXPECT_EQ(expected_created,
  1056. fake_ui_resource_manager_->TotalUIResourceCreated());
  1057. EXPECT_EQ(expected_deleted,
  1058. fake_ui_resource_manager_->TotalUIResourceDeleted());
  1059. resource_count = 0;
  1060. expected_created = 2;
  1061. expected_deleted = 2;
  1062. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0));
  1063. EXPECT_FALSE(scrollbar_layer->Update());
  1064. EXPECT_EQ(0, scrollbar_layer->track_resource_id());
  1065. EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
  1066. EXPECT_EQ(resource_count, fake_ui_resource_manager_->UIResourceCount());
  1067. EXPECT_EQ(expected_created,
  1068. fake_ui_resource_manager_->TotalUIResourceCreated());
  1069. EXPECT_EQ(expected_deleted,
  1070. fake_ui_resource_manager_->TotalUIResourceDeleted());
  1071. resource_count = 2;
  1072. expected_created = 4;
  1073. expected_deleted = 2;
  1074. scrollbar_layer->SetBounds(gfx::Size(100, 15));
  1075. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
  1076. EXPECT_TRUE(scrollbar_layer->Update());
  1077. EXPECT_NE(0, scrollbar_layer->track_resource_id());
  1078. EXPECT_NE(0, scrollbar_layer->thumb_resource_id());
  1079. EXPECT_EQ(resource_count, fake_ui_resource_manager_->UIResourceCount());
  1080. EXPECT_EQ(expected_created,
  1081. fake_ui_resource_manager_->TotalUIResourceCreated());
  1082. EXPECT_EQ(expected_deleted,
  1083. fake_ui_resource_manager_->TotalUIResourceDeleted());
  1084. resource_count = 1;
  1085. expected_created = 5;
  1086. expected_deleted = 4;
  1087. scrollbar_layer->fake_scrollbar()->set_has_thumb(false);
  1088. EXPECT_TRUE(scrollbar_layer->Update());
  1089. EXPECT_NE(0, scrollbar_layer->track_resource_id());
  1090. EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
  1091. EXPECT_EQ(resource_count, fake_ui_resource_manager_->UIResourceCount());
  1092. EXPECT_EQ(expected_created,
  1093. fake_ui_resource_manager_->TotalUIResourceCreated());
  1094. EXPECT_EQ(expected_deleted,
  1095. fake_ui_resource_manager_->TotalUIResourceDeleted());
  1096. resource_count = 0;
  1097. expected_created = 5;
  1098. expected_deleted = 5;
  1099. scrollbar_layer->SetBounds(gfx::Size(0, 0));
  1100. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0));
  1101. EXPECT_TRUE(scrollbar_layer->Update());
  1102. EXPECT_EQ(0, scrollbar_layer->track_resource_id());
  1103. EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
  1104. EXPECT_EQ(resource_count, fake_ui_resource_manager_->UIResourceCount());
  1105. EXPECT_EQ(expected_created,
  1106. fake_ui_resource_manager_->TotalUIResourceCreated());
  1107. EXPECT_EQ(expected_deleted,
  1108. fake_ui_resource_manager_->TotalUIResourceDeleted());
  1109. resource_count = 2;
  1110. expected_created = 7;
  1111. expected_deleted = 5;
  1112. scrollbar_layer->SetBounds(gfx::Size(100, 15));
  1113. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
  1114. scrollbar_layer->fake_scrollbar()->set_has_thumb(true);
  1115. EXPECT_TRUE(scrollbar_layer->Update());
  1116. EXPECT_NE(0, scrollbar_layer->track_resource_id());
  1117. EXPECT_NE(0, scrollbar_layer->thumb_resource_id());
  1118. resource_count = 2;
  1119. expected_created = 9;
  1120. expected_deleted = 7;
  1121. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0));
  1122. EXPECT_TRUE(scrollbar_layer->Update());
  1123. EXPECT_NE(0, scrollbar_layer->track_resource_id());
  1124. EXPECT_NE(0, scrollbar_layer->thumb_resource_id());
  1125. EXPECT_EQ(resource_count, fake_ui_resource_manager_->UIResourceCount());
  1126. EXPECT_EQ(expected_created,
  1127. fake_ui_resource_manager_->TotalUIResourceCreated());
  1128. EXPECT_EQ(expected_deleted,
  1129. fake_ui_resource_manager_->TotalUIResourceDeleted());
  1130. resource_count = 1;
  1131. expected_created = 10;
  1132. expected_deleted = 9;
  1133. scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
  1134. scrollbar_layer->fake_scrollbar()->set_has_thumb(false);
  1135. scrollbar_layer->SetBounds(gfx::Size(90, 15));
  1136. EXPECT_TRUE(scrollbar_layer->Update());
  1137. EXPECT_EQ(resource_count, fake_ui_resource_manager_->UIResourceCount());
  1138. EXPECT_EQ(expected_created,
  1139. fake_ui_resource_manager_->TotalUIResourceCreated());
  1140. EXPECT_EQ(expected_deleted,
  1141. fake_ui_resource_manager_->TotalUIResourceDeleted());
  1142. EXPECT_EQ(gfx::Size(90, 15), fake_ui_resource_manager_->ui_resource_size(
  1143. scrollbar_layer->track_resource_id()));
  1144. // Simulate commit to compositor thread.
  1145. scrollbar_layer->PushPropertiesTo(
  1146. scrollbar_layer->CreateLayerImpl(layer_tree_host_->active_tree()).get(),
  1147. *layer_tree_host_->GetPendingCommitState(),
  1148. layer_tree_host_->GetThreadUnsafeCommitState());
  1149. scrollbar_layer->fake_scrollbar()->set_needs_repaint_thumb(false);
  1150. scrollbar_layer->fake_scrollbar()->set_needs_repaint_track(false);
  1151. EXPECT_FALSE(scrollbar_layer->Update());
  1152. EXPECT_NE(0, scrollbar_layer->track_resource_id());
  1153. EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
  1154. EXPECT_EQ(resource_count, fake_ui_resource_manager_->UIResourceCount());
  1155. EXPECT_EQ(expected_created,
  1156. fake_ui_resource_manager_->TotalUIResourceCreated());
  1157. EXPECT_EQ(expected_deleted,
  1158. fake_ui_resource_manager_->TotalUIResourceDeleted());
  1159. testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
  1160. }
  1161. class ScaledScrollbarLayerTestResourceCreation : public ScrollbarLayerTest {
  1162. public:
  1163. void TestResourceUpload(float test_scale) {
  1164. gfx::Point scrollbar_location(0, 185);
  1165. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  1166. scoped_refptr<Layer> content_layer = Layer::Create();
  1167. scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
  1168. FakePaintedScrollbarLayer::Create(false, true,
  1169. layer_tree_root->element_id());
  1170. layer_tree_root->AddChild(content_layer);
  1171. layer_tree_root->AddChild(scrollbar_layer);
  1172. layer_tree_host_->SetRootLayer(layer_tree_root);
  1173. scrollbar_layer->SetIsDrawable(true);
  1174. scrollbar_layer->SetBounds(gfx::Size(100, 15));
  1175. scrollbar_layer->SetPosition(gfx::PointF(scrollbar_location));
  1176. layer_tree_root->SetBounds(gfx::Size(100, 200));
  1177. content_layer->SetBounds(gfx::Size(100, 200));
  1178. EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
  1179. UpdateDrawProperties(layer_tree_host_.get());
  1180. layer_tree_host_->SetViewportRectAndScale(
  1181. layer_tree_host_->device_viewport_rect(), test_scale,
  1182. layer_tree_host_->local_surface_id_from_parent());
  1183. scrollbar_layer->Update();
  1184. // Verify that we have not generated any content uploads that are larger
  1185. // than their destination textures.
  1186. gfx::Size track_size = fake_ui_resource_manager_->ui_resource_size(
  1187. scrollbar_layer->track_resource_id());
  1188. gfx::Size thumb_size = fake_ui_resource_manager_->ui_resource_size(
  1189. scrollbar_layer->thumb_resource_id());
  1190. EXPECT_LE(track_size.width(),
  1191. scrollbar_layer->internal_content_bounds().width());
  1192. EXPECT_LE(track_size.height(),
  1193. scrollbar_layer->internal_content_bounds().height());
  1194. EXPECT_LE(thumb_size.width(),
  1195. scrollbar_layer->internal_content_bounds().width());
  1196. EXPECT_LE(thumb_size.height(),
  1197. scrollbar_layer->internal_content_bounds().height());
  1198. }
  1199. };
  1200. TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
  1201. // Pick a test scale that moves the scrollbar's (non-zero) position to
  1202. // a non-pixel-aligned location.
  1203. TestResourceUpload(.041f);
  1204. TestResourceUpload(1.41f);
  1205. TestResourceUpload(4.1f);
  1206. // Try something extreme to be larger than max texture size, and make it a
  1207. // non-integer for funsies.
  1208. scoped_refptr<viz::TestContextProvider> context =
  1209. viz::TestContextProvider::Create();
  1210. // Keep the max texture size reasonable so we don't OOM on low end devices
  1211. // (crbug.com/642333).
  1212. context->UnboundTestContextGL()->set_max_texture_size(512);
  1213. context->BindToCurrentThread();
  1214. int max_texture_size = 0;
  1215. context->ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
  1216. EXPECT_EQ(512, max_texture_size);
  1217. TestResourceUpload(max_texture_size / 9.9f);
  1218. }
  1219. class ScaledScrollbarLayerTestScaledRasterization : public ScrollbarLayerTest {
  1220. public:
  1221. void TestScale(const gfx::Rect& scrollbar_rect, float test_scale) {
  1222. bool paint_during_update = true;
  1223. bool has_thumb = false;
  1224. scoped_refptr<Layer> layer_tree_root = Layer::Create();
  1225. scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
  1226. FakePaintedScrollbarLayer::Create(paint_during_update, has_thumb,
  1227. layer_tree_root->element_id());
  1228. layer_tree_root->AddChild(scrollbar_layer);
  1229. layer_tree_host_->SetRootLayer(layer_tree_root);
  1230. scrollbar_layer->SetBounds(scrollbar_rect.size());
  1231. scrollbar_layer->SetPosition(gfx::PointF(scrollbar_rect.origin()));
  1232. scrollbar_layer->fake_scrollbar()->set_track_rect(
  1233. gfx::Rect(scrollbar_rect.size()));
  1234. layer_tree_host_->SetViewportRectAndScale(
  1235. layer_tree_host_->device_viewport_rect(), test_scale,
  1236. layer_tree_host_->local_surface_id_from_parent());
  1237. UpdateDrawProperties(layer_tree_host_.get());
  1238. scrollbar_layer->Update();
  1239. UIResourceBitmap* bitmap = fake_ui_resource_manager_->ui_resource_bitmap(
  1240. scrollbar_layer->track_resource_id());
  1241. DCHECK(bitmap);
  1242. const SkColor* pixels =
  1243. reinterpret_cast<const SkColor*>(bitmap->GetPixels());
  1244. SkColor color = argb_to_skia(
  1245. scrollbar_layer->fake_scrollbar()->paint_fill_color());
  1246. int width = bitmap->GetSize().width();
  1247. int height = bitmap->GetSize().height();
  1248. // Make sure none of the corners of the bitmap were inadvertently clipped.
  1249. EXPECT_EQ(color, pixels[0])
  1250. << "Top left pixel doesn't match scrollbar color.";
  1251. EXPECT_EQ(color, pixels[width - 1])
  1252. << "Top right pixel doesn't match scrollbar color.";
  1253. EXPECT_EQ(color, pixels[width * (height - 1)])
  1254. << "Bottom left pixel doesn't match scrollbar color.";
  1255. EXPECT_EQ(color, pixels[width * height - 1])
  1256. << "Bottom right pixel doesn't match scrollbar color.";
  1257. }
  1258. protected:
  1259. // On Android, Skia uses ABGR
  1260. static SkColor argb_to_skia(SkColor c) {
  1261. return (SkColorGetA(c) << SK_A32_SHIFT) |
  1262. (SkColorGetR(c) << SK_R32_SHIFT) |
  1263. (SkColorGetG(c) << SK_G32_SHIFT) |
  1264. (SkColorGetB(c) << SK_B32_SHIFT);
  1265. }
  1266. };
  1267. TEST_F(ScaledScrollbarLayerTestScaledRasterization, TestLostPrecisionInClip) {
  1268. // Try rasterization at coordinates and scale that caused problematic
  1269. // rounding and clipping errors.
  1270. // Vertical Scrollbars.
  1271. TestScale(gfx::Rect(1240, 0, 15, 1333), 2.7754839f);
  1272. TestScale(gfx::Rect(1240, 0, 15, 677), 2.46677136f);
  1273. // Horizontal Scrollbars.
  1274. TestScale(gfx::Rect(0, 1240, 1333, 15), 2.7754839f);
  1275. TestScale(gfx::Rect(0, 1240, 677, 15), 2.46677136f);
  1276. }
  1277. } // namespace cc