| 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" | |
| 9 #include "core/dom/Document.h" | 8 #include "core/dom/Document.h" |
| 10 #include "core/dom/Range.h" | 9 #include "core/dom/Range.h" |
| 11 #include "core/editing/Editor.h" | 10 #include "core/editing/Editor.h" |
| 12 #include "core/editing/FrameSelection.h" | 11 #include "core/editing/FrameSelection.h" |
| 13 #include "core/frame/FrameView.h" | 12 #include "core/frame/FrameView.h" |
| 14 #include "core/frame/LocalFrame.h" | 13 #include "core/frame/LocalFrame.h" |
| 15 #include "core/frame/Settings.h" | 14 #include "core/frame/Settings.h" |
| 16 #include "core/layout/LayoutBox.h" | |
| 17 #include "core/loader/EmptyClients.h" | 15 #include "core/loader/EmptyClients.h" |
| 18 #include "core/page/AutoscrollController.h" | 16 #include "core/page/AutoscrollController.h" |
| 19 #include "core/page/Page.h" | 17 #include "core/page/Page.h" |
| 20 #include "core/paint/PaintLayerScrollableArea.h" | |
| 21 #include "core/testing/DummyPageHolder.h" | 18 #include "core/testing/DummyPageHolder.h" |
| 22 #include "platform/scroll/MainThreadScrollingReason.h" | |
| 23 #include "platform/testing/HistogramTester.h" | |
| 24 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 25 | 20 |
| 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 | |
| 44 namespace blink { | 21 namespace blink { |
| 45 | 22 |
| 46 class EventHandlerTest : public ::testing::Test { | 23 class EventHandlerTest : public ::testing::Test { |
| 47 protected: | 24 protected: |
| 48 void SetUp() override; | 25 void SetUp() override; |
| 49 | 26 |
| 50 Page& GetPage() const { return dummy_page_holder_->GetPage(); } | 27 Page& GetPage() const { return dummy_page_holder_->GetPage(); } |
| 51 Document& GetDocument() const { return dummy_page_holder_->GetDocument(); } | 28 Document& GetDocument() const { return dummy_page_holder_->GetDocument(); } |
| 52 FrameSelection& Selection() const { | 29 FrameSelection& Selection() const { |
| 53 return GetDocument().GetFrame()->Selection(); | 30 return GetDocument().GetFrame()->Selection(); |
| 54 } | 31 } |
| 55 | 32 |
| 56 void SetHtmlInnerHTML(const char* html_content); | 33 void SetHtmlInnerHTML(const char* html_content); |
| 57 | 34 |
| 58 protected: | 35 protected: |
| 59 std::unique_ptr<DummyPageHolder> dummy_page_holder_; | 36 std::unique_ptr<DummyPageHolder> dummy_page_holder_; |
| 60 }; | 37 }; |
| 61 | 38 |
| 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 | |
| 104 class TapEventBuilder : public WebGestureEvent { | 39 class TapEventBuilder : public WebGestureEvent { |
| 105 public: | 40 public: |
| 106 TapEventBuilder(IntPoint position, int tap_count) | 41 TapEventBuilder(IntPoint position, int tap_count) |
| 107 : WebGestureEvent(WebInputEvent::kGestureTap, | 42 : WebGestureEvent(WebInputEvent::kGestureTap, |
| 108 WebInputEvent::kNoModifiers, | 43 WebInputEvent::kNoModifiers, |
| 109 TimeTicks::Now().InSeconds()) { | 44 TimeTicks::Now().InSeconds()) { |
| 110 x = global_x = position.X(); | 45 x = global_x = position.X(); |
| 111 y = global_y = position.Y(); | 46 y = global_y = position.Y(); |
| 112 source_device = kWebGestureDeviceTouchscreen; | 47 source_device = kWebGestureDeviceTouchscreen; |
| 113 data.tap.tap_count = tap_count; | 48 data.tap.tap_count = tap_count; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 | 83 |
| 149 void EventHandlerTest::SetUp() { | 84 void EventHandlerTest::SetUp() { |
| 150 dummy_page_holder_ = DummyPageHolder::Create(IntSize(300, 400)); | 85 dummy_page_holder_ = DummyPageHolder::Create(IntSize(300, 400)); |
| 151 } | 86 } |
| 152 | 87 |
| 153 void EventHandlerTest::SetHtmlInnerHTML(const char* html_content) { | 88 void EventHandlerTest::SetHtmlInnerHTML(const char* html_content) { |
| 154 GetDocument().documentElement()->setInnerHTML(String::FromUTF8(html_content)); | 89 GetDocument().documentElement()->setInnerHTML(String::FromUTF8(html_content)); |
| 155 GetDocument().View()->UpdateAllLifecyclePhases(); | 90 GetDocument().View()->UpdateAllLifecyclePhases(); |
| 156 } | 91 } |
| 157 | 92 |
| 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 | |
| 186 TEST_F(EventHandlerTest, dragSelectionAfterScroll) { | 93 TEST_F(EventHandlerTest, dragSelectionAfterScroll) { |
| 187 SetHtmlInnerHTML( | 94 SetHtmlInnerHTML( |
| 188 "<style> body { margin: 0px; } .upper { width: 300px; height: 400px; }" | 95 "<style> body { margin: 0px; } .upper { width: 300px; height: 400px; }" |
| 189 ".lower { margin: 0px; width: 300px; height: 400px; } .line { display: " | 96 ".lower { margin: 0px; width: 300px; height: 400px; } .line { display: " |
| 190 "block; width: 300px; height: 30px; } </style>" | 97 "block; width: 300px; height: 30px; } </style>" |
| 191 "<div class='upper'></div>" | 98 "<div class='upper'></div>" |
| 192 "<div class='lower'>" | 99 "<div class='lower'>" |
| 193 "<span class='line'>Line 1</span><span class='line'>Line 2</span><span " | 100 "<span class='line'>Line 1</span><span class='line'>Line 2</span><span " |
| 194 "class='line'>Line 3</span><span class='line'>Line 4</span><span " | 101 "class='line'>Line 3</span><span class='line'>Line 4</span><span " |
| 195 "class='line'>Line 5</span>" | 102 "class='line'>Line 5</span>" |
| (...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 634 WebInputEvent::kMouseLeave, WebFloatPoint(0, 0), WebFloatPoint(0, 0), | 541 WebInputEvent::kMouseLeave, WebFloatPoint(0, 0), WebFloatPoint(0, 0), |
| 635 WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers, | 542 WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers, |
| 636 TimeTicks::Now().InSeconds()); | 543 TimeTicks::Now().InSeconds()); |
| 637 mouse_leave_event.SetFrameScale(1); | 544 mouse_leave_event.SetFrameScale(1); |
| 638 GetDocument().GetFrame()->GetEventHandler().HandleMouseLeaveEvent( | 545 GetDocument().GetFrame()->GetEventHandler().HandleMouseLeaveEvent( |
| 639 mouse_leave_event); | 546 mouse_leave_event); |
| 640 | 547 |
| 641 EXPECT_EQ(WTF::String(), LastToolTip()); | 548 EXPECT_EQ(WTF::String(), LastToolTip()); |
| 642 } | 549 } |
| 643 | 550 |
| 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>" | |
| 762 " <div class='spacer'></div>" | |
| 763 "</div>"); | |
| 764 | |
| 765 GetPage().GetSettings().SetAcceleratedCompositingEnabled(true); | |
| 766 GetDocument().View()->SetParentVisible(true); | |
| 767 GetDocument().View()->SetSelfVisible(true); | |
| 768 GetDocument().View()->UpdateAllLifecyclePhases(); | |
| 769 | |
| 770 Element* box = GetDocument().getElementById("inner"); | |
| 771 HistogramTester histogram_tester; | |
| 772 | |
| 773 Scroll(box, kWebGestureDeviceTouchpad); | |
| 774 // Scrolling the inner box will gather reasons from the scrolling chain. The | |
| 775 // inner box itself has no reason because it's composited. Other scrollable | |
| 776 // areas from the chain have corresponding reasons. | |
| 777 EXPECT_WHEEL_BUCKET(kHasOpacityAndLCDText, 1); | |
| 778 EXPECT_WHEEL_BUCKET(kBackgroundNotOpaqueInRectAndLCDText, 1); | |
| 779 EXPECT_WHEEL_BUCKET(kHasBorderRadius, 1); | |
| 780 EXPECT_WHEEL_BUCKET(kHasTransformAndLCDText, 0); | |
| 781 EXPECT_WHEEL_TOTAL(3); | |
| 782 } | |
| 783 | |
| 784 } // namespace blink | 551 } // namespace blink |
| OLD | NEW |