OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/input/EventHandler.h" | 5 #include "core/input/EventHandler.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
| 8 #include "core/dom/ClientRect.h" |
8 #include "core/dom/Document.h" | 9 #include "core/dom/Document.h" |
9 #include "core/dom/Range.h" | 10 #include "core/dom/Range.h" |
10 #include "core/editing/Editor.h" | 11 #include "core/editing/Editor.h" |
11 #include "core/editing/FrameSelection.h" | 12 #include "core/editing/FrameSelection.h" |
12 #include "core/frame/FrameView.h" | 13 #include "core/frame/FrameView.h" |
13 #include "core/frame/LocalFrame.h" | 14 #include "core/frame/LocalFrame.h" |
14 #include "core/frame/Settings.h" | 15 #include "core/frame/Settings.h" |
| 16 #include "core/layout/LayoutBox.h" |
15 #include "core/loader/EmptyClients.h" | 17 #include "core/loader/EmptyClients.h" |
16 #include "core/page/AutoscrollController.h" | 18 #include "core/page/AutoscrollController.h" |
17 #include "core/page/Page.h" | 19 #include "core/page/Page.h" |
| 20 #include "core/paint/PaintLayerScrollableArea.h" |
18 #include "core/testing/DummyPageHolder.h" | 21 #include "core/testing/DummyPageHolder.h" |
| 22 #include "platform/scroll/MainThreadScrollingReason.h" |
| 23 #include "platform/testing/HistogramTester.h" |
19 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
20 | 25 |
| 26 #define EXPECT_WHEEL_BUCKET(reason, count) \ |
| 27 histogram_tester.ExpectBucketCount( \ |
| 28 "Renderer4.MainThreadWheelScrollReason", \ |
| 29 GetBucketIndex(MainThreadScrollingReason::reason), count); |
| 30 |
| 31 #define EXPECT_TOUCH_BUCKET(reason, count) \ |
| 32 histogram_tester.ExpectBucketCount( \ |
| 33 "Renderer4.MainThreadGestureScrollReason", \ |
| 34 GetBucketIndex(MainThreadScrollingReason::reason), count); |
| 35 |
| 36 #define EXPECT_WHEEL_TOTAL(count) \ |
| 37 histogram_tester.ExpectTotalCount("Renderer4.MainThreadWheelScrollReason", \ |
| 38 count); |
| 39 |
| 40 #define EXPECT_TOUCH_TOTAL(count) \ |
| 41 histogram_tester.ExpectTotalCount("Renderer4.MainThreadGestureScrollReason", \ |
| 42 count); |
| 43 |
21 namespace blink { | 44 namespace blink { |
22 | 45 |
23 class EventHandlerTest : public ::testing::Test { | 46 class EventHandlerTest : public ::testing::Test { |
24 protected: | 47 protected: |
25 void SetUp() override; | 48 void SetUp() override; |
26 | 49 |
27 Page& GetPage() const { return dummy_page_holder_->GetPage(); } | 50 Page& GetPage() const { return dummy_page_holder_->GetPage(); } |
28 Document& GetDocument() const { return dummy_page_holder_->GetDocument(); } | 51 Document& GetDocument() const { return dummy_page_holder_->GetDocument(); } |
29 FrameSelection& Selection() const { | 52 FrameSelection& Selection() const { |
30 return GetDocument().GetFrame()->Selection(); | 53 return GetDocument().GetFrame()->Selection(); |
31 } | 54 } |
32 | 55 |
33 void SetHtmlInnerHTML(const char* html_content); | 56 void SetHtmlInnerHTML(const char* html_content); |
34 | 57 |
35 protected: | 58 protected: |
36 std::unique_ptr<DummyPageHolder> dummy_page_holder_; | 59 std::unique_ptr<DummyPageHolder> dummy_page_holder_; |
37 }; | 60 }; |
38 | 61 |
| 62 class NonCompositedMainThreadScrollingReasonRecordTest |
| 63 : public EventHandlerTest { |
| 64 protected: |
| 65 class ScrollBeginEventBuilder : public WebGestureEvent { |
| 66 public: |
| 67 ScrollBeginEventBuilder(IntPoint position, |
| 68 FloatPoint delta, |
| 69 WebGestureDevice device) |
| 70 : WebGestureEvent() { |
| 71 type_ = WebInputEvent::kGestureScrollBegin; |
| 72 x = global_x = position.X(); |
| 73 y = global_y = position.Y(); |
| 74 data.scroll_begin.delta_y_hint = delta.Y(); |
| 75 source_device = device; |
| 76 frame_scale_ = 1; |
| 77 } |
| 78 }; |
| 79 |
| 80 class ScrollUpdateEventBuilder : public WebGestureEvent { |
| 81 public: |
| 82 ScrollUpdateEventBuilder() : WebGestureEvent() { |
| 83 type_ = WebInputEvent::kGestureScrollUpdate; |
| 84 data.scroll_update.delta_x = 0.0f; |
| 85 data.scroll_update.delta_y = 1.0f; |
| 86 data.scroll_update.velocity_x = 0; |
| 87 data.scroll_update.velocity_y = 1; |
| 88 frame_scale_ = 1; |
| 89 } |
| 90 }; |
| 91 |
| 92 class ScrollEndEventBuilder : public WebGestureEvent { |
| 93 public: |
| 94 ScrollEndEventBuilder() : WebGestureEvent() { |
| 95 type_ = WebInputEvent::kGestureScrollEnd; |
| 96 frame_scale_ = 1; |
| 97 } |
| 98 }; |
| 99 |
| 100 int GetBucketIndex(uint32_t reason); |
| 101 void Scroll(Element*, const WebGestureDevice); |
| 102 }; |
| 103 |
39 class TapEventBuilder : public WebGestureEvent { | 104 class TapEventBuilder : public WebGestureEvent { |
40 public: | 105 public: |
41 TapEventBuilder(IntPoint position, int tap_count) | 106 TapEventBuilder(IntPoint position, int tap_count) |
42 : WebGestureEvent(WebInputEvent::kGestureTap, | 107 : WebGestureEvent(WebInputEvent::kGestureTap, |
43 WebInputEvent::kNoModifiers, | 108 WebInputEvent::kNoModifiers, |
44 TimeTicks::Now().InSeconds()) { | 109 TimeTicks::Now().InSeconds()) { |
45 x = global_x = position.X(); | 110 x = global_x = position.X(); |
46 y = global_y = position.Y(); | 111 y = global_y = position.Y(); |
47 source_device = kWebGestureDeviceTouchscreen; | 112 source_device = kWebGestureDeviceTouchscreen; |
48 data.tap.tap_count = tap_count; | 113 data.tap.tap_count = tap_count; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 | 148 |
84 void EventHandlerTest::SetUp() { | 149 void EventHandlerTest::SetUp() { |
85 dummy_page_holder_ = DummyPageHolder::Create(IntSize(300, 400)); | 150 dummy_page_holder_ = DummyPageHolder::Create(IntSize(300, 400)); |
86 } | 151 } |
87 | 152 |
88 void EventHandlerTest::SetHtmlInnerHTML(const char* html_content) { | 153 void EventHandlerTest::SetHtmlInnerHTML(const char* html_content) { |
89 GetDocument().documentElement()->setInnerHTML(String::FromUTF8(html_content)); | 154 GetDocument().documentElement()->setInnerHTML(String::FromUTF8(html_content)); |
90 GetDocument().View()->UpdateAllLifecyclePhases(); | 155 GetDocument().View()->UpdateAllLifecyclePhases(); |
91 } | 156 } |
92 | 157 |
| 158 int NonCompositedMainThreadScrollingReasonRecordTest::GetBucketIndex( |
| 159 uint32_t reason) { |
| 160 int index = 1; |
| 161 while (!(reason & 1)) { |
| 162 reason >>= 1; |
| 163 ++index; |
| 164 } |
| 165 DCHECK_EQ(reason, 1u); |
| 166 return index; |
| 167 } |
| 168 |
| 169 void NonCompositedMainThreadScrollingReasonRecordTest::Scroll( |
| 170 Element* element, |
| 171 const WebGestureDevice device) { |
| 172 DCHECK(element); |
| 173 DCHECK(element->getBoundingClientRect()); |
| 174 ClientRect* rect = element->getBoundingClientRect(); |
| 175 ScrollBeginEventBuilder scroll_begin( |
| 176 IntPoint(rect->left() + rect->width() / 2, |
| 177 rect->top() + rect->height() / 2), |
| 178 FloatPoint(0.f, 1.f), device); |
| 179 ScrollUpdateEventBuilder scroll_update; |
| 180 ScrollEndEventBuilder scroll_end; |
| 181 GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(scroll_begin); |
| 182 GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(scroll_update); |
| 183 GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(scroll_end); |
| 184 } |
| 185 |
93 TEST_F(EventHandlerTest, dragSelectionAfterScroll) { | 186 TEST_F(EventHandlerTest, dragSelectionAfterScroll) { |
94 SetHtmlInnerHTML( | 187 SetHtmlInnerHTML( |
95 "<style> body { margin: 0px; } .upper { width: 300px; height: 400px; }" | 188 "<style> body { margin: 0px; } .upper { width: 300px; height: 400px; }" |
96 ".lower { margin: 0px; width: 300px; height: 400px; } .line { display: " | 189 ".lower { margin: 0px; width: 300px; height: 400px; } .line { display: " |
97 "block; width: 300px; height: 30px; } </style>" | 190 "block; width: 300px; height: 30px; } </style>" |
98 "<div class='upper'></div>" | 191 "<div class='upper'></div>" |
99 "<div class='lower'>" | 192 "<div class='lower'>" |
100 "<span class='line'>Line 1</span><span class='line'>Line 2</span><span " | 193 "<span class='line'>Line 1</span><span class='line'>Line 2</span><span " |
101 "class='line'>Line 3</span><span class='line'>Line 4</span><span " | 194 "class='line'>Line 3</span><span class='line'>Line 4</span><span " |
102 "class='line'>Line 5</span>" | 195 "class='line'>Line 5</span>" |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
541 WebInputEvent::kMouseLeave, WebFloatPoint(0, 0), WebFloatPoint(0, 0), | 634 WebInputEvent::kMouseLeave, WebFloatPoint(0, 0), WebFloatPoint(0, 0), |
542 WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers, | 635 WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers, |
543 TimeTicks::Now().InSeconds()); | 636 TimeTicks::Now().InSeconds()); |
544 mouse_leave_event.SetFrameScale(1); | 637 mouse_leave_event.SetFrameScale(1); |
545 GetDocument().GetFrame()->GetEventHandler().HandleMouseLeaveEvent( | 638 GetDocument().GetFrame()->GetEventHandler().HandleMouseLeaveEvent( |
546 mouse_leave_event); | 639 mouse_leave_event); |
547 | 640 |
548 EXPECT_EQ(WTF::String(), LastToolTip()); | 641 EXPECT_EQ(WTF::String(), LastToolTip()); |
549 } | 642 } |
550 | 643 |
| 644 TEST_F(NonCompositedMainThreadScrollingReasonRecordTest, |
| 645 TouchAndWheelGeneralTest) { |
| 646 SetHtmlInnerHTML( |
| 647 "<style>" |
| 648 " .box { overflow:scroll; width: 100px; height: 100px; }" |
| 649 " .translucent { opacity: 0.5; }" |
| 650 " .spacer { height: 1000px; }" |
| 651 "</style>" |
| 652 "<div id='box' class='translucent box'>" |
| 653 " <div class='spacer'></div>" |
| 654 "</div>"); |
| 655 |
| 656 GetDocument().View()->UpdateAllLifecyclePhases(); |
| 657 |
| 658 Element* box = GetDocument().getElementById("box"); |
| 659 HistogramTester histogram_tester; |
| 660 |
| 661 // Test touch scroll. |
| 662 Scroll(box, kWebGestureDeviceTouchscreen); |
| 663 EXPECT_TOUCH_BUCKET(kHasOpacityAndLCDText, 1); |
| 664 EXPECT_TOUCH_BUCKET(kBackgroundNotOpaqueInRectAndLCDText, 1); |
| 665 |
| 666 Scroll(box, kWebGestureDeviceTouchscreen); |
| 667 EXPECT_TOUCH_BUCKET(kHasOpacityAndLCDText, 2); |
| 668 EXPECT_TOUCH_BUCKET(kBackgroundNotOpaqueInRectAndLCDText, 2); |
| 669 EXPECT_TOUCH_TOTAL(4); |
| 670 |
| 671 // Test wheel scroll. |
| 672 Scroll(box, kWebGestureDeviceTouchpad); |
| 673 EXPECT_WHEEL_BUCKET(kHasOpacityAndLCDText, 1); |
| 674 EXPECT_WHEEL_BUCKET(kBackgroundNotOpaqueInRectAndLCDText, 1); |
| 675 EXPECT_WHEEL_TOTAL(2); |
| 676 } |
| 677 |
| 678 TEST_F(NonCompositedMainThreadScrollingReasonRecordTest, |
| 679 CompositedScrollableAreaTest) { |
| 680 SetHtmlInnerHTML( |
| 681 "<style>" |
| 682 " .box { overflow:scroll; width: 100px; height: 100px; }" |
| 683 " .translucent { opacity: 0.5; }" |
| 684 " .composited { will-change: transform; }" |
| 685 " .spacer { height: 1000px; }" |
| 686 "</style>" |
| 687 "<div id='box' class='translucent box'>" |
| 688 " <div class='spacer'></div>" |
| 689 "</div>"); |
| 690 |
| 691 GetPage().GetSettings().SetAcceleratedCompositingEnabled(true); |
| 692 GetDocument().View()->SetParentVisible(true); |
| 693 GetDocument().View()->SetSelfVisible(true); |
| 694 GetDocument().View()->UpdateAllLifecyclePhases(); |
| 695 |
| 696 Element* box = GetDocument().getElementById("box"); |
| 697 HistogramTester histogram_tester; |
| 698 |
| 699 Scroll(box, kWebGestureDeviceTouchpad); |
| 700 EXPECT_WHEEL_BUCKET(kHasOpacityAndLCDText, 1); |
| 701 EXPECT_WHEEL_BUCKET(kBackgroundNotOpaqueInRectAndLCDText, 1); |
| 702 EXPECT_WHEEL_TOTAL(2); |
| 703 |
| 704 box->setAttribute("class", "composited translucent box"); |
| 705 GetDocument().View()->UpdateAllLifecyclePhases(); |
| 706 Scroll(box, kWebGestureDeviceTouchpad); |
| 707 EXPECT_FALSE(ToLayoutBox(box->GetLayoutObject()) |
| 708 ->GetScrollableArea() |
| 709 ->GetNonCompositedMainThreadScrollingReasons()); |
| 710 EXPECT_WHEEL_BUCKET(kHasOpacityAndLCDText, 1); |
| 711 EXPECT_WHEEL_BUCKET(kBackgroundNotOpaqueInRectAndLCDText, 1); |
| 712 EXPECT_WHEEL_TOTAL(2); |
| 713 } |
| 714 |
| 715 TEST_F(NonCompositedMainThreadScrollingReasonRecordTest, |
| 716 NotScrollableAreaTest) { |
| 717 SetHtmlInnerHTML( |
| 718 "<style>.box { overflow:scroll; width: 100px; height: 100px; }" |
| 719 " .translucent { opacity: 0.5; }" |
| 720 " .hidden { overflow: hidden; }" |
| 721 " .spacer { height: 1000px; }" |
| 722 "</style>" |
| 723 "<div id='box' class='translucent box'>" |
| 724 " <div class='spacer'></div>" |
| 725 "</div>"); |
| 726 |
| 727 GetDocument().View()->UpdateAllLifecyclePhases(); |
| 728 |
| 729 Element* box = GetDocument().getElementById("box"); |
| 730 HistogramTester histogram_tester; |
| 731 |
| 732 Scroll(box, kWebGestureDeviceTouchpad); |
| 733 EXPECT_WHEEL_BUCKET(kHasOpacityAndLCDText, 1); |
| 734 EXPECT_WHEEL_BUCKET(kBackgroundNotOpaqueInRectAndLCDText, 1); |
| 735 EXPECT_WHEEL_TOTAL(2); |
| 736 |
| 737 box->setAttribute("class", "hidden translucent box"); |
| 738 GetDocument().View()->UpdateAllLifecyclePhases(); |
| 739 Scroll(box, kWebGestureDeviceTouchpad); |
| 740 EXPECT_WHEEL_BUCKET(kHasOpacityAndLCDText, 1); |
| 741 EXPECT_WHEEL_BUCKET(kBackgroundNotOpaqueInRectAndLCDText, 1); |
| 742 EXPECT_WHEEL_TOTAL(2); |
| 743 } |
| 744 |
| 745 TEST_F(NonCompositedMainThreadScrollingReasonRecordTest, NestedScrollersTest) { |
| 746 SetHtmlInnerHTML( |
| 747 "<style>" |
| 748 " .container { overflow:scroll; width: 200px; height: 200px; }" |
| 749 " .box { overflow:scroll; width: 100px; height: 100px; }" |
| 750 " .translucent { opacity: 0.5; }" |
| 751 " .transform { transform: scale(0.8); }" |
| 752 " .with-border-radius { border: 5px solid; border-radius: 5px; }" |
| 753 " .spacer { height: 1000px; }" |
| 754 " .composited { will-change: transform; }" |
| 755 "</style>" |
| 756 "<div id='container' class='container with-border-radius'>" |
| 757 " <div class='translucent box'>" |
| 758 " <div id='inner' class='composited transform box'>" |
| 759 " <div class='spacer'></div>" |
| 760 " </div>" |
| 761 " <div class='spacer'></div>" |
| 762 " </div>" |
| 763 " <div class='spacer'></div>" |
| 764 "</div>"); |
| 765 |
| 766 GetPage().GetSettings().SetAcceleratedCompositingEnabled(true); |
| 767 GetDocument().View()->SetParentVisible(true); |
| 768 GetDocument().View()->SetSelfVisible(true); |
| 769 GetDocument().View()->UpdateAllLifecyclePhases(); |
| 770 |
| 771 Element* box = GetDocument().getElementById("inner"); |
| 772 HistogramTester histogram_tester; |
| 773 |
| 774 Scroll(box, kWebGestureDeviceTouchpad); |
| 775 // Scrolling the inner box will gather reasons from the scrolling chain. The |
| 776 // inner box itself has no reason because it's composited. Other scrollable |
| 777 // areas from the chain have corresponding reasons. |
| 778 EXPECT_WHEEL_BUCKET(kHasOpacityAndLCDText, 1); |
| 779 EXPECT_WHEEL_BUCKET(kBackgroundNotOpaqueInRectAndLCDText, 1); |
| 780 EXPECT_WHEEL_BUCKET(kHasBorderRadius, 1); |
| 781 EXPECT_WHEEL_BUCKET(kHasTransformAndLCDText, 0); |
| 782 EXPECT_WHEEL_TOTAL(3); |
| 783 } |
| 784 |
551 } // namespace blink | 785 } // namespace blink |
OLD | NEW |