PageRenderTime 34ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/third_party/blink/renderer/core/scroll/scroll_test.cc

http://github.com/chromium/chromium
C++ | 587 lines | 476 code | 61 blank | 50 comment | 2 complexity | 2eecb5c72621ef8c49c88cb7acfc2d93 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, BSD-2-Clause, LGPL-2.1, MPL-2.0, 0BSD, EPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, BitTorrent-1.0, CPL-1.0, LGPL-3.0, Unlicense, BSD-3-Clause, CC0-1.0, JSON, MIT, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0
  1. // Copyright 2019 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 "third_party/blink/renderer/core/scroll/scroll_animator.h"
  5. #include "base/test/bind_test_util.h"
  6. #include "testing/gtest/include/gtest/gtest.h"
  7. #include "third_party/blink/public/web/web_script_source.h"
  8. #include "third_party/blink/renderer/core/css/css_style_declaration.h"
  9. #include "third_party/blink/renderer/core/dom/document.h"
  10. #include "third_party/blink/renderer/core/dom/element.h"
  11. #include "third_party/blink/renderer/core/frame/local_dom_window.h"
  12. #include "third_party/blink/renderer/core/frame/local_frame.h"
  13. #include "third_party/blink/renderer/core/frame/local_frame_view.h"
  14. #include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
  15. #include "third_party/blink/renderer/core/frame/visual_viewport.h"
  16. #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
  17. #include "third_party/blink/renderer/core/geometry/dom_rect.h"
  18. #include "third_party/blink/renderer/core/layout/layout_box.h"
  19. #include "third_party/blink/renderer/core/paint/paint_layer.h"
  20. #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
  21. #include "third_party/blink/renderer/core/scroll/scroll_animator_base.h"
  22. #include "third_party/blink/renderer/core/scroll/scrollable_area.h"
  23. #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
  24. #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
  25. #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
  26. namespace blink {
  27. namespace {
  28. constexpr double kBeginFrameDelaySeconds = 0.5;
  29. }
  30. class FractionalScrollSimTest : public SimTest {
  31. public:
  32. FractionalScrollSimTest() : fractional_scroll_offsets_for_test_(true) {}
  33. private:
  34. ScopedFractionalScrollOffsetsForTest fractional_scroll_offsets_for_test_;
  35. };
  36. TEST_F(FractionalScrollSimTest, GetBoundingClientRectAtFractional) {
  37. WebView().MainFrameWidget()->Resize(WebSize(800, 600));
  38. SimRequest request("https://example.com/test.html", "text/html");
  39. LoadURL("https://example.com/test.html");
  40. request.Complete(R"HTML(
  41. <!DOCTYPE html>
  42. <style>
  43. body, html {
  44. margin: 0;
  45. height: 2000px;
  46. width: 2000px;
  47. }
  48. div {
  49. position: absolute;
  50. left: 800px;
  51. top: 600px;
  52. width: 100px;
  53. height: 100px;
  54. }
  55. </style>
  56. <body>
  57. <div id="target"></div>
  58. </body>
  59. )HTML");
  60. Compositor().BeginFrame();
  61. // Scroll on the layout viewport.
  62. GetDocument().View()->GetScrollableArea()->SetScrollOffset(
  63. FloatSize(700.5f, 500.6f), mojom::blink::ScrollType::kProgrammatic,
  64. mojom::blink::ScrollBehavior::kInstant);
  65. Compositor().BeginFrame();
  66. Element* target = GetDocument().getElementById("target");
  67. DOMRect* rect = target->getBoundingClientRect();
  68. const float kOneLayoutUnit = 1.f / kFixedPointDenominator;
  69. EXPECT_NEAR(LayoutUnit(800.f - 700.5f), rect->left(), kOneLayoutUnit);
  70. EXPECT_NEAR(LayoutUnit(600.f - 500.6f), rect->top(), kOneLayoutUnit);
  71. }
  72. TEST_F(FractionalScrollSimTest, NoRepaintOnScrollFromSubpixel) {
  73. WebView().MainFrameWidget()->Resize(WebSize(800, 600));
  74. SimRequest request("https://example.com/test.html", "text/html");
  75. LoadURL("https://example.com/test.html");
  76. request.Complete(R"HTML(
  77. <!DOCTYPE html>
  78. <style>
  79. body {
  80. height: 4000px;
  81. }
  82. #container {
  83. will-change:transform;
  84. margin-top: 300px;
  85. }
  86. #child {
  87. height: 100px;
  88. width: 100px;
  89. transform: translateY(-0.5px);
  90. background-color: coral;
  91. }
  92. #fixed {
  93. position: fixed;
  94. top: 0;
  95. width: 100px;
  96. height: 20px;
  97. background-color: dodgerblue
  98. }
  99. </style>
  100. <!-- Need fixed element because of PLSA::UpdateCompositingLayersAfterScroll
  101. will invalidate compositing due to potential overlap changes. -->
  102. <div id="fixed"></div>
  103. <div id="container">
  104. <div id="child"></div>
  105. </div>
  106. )HTML");
  107. Compositor().BeginFrame();
  108. auto* container_layer =
  109. ToLayoutBoxModelObject(
  110. GetDocument().getElementById("container")->GetLayoutObject())
  111. ->Layer()
  112. ->GraphicsLayerBacking();
  113. container_layer->ResetTrackedRasterInvalidations();
  114. GetDocument().View()->SetTracksRasterInvalidations(true);
  115. // Scroll on the layout viewport.
  116. GetDocument().View()->GetScrollableArea()->SetScrollOffset(
  117. FloatSize(0.f, 100.5f), mojom::blink::ScrollType::kProgrammatic,
  118. mojom::blink::ScrollBehavior::kInstant);
  119. Compositor().BeginFrame();
  120. EXPECT_FALSE(
  121. container_layer->GetRasterInvalidationTracking()->HasInvalidations());
  122. GetDocument().View()->SetTracksRasterInvalidations(false);
  123. }
  124. class ScrollAnimatorSimTest : public SimTest {};
  125. // Test that the callback of user scroll will be executed when the animation
  126. // finishes at ScrollAnimator::TickAnimation for root frame user scroll at the
  127. // layout viewport.
  128. TEST_F(ScrollAnimatorSimTest, TestRootFrameLayoutViewportUserScrollCallBack) {
  129. GetDocument().GetFrame()->GetSettings()->SetScrollAnimatorEnabled(true);
  130. WebView().MainFrameWidget()->Resize(WebSize(800, 500));
  131. SimRequest request("https://example.com/test.html", "text/html");
  132. LoadURL("https://example.com/test.html");
  133. request.Complete(R"HTML(
  134. <!DOCTYPE html>
  135. <style>
  136. body, html {
  137. margin: 0;
  138. height: 500vh;
  139. }
  140. </style>
  141. <body>
  142. </body>
  143. )HTML");
  144. Compositor().BeginFrame();
  145. WebView().MainFrameWidget()->SetFocus(true);
  146. WebView().SetIsActive(true);
  147. // Scroll on the layout viewport.
  148. bool finished = false;
  149. GetDocument().View()->GetScrollableArea()->UserScroll(
  150. ScrollGranularity::kScrollByLine, FloatSize(100, 300),
  151. ScrollableArea::ScrollCallback(
  152. base::BindLambdaForTesting([&]() { finished = true; })));
  153. Compositor().BeginFrame();
  154. ASSERT_FALSE(finished);
  155. // The callback is executed when the animation finishes at
  156. // ScrollAnimator::TickAnimation.
  157. Compositor().BeginFrame();
  158. Compositor().BeginFrame(kBeginFrameDelaySeconds);
  159. ASSERT_TRUE(finished);
  160. }
  161. // Test that the callback of user scroll will be executed when the animation
  162. // finishes at ScrollAnimator::TickAnimation for root frame user scroll at the
  163. // visual viewport.
  164. TEST_F(ScrollAnimatorSimTest, TestRootFrameVisualViewporUserScrollCallBack) {
  165. GetDocument().GetFrame()->GetSettings()->SetScrollAnimatorEnabled(true);
  166. WebView().MainFrameWidget()->Resize(WebSize(800, 500));
  167. SimRequest request("https://example.com/test.html", "text/html");
  168. LoadURL("https://example.com/test.html");
  169. request.Complete(R"HTML(
  170. <!DOCTYPE html>
  171. <style>
  172. body, html {
  173. margin: 0;
  174. height: 500vh;
  175. }
  176. </style>
  177. <body>
  178. </body>
  179. )HTML");
  180. Compositor().BeginFrame();
  181. WebView().MainFrameWidget()->SetFocus(true);
  182. WebView().SetIsActive(true);
  183. WebView().SetPageScaleFactor(2);
  184. // Scroll on the visual viewport.
  185. bool finished = false;
  186. GetDocument().View()->GetScrollableArea()->UserScroll(
  187. ScrollGranularity::kScrollByLine, FloatSize(100, 300),
  188. ScrollableArea::ScrollCallback(
  189. base::BindLambdaForTesting([&]() { finished = true; })));
  190. Compositor().BeginFrame();
  191. ASSERT_FALSE(finished);
  192. // The callback is executed when the animation finishes at
  193. // ScrollAnimator::TickAnimation.
  194. Compositor().BeginFrame();
  195. Compositor().BeginFrame(kBeginFrameDelaySeconds);
  196. ASSERT_TRUE(finished);
  197. }
  198. // Test that the callback of user scroll will be executed when the animation
  199. // finishes at ScrollAnimator::TickAnimation for root frame user scroll at both
  200. // the layout and visual viewport.
  201. TEST_F(ScrollAnimatorSimTest, TestRootFrameBothViewportsUserScrollCallBack) {
  202. GetDocument().GetFrame()->GetSettings()->SetScrollAnimatorEnabled(true);
  203. WebView().MainFrameWidget()->Resize(WebSize(800, 500));
  204. SimRequest request("https://example.com/test.html", "text/html");
  205. LoadURL("https://example.com/test.html");
  206. request.Complete(R"HTML(
  207. <!DOCTYPE html>
  208. <style>
  209. body, html {
  210. margin: 0;
  211. height: 500vh;
  212. }
  213. </style>
  214. <body>
  215. </body>
  216. )HTML");
  217. Compositor().BeginFrame();
  218. WebView().MainFrameWidget()->SetFocus(true);
  219. WebView().SetIsActive(true);
  220. WebView().SetPageScaleFactor(2);
  221. // Scroll on both the layout and visual viewports.
  222. bool finished = false;
  223. GetDocument().View()->GetScrollableArea()->UserScroll(
  224. ScrollGranularity::kScrollByLine, FloatSize(0, 1000),
  225. ScrollableArea::ScrollCallback(
  226. base::BindLambdaForTesting([&]() { finished = true; })));
  227. Compositor().BeginFrame();
  228. ASSERT_FALSE(finished);
  229. // The callback is executed when the animation finishes at
  230. // ScrollAnimator::TickAnimation.
  231. Compositor().BeginFrame();
  232. Compositor().BeginFrame(kBeginFrameDelaySeconds);
  233. ASSERT_TRUE(finished);
  234. }
  235. // Test that the callback of user scroll will be executed when the animation
  236. // finishes at ScrollAnimator::TickAnimation for div user scroll.
  237. TEST_F(ScrollAnimatorSimTest, TestDivUserScrollCallBack) {
  238. GetDocument().GetSettings()->SetScrollAnimatorEnabled(true);
  239. WebView().MainFrameWidget()->Resize(WebSize(800, 500));
  240. SimRequest request("https://example.com/test.html", "text/html");
  241. LoadURL("https://example.com/test.html");
  242. request.Complete(R"HTML(
  243. <!DOCTYPE html>
  244. <style>
  245. #scroller {
  246. width: 100px;
  247. height: 100px;
  248. overflow: auto;
  249. }
  250. #overflow {
  251. height: 500px;
  252. width: 500px;
  253. }
  254. </style>
  255. <div id="scroller">
  256. <div id="overflow"></div>
  257. </div>
  258. )HTML");
  259. Compositor().BeginFrame();
  260. WebView().MainFrameWidget()->SetFocus(true);
  261. WebView().SetIsActive(true);
  262. Element* scroller = GetDocument().getElementById("scroller");
  263. bool finished = false;
  264. PaintLayerScrollableArea* scrollable_area =
  265. ToLayoutBox(scroller->GetLayoutObject())->GetScrollableArea();
  266. scrollable_area->UserScroll(
  267. ScrollGranularity::kScrollByLine, FloatSize(0, 100),
  268. ScrollableArea::ScrollCallback(
  269. base::BindLambdaForTesting([&]() { finished = true; })));
  270. Compositor().BeginFrame();
  271. ASSERT_FALSE(finished);
  272. // The callback is executed when the animation finishes at
  273. // ScrollAnimator::TickAnimation.
  274. Compositor().BeginFrame(kBeginFrameDelaySeconds);
  275. ASSERT_TRUE(finished);
  276. }
  277. // Test that the callback of user scroll will be executed in
  278. // ScrollAnimatorBase::UserScroll when animation is disabled.
  279. TEST_F(ScrollAnimatorSimTest, TestUserScrollCallBackAnimatorDisabled) {
  280. GetDocument().GetFrame()->GetSettings()->SetScrollAnimatorEnabled(false);
  281. WebView().MainFrameWidget()->Resize(WebSize(800, 500));
  282. SimRequest request("https://example.com/test.html", "text/html");
  283. LoadURL("https://example.com/test.html");
  284. request.Complete(R"HTML(
  285. <!DOCTYPE html>
  286. <style>
  287. body, html {
  288. margin: 0;
  289. height: 500vh;
  290. }
  291. </style>
  292. <body>
  293. </body>
  294. )HTML");
  295. Compositor().BeginFrame();
  296. WebView().MainFrameWidget()->SetFocus(true);
  297. WebView().SetIsActive(true);
  298. bool finished = false;
  299. GetDocument().View()->GetScrollableArea()->UserScroll(
  300. ScrollGranularity::kScrollByLine, FloatSize(0, 300),
  301. ScrollableArea::ScrollCallback(
  302. base::BindLambdaForTesting([&]() { finished = true; })));
  303. Compositor().BeginFrame();
  304. ASSERT_TRUE(finished);
  305. }
  306. // Test that the callback of user scroll will be executed when the animation is
  307. // canceled because performing a programmatic scroll in the middle of a user
  308. // scroll will cancel the animation.
  309. TEST_F(ScrollAnimatorSimTest, TestRootFrameUserScrollCallBackCancelAnimation) {
  310. GetDocument().GetFrame()->GetSettings()->SetScrollAnimatorEnabled(true);
  311. WebView().MainFrameWidget()->Resize(WebSize(800, 500));
  312. SimRequest request("https://example.com/test.html", "text/html");
  313. LoadURL("https://example.com/test.html");
  314. request.Complete(R"HTML(
  315. <!DOCTYPE html>
  316. <style>
  317. body, html {
  318. margin: 0;
  319. height: 500vh;
  320. }
  321. </style>
  322. <body>
  323. </body>
  324. )HTML");
  325. Compositor().BeginFrame();
  326. WebView().MainFrameWidget()->SetFocus(true);
  327. WebView().SetIsActive(true);
  328. // Scroll on the layout viewport.
  329. bool finished = false;
  330. GetDocument().View()->GetScrollableArea()->UserScroll(
  331. ScrollGranularity::kScrollByLine, FloatSize(100, 300),
  332. ScrollableArea::ScrollCallback(
  333. base::BindLambdaForTesting([&]() { finished = true; })));
  334. Compositor().BeginFrame();
  335. ASSERT_FALSE(finished);
  336. // Programmatic scroll will cancel the current user scroll animation and the
  337. // callback will be executed.
  338. GetDocument().View()->GetScrollableArea()->SetScrollOffset(
  339. ScrollOffset(0, 300), mojom::blink::ScrollType::kProgrammatic,
  340. mojom::blink::ScrollBehavior::kSmooth, ScrollableArea::ScrollCallback());
  341. Compositor().BeginFrame();
  342. ASSERT_TRUE(finished);
  343. }
  344. class ScrollInfacesUseCounterSimTest : public SimTest {
  345. public:
  346. // Reload the page, set direction and writing-mode, then check the initial
  347. // useCounted status.
  348. void Reset(const String& direction, const String& writing_mode) {
  349. SimRequest request("https://example.com/test.html", "text/html");
  350. LoadURL("https://example.com/test.html");
  351. request.Complete(R"HTML(
  352. <!DOCTYPE html>
  353. <style>
  354. #scroller {
  355. width: 100px;
  356. height: 100px;
  357. overflow: scroll;
  358. }
  359. #content {
  360. width: 300;
  361. height: 300;
  362. }
  363. </style>
  364. <div id="scroller"><div id="content"></div></div>
  365. )HTML");
  366. auto& document = GetDocument();
  367. auto* style = document.getElementById("scroller")->style();
  368. style->setProperty(&Window(), "direction", direction, String(),
  369. ASSERT_NO_EXCEPTION);
  370. style->setProperty(&Window(), "writing-mode", writing_mode, String(),
  371. ASSERT_NO_EXCEPTION);
  372. Compositor().BeginFrame();
  373. EXPECT_FALSE(document.IsUseCounted(
  374. WebFeature::
  375. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop));
  376. EXPECT_FALSE(document.IsUseCounted(
  377. WebFeature::
  378. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive));
  379. }
  380. // Check if Element.scrollLeft/Top could trigger useCounter as expected.
  381. void CheckScrollLeftOrTop(const String& command, bool exppected_use_counted) {
  382. String scroll_command =
  383. "document.querySelector('#scroller')." + command + ";";
  384. MainFrame().ExecuteScriptAndReturnValue(WebScriptSource(scroll_command));
  385. auto& document = GetDocument();
  386. EXPECT_EQ(
  387. exppected_use_counted,
  388. document.IsUseCounted(
  389. WebFeature::
  390. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop));
  391. EXPECT_FALSE(document.IsUseCounted(
  392. WebFeature::
  393. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive));
  394. }
  395. // Check if Element.setScrollLeft/Top could trigger useCounter as expected.
  396. void CheckSetScrollLeftOrTop(const String& command,
  397. bool exppected_use_counted) {
  398. String scroll_command =
  399. "document.querySelector('#scroller')." + command + " = -1;";
  400. MainFrame().ExecuteScriptAndReturnValue(WebScriptSource(scroll_command));
  401. auto& document = GetDocument();
  402. EXPECT_EQ(
  403. exppected_use_counted,
  404. document.IsUseCounted(
  405. WebFeature::
  406. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop));
  407. EXPECT_FALSE(document.IsUseCounted(
  408. WebFeature::
  409. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive));
  410. scroll_command = "document.querySelector('#scroller')." + command + " = 1;";
  411. MainFrame().ExecuteScriptAndReturnValue(WebScriptSource(scroll_command));
  412. EXPECT_EQ(
  413. exppected_use_counted,
  414. document.IsUseCounted(
  415. WebFeature::
  416. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive));
  417. }
  418. // Check if Element.scrollTo/scroll could trigger useCounter as expected.
  419. void CheckScrollTo(const String& command, bool exppected_use_counted) {
  420. String scroll_command =
  421. "document.querySelector('#scroller')." + command + "(-1, -1);";
  422. MainFrame().ExecuteScriptAndReturnValue(WebScriptSource(scroll_command));
  423. auto& document = GetDocument();
  424. EXPECT_EQ(
  425. exppected_use_counted,
  426. document.IsUseCounted(
  427. WebFeature::
  428. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop));
  429. EXPECT_FALSE(document.IsUseCounted(
  430. WebFeature::
  431. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive));
  432. scroll_command =
  433. "document.querySelector('#scroller')." + command + "(1, 1);";
  434. MainFrame().ExecuteScriptAndReturnValue(WebScriptSource(scroll_command));
  435. EXPECT_EQ(
  436. exppected_use_counted,
  437. document.IsUseCounted(
  438. WebFeature::
  439. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive));
  440. }
  441. };
  442. struct TestCase {
  443. String direction;
  444. String writingMode;
  445. bool scrollLeftUseCounted;
  446. bool scrollTopUseCounted;
  447. };
  448. TEST_F(ScrollInfacesUseCounterSimTest, ScrollTestAll) {
  449. v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
  450. WebView().MainFrameWidget()->Resize(WebSize(800, 600));
  451. const Vector<TestCase> test_cases = {
  452. {"ltr", "horizontal-tb", false, false},
  453. {"rtl", "horizontal-tb", true, false},
  454. {"ltr", "vertical-lr", false, false},
  455. {"rtl", "vertical-lr", false, true},
  456. {"ltr", "vertical-rl", true, false},
  457. {"rtl", "vertical-rl", true, true},
  458. };
  459. for (const TestCase& test_case : test_cases) {
  460. Reset(test_case.direction, test_case.writingMode);
  461. CheckScrollLeftOrTop("scrollLeft", test_case.scrollLeftUseCounted);
  462. Reset(test_case.direction, test_case.writingMode);
  463. CheckSetScrollLeftOrTop("scrollLeft", test_case.scrollLeftUseCounted);
  464. Reset(test_case.direction, test_case.writingMode);
  465. CheckScrollLeftOrTop("scrollTop", test_case.scrollTopUseCounted);
  466. Reset(test_case.direction, test_case.writingMode);
  467. CheckSetScrollLeftOrTop("scrollTop", test_case.scrollTopUseCounted);
  468. bool expectedScrollUseCounted =
  469. test_case.scrollLeftUseCounted || test_case.scrollTopUseCounted;
  470. Reset(test_case.direction, test_case.writingMode);
  471. CheckScrollTo("scrollTo", expectedScrollUseCounted);
  472. Reset(test_case.direction, test_case.writingMode);
  473. CheckScrollTo("scroll", expectedScrollUseCounted);
  474. Reset(test_case.direction, test_case.writingMode);
  475. CheckScrollTo("scrollBy", false);
  476. }
  477. }
  478. class ScrollPositionsInNonDefaultWritingModeSimTest : public SimTest {};
  479. // Verify that scrollIntoView() does not trigger the use counter
  480. // kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive
  481. // and can be used to feature detect the convention of scroll coordinates.
  482. TEST_F(ScrollPositionsInNonDefaultWritingModeSimTest,
  483. ScrollIntoViewAndCounters) {
  484. SimRequest main_resource("https://example.com/", "text/html");
  485. SimRequest child_frame_resource("https://example.com/subframe.html",
  486. "text/html");
  487. LoadURL("https://example.com/");
  488. // Load a page that performs feature detection of scroll behavior by relying
  489. // on scrollIntoView().
  490. main_resource.Complete(
  491. R"HTML(
  492. <body>
  493. <div style="direction: rtl; position: fixed; left: 0; top: 0; overflow: hidden; width: 1px; height: 1px;"><div style="width: 2px; height: 1px;"><div style="display: inline-block; width: 1px;"></div><div style="display: inline-block; width: 1px;"></div></div></div>
  494. <script>
  495. var scroller = document.body.firstElementChild;
  496. scroller.firstElementChild.children[0].scrollIntoView();
  497. var right = scroller.scrollLeft;
  498. scroller.firstElementChild.children[1].scrollIntoView();
  499. var left = scroller.scrollLeft;
  500. if (left < right)
  501. console.log("decreasing");
  502. if (left < 0)
  503. console.log("nonpositive");
  504. </script>
  505. </body>)HTML");
  506. Compositor().BeginFrame();
  507. test::RunPendingTasks();
  508. // Per the CSSOM specification, the standard behavior is:
  509. // - decreasing coordinates when scrolling leftward.
  510. // - nonpositive coordinates for leftward scroller.
  511. EXPECT_TRUE(ConsoleMessages().Contains("decreasing"));
  512. EXPECT_TRUE(ConsoleMessages().Contains("nonpositive"));
  513. // Reading scrollLeft triggers the first counter:
  514. EXPECT_TRUE(GetDocument().IsUseCounted(
  515. WebFeature::
  516. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop));
  517. // However, calling scrollIntoView() should not trigger the second counter:
  518. EXPECT_FALSE(GetDocument().IsUseCounted(
  519. WebFeature::
  520. kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive));
  521. }
  522. } // namespace blink