Chromium Code Reviews| 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/Document.h" | 8 #include "core/dom/Document.h" |
| 9 #include "core/dom/Range.h" | 9 #include "core/dom/Range.h" |
| 10 #include "core/editing/Editor.h" | 10 #include "core/editing/Editor.h" |
| 11 #include "core/editing/FrameSelection.h" | 11 #include "core/editing/FrameSelection.h" |
| 12 #include "core/frame/FrameView.h" | 12 #include "core/frame/FrameView.h" |
| 13 #include "core/frame/LocalFrame.h" | 13 #include "core/frame/LocalFrame.h" |
| 14 #include "core/frame/Settings.h" | 14 #include "core/frame/Settings.h" |
| 15 #include "core/layout/LayoutBox.h" | |
| 15 #include "core/loader/EmptyClients.h" | 16 #include "core/loader/EmptyClients.h" |
| 16 #include "core/page/AutoscrollController.h" | 17 #include "core/page/AutoscrollController.h" |
| 17 #include "core/page/Page.h" | 18 #include "core/page/Page.h" |
| 19 #include "core/paint/PaintLayerScrollableArea.h" | |
| 18 #include "core/testing/DummyPageHolder.h" | 20 #include "core/testing/DummyPageHolder.h" |
| 21 #include "platform/scroll/MainThreadScrollingReason.h" | |
| 22 #include "platform/testing/HistogramTester.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 24 |
| 25 #define EXPECT_WHEEL_BUCKET(reason, count) \ | |
| 26 histogram_tester.ExpectBucketCount( \ | |
| 27 "Renderer4.MainThreadWheelScrollReason", \ | |
| 28 GetBucketIndex(MainThreadScrollingReason::reason), count); | |
| 29 | |
| 30 #define EXPECT_TOUCH_BUCKET(reason, count) \ | |
| 31 histogram_tester.ExpectBucketCount( \ | |
| 32 "Renderer4.MainThreadGestureScrollReason", \ | |
| 33 GetBucketIndex(MainThreadScrollingReason::reason), count); | |
| 34 | |
| 35 #define EXPECT_WHEEL_TOTAL(count) \ | |
| 36 histogram_tester.ExpectTotalCount("Renderer4.MainThreadWheelScrollReason", \ | |
| 37 count); | |
| 38 | |
| 39 #define EXPECT_TOUCH_TOTAL(count) \ | |
| 40 histogram_tester.ExpectTotalCount("Renderer4.MainThreadGestureScrollReason", \ | |
| 41 count); | |
| 42 | |
| 21 namespace blink { | 43 namespace blink { |
| 22 | 44 |
| 23 class EventHandlerTest : public ::testing::Test { | 45 class EventHandlerTest : public ::testing::Test { |
| 24 protected: | 46 protected: |
| 25 void SetUp() override; | 47 void SetUp() override; |
| 26 | 48 |
| 27 Page& GetPage() const { return dummy_page_holder_->GetPage(); } | 49 Page& GetPage() const { return dummy_page_holder_->GetPage(); } |
| 28 Document& GetDocument() const { return dummy_page_holder_->GetDocument(); } | 50 Document& GetDocument() const { return dummy_page_holder_->GetDocument(); } |
| 29 FrameSelection& Selection() const { | 51 FrameSelection& Selection() const { |
| 30 return GetDocument().GetFrame()->Selection(); | 52 return GetDocument().GetFrame()->Selection(); |
| 31 } | 53 } |
| 32 | 54 |
| 33 void SetHtmlInnerHTML(const char* html_content); | 55 void SetHtmlInnerHTML(const char* html_content); |
| 34 | 56 |
| 35 protected: | 57 protected: |
| 36 std::unique_ptr<DummyPageHolder> dummy_page_holder_; | 58 std::unique_ptr<DummyPageHolder> dummy_page_holder_; |
| 37 }; | 59 }; |
| 38 | 60 |
| 61 class NonCompositedMainThreadScrollingReasonRecordTest | |
| 62 : public EventHandlerTest { | |
| 63 protected: | |
| 64 class ScrollBeginEventBuilder : public WebGestureEvent { | |
| 65 public: | |
| 66 ScrollBeginEventBuilder(IntPoint position, | |
| 67 FloatPoint delta, | |
| 68 WebGestureDevice device) | |
| 69 : WebGestureEvent() { | |
| 70 type_ = WebInputEvent::kGestureScrollBegin; | |
| 71 x = global_x = position.X(); | |
| 72 y = global_y = position.Y(); | |
| 73 data.scroll_begin.delta_y_hint = delta.Y(); | |
| 74 source_device = device; | |
| 75 frame_scale_ = 1; | |
| 76 } | |
| 77 }; | |
| 78 | |
| 79 class ScrollUpdateEventBuilder : public WebGestureEvent { | |
| 80 public: | |
| 81 ScrollUpdateEventBuilder() : WebGestureEvent() { | |
| 82 type_ = WebInputEvent::kGestureScrollUpdate; | |
| 83 data.scroll_update.delta_x = 0.0f; | |
| 84 data.scroll_update.delta_y = 1.0f; | |
| 85 data.scroll_update.velocity_x = 0; | |
| 86 data.scroll_update.velocity_y = 1; | |
| 87 frame_scale_ = 1; | |
| 88 } | |
| 89 }; | |
| 90 | |
| 91 class ScrollEndEventBuilder : public WebGestureEvent { | |
| 92 public: | |
| 93 ScrollEndEventBuilder() : WebGestureEvent() { | |
| 94 type_ = WebInputEvent::kGestureScrollEnd; | |
| 95 frame_scale_ = 1; | |
| 96 } | |
| 97 }; | |
| 98 | |
| 99 int GetBucketIndex(uint32_t reason); | |
| 100 void Scroll(const Element*, | |
| 101 const WebGestureDevice = kWebGestureDeviceTouchpad); | |
|
bokan
2017/04/11 17:30:52
No default param. It should be clear at the call s
yigu
2017/04/11 21:28:10
Done.
| |
| 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 const Element* element, | |
| 171 const WebGestureDevice device) { | |
| 172 DCHECK(element); | |
| 173 DCHECK(element->GetLayoutBox()); | |
| 174 LayoutBox* box = element->GetLayoutBox(); | |
| 175 ScrollBeginEventBuilder scroll_begin( | |
| 176 IntPoint(box->Location().X().ToInt() + box->size().Width().ToInt() / 2, | |
|
bokan
2017/04/11 17:30:52
Location() is relative to its container, which is
yigu
2017/04/11 21:28:10
Done.
| |
| 177 box->Location().Y().ToInt() + box->size().Height().ToInt() / 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); | |
| 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); | |
| 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); | |
| 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); | |
| 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); | |
| 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); | |
| 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 | |
| 551 } // namespace blink | 784 } // namespace blink |
| OLD | NEW |