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/loader/EmptyClients.h" | 15 #include "core/loader/EmptyClients.h" |
| 16 #include "core/page/AutoscrollController.h" | 16 #include "core/page/AutoscrollController.h" |
| 17 #include "core/page/Page.h" | 17 #include "core/page/Page.h" |
| 18 #include "core/testing/DummyPageHolder.h" | 18 #include "core/testing/DummyPageHolder.h" |
| 19 #include "platform/scroll/MainThreadScrollingReason.h" | |
| 20 #include "platform/testing/HistogramTester.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 22 |
| 21 namespace blink { | 23 namespace blink { |
| 22 | 24 |
| 23 class EventHandlerTest : public ::testing::Test { | 25 class EventHandlerTest : public ::testing::Test { |
| 24 protected: | 26 protected: |
| 25 void SetUp() override; | 27 void SetUp() override; |
| 26 | 28 |
| 27 Page& page() const { return m_dummyPageHolder->page(); } | 29 Page& page() const { return m_dummyPageHolder->page(); } |
| 28 Document& document() const { return m_dummyPageHolder->document(); } | 30 Document& document() const { return m_dummyPageHolder->document(); } |
| 29 FrameSelection& selection() const { return document().frame()->selection(); } | 31 FrameSelection& selection() const { return document().frame()->selection(); } |
| 30 | 32 |
| 31 void setHtmlInnerHTML(const char* htmlContent); | 33 void setHtmlInnerHTML(const char* htmlContent); |
| 34 int getBucketIndex(uint32_t reason); | |
| 32 | 35 |
| 33 protected: | 36 protected: |
| 34 std::unique_ptr<DummyPageHolder> m_dummyPageHolder; | 37 std::unique_ptr<DummyPageHolder> m_dummyPageHolder; |
| 35 }; | 38 }; |
| 36 | 39 |
| 37 class TapEventBuilder : public WebGestureEvent { | 40 class TapEventBuilder : public WebGestureEvent { |
| 38 public: | 41 public: |
| 39 TapEventBuilder(IntPoint position, int tapCount) | 42 TapEventBuilder(IntPoint position, int tapCount) |
| 40 : WebGestureEvent(WebInputEvent::GestureTap, | 43 : WebGestureEvent(WebInputEvent::GestureTap, |
| 41 WebInputEvent::NoModifiers, | 44 WebInputEvent::NoModifiers, |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 72 WebInputEvent::NoModifiers, | 75 WebInputEvent::NoModifiers, |
| 73 TimeTicks::Now().InSeconds()) { | 76 TimeTicks::Now().InSeconds()) { |
| 74 clickCount = clickCountParam; | 77 clickCount = clickCountParam; |
| 75 button = buttonParam; | 78 button = buttonParam; |
| 76 setPositionInWidget(positionParam.x(), positionParam.y()); | 79 setPositionInWidget(positionParam.x(), positionParam.y()); |
| 77 setPositionInScreen(positionParam.x(), positionParam.y()); | 80 setPositionInScreen(positionParam.x(), positionParam.y()); |
| 78 m_frameScale = 1; | 81 m_frameScale = 1; |
| 79 } | 82 } |
| 80 }; | 83 }; |
| 81 | 84 |
| 85 class ScrollBeginEventBuilder : public WebGestureEvent { | |
| 86 public: | |
| 87 ScrollBeginEventBuilder(IntPoint position, | |
| 88 FloatPoint delta, | |
| 89 WebGestureDevice device) | |
| 90 : WebGestureEvent() { | |
| 91 m_type = WebInputEvent::GestureScrollBegin; | |
| 92 x = globalX = position.x(); | |
| 93 y = globalY = position.y(); | |
| 94 data.scrollBegin.deltaYHint = delta.y(); | |
| 95 sourceDevice = device; | |
| 96 m_frameScale = 1; | |
| 97 } | |
| 98 }; | |
| 99 | |
| 100 class ScrollEndEventBuilder : public WebGestureEvent { | |
| 101 public: | |
| 102 ScrollEndEventBuilder() : WebGestureEvent() { | |
| 103 m_type = WebInputEvent::GestureScrollEnd; | |
| 104 m_frameScale = 1; | |
| 105 } | |
| 106 }; | |
| 107 | |
| 82 void EventHandlerTest::SetUp() { | 108 void EventHandlerTest::SetUp() { |
| 83 m_dummyPageHolder = DummyPageHolder::create(IntSize(300, 400)); | 109 m_dummyPageHolder = DummyPageHolder::create(IntSize(300, 400)); |
| 84 } | 110 } |
| 85 | 111 |
| 86 void EventHandlerTest::setHtmlInnerHTML(const char* htmlContent) { | 112 void EventHandlerTest::setHtmlInnerHTML(const char* htmlContent) { |
| 87 document().documentElement()->setInnerHTML(String::fromUTF8(htmlContent)); | 113 document().documentElement()->setInnerHTML(String::fromUTF8(htmlContent)); |
| 88 document().view()->updateAllLifecyclePhases(); | 114 document().view()->updateAllLifecyclePhases(); |
| 89 } | 115 } |
| 90 | 116 |
| 117 int EventHandlerTest::getBucketIndex(uint32_t reason) { | |
| 118 if (reason & (reason - 1)) | |
|
bokan
2017/04/07 21:05:57
I had to google what this does. A clearer way to e
yigu
2017/04/10 20:39:04
Done.
| |
| 119 return -1; | |
| 120 int index = 0; | |
| 121 while (reason > 0) { | |
| 122 reason >>= 1; | |
| 123 ++index; | |
| 124 } | |
| 125 return index; | |
| 126 } | |
| 127 | |
| 91 TEST_F(EventHandlerTest, dragSelectionAfterScroll) { | 128 TEST_F(EventHandlerTest, dragSelectionAfterScroll) { |
| 92 setHtmlInnerHTML( | 129 setHtmlInnerHTML( |
| 93 "<style> body { margin: 0px; } .upper { width: 300px; height: 400px; }" | 130 "<style> body { margin: 0px; } .upper { width: 300px; height: 400px; }" |
| 94 ".lower { margin: 0px; width: 300px; height: 400px; } .line { display: " | 131 ".lower { margin: 0px; width: 300px; height: 400px; } .line { display: " |
| 95 "block; width: 300px; height: 30px; } </style>" | 132 "block; width: 300px; height: 30px; } </style>" |
| 96 "<div class='upper'></div>" | 133 "<div class='upper'></div>" |
| 97 "<div class='lower'>" | 134 "<div class='lower'>" |
| 98 "<span class='line'>Line 1</span><span class='line'>Line 2</span><span " | 135 "<span class='line'>Line 1</span><span class='line'>Line 2</span><span " |
| 99 "class='line'>Line 3</span><span class='line'>Line 4</span><span " | 136 "class='line'>Line 3</span><span class='line'>Line 4</span><span " |
| 100 "class='line'>Line 5</span>" | 137 "class='line'>Line 5</span>" |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 454 WebInputEvent::MouseUp, WebFloatPoint(100, 50), WebFloatPoint(200, 250), | 491 WebInputEvent::MouseUp, WebFloatPoint(100, 50), WebFloatPoint(200, 250), |
| 455 WebPointerProperties::Button::Left, 1, WebInputEvent::NoModifiers, | 492 WebPointerProperties::Button::Left, 1, WebInputEvent::NoModifiers, |
| 456 TimeTicks::Now().InSeconds()); | 493 TimeTicks::Now().InSeconds()); |
| 457 mouseUpEvent.setFrameScale(1); | 494 mouseUpEvent.setFrameScale(1); |
| 458 document().frame()->eventHandler().dragSourceEndedAt(mouseUpEvent, | 495 document().frame()->eventHandler().dragSourceEndedAt(mouseUpEvent, |
| 459 DragOperationNone); | 496 DragOperationNone); |
| 460 | 497 |
| 461 // This test passes if it doesn't crash. | 498 // This test passes if it doesn't crash. |
| 462 } | 499 } |
| 463 | 500 |
| 501 TEST_F(EventHandlerTest, NonCompositedMainThreadScrollingReasonTest) { | |
| 502 setHtmlInnerHTML( | |
| 503 "<style>" | |
| 504 " .box { overflow:scroll; width: 100px; height: 100px; }" | |
| 505 " .translucent { opacity: 0.5; }" | |
| 506 " .spacer { height: 1000px; }" | |
| 507 "</style>" | |
| 508 "<div id='box' class='translucent box'>" | |
| 509 " <div class='spacer'></div>" | |
| 510 "</div>"); | |
| 511 | |
| 512 document().view()->updateAllLifecyclePhases(); | |
| 513 | |
| 514 HistogramTester histogramTester; | |
| 515 | |
| 516 // Test touch scroll. | |
| 517 ScrollBeginEventBuilder touchScrollBegin( | |
| 518 IntPoint(50, 50), FloatPoint(0.f, 1.f), WebGestureDeviceTouchscreen); | |
| 519 ScrollEndEventBuilder touchScrollEnd; | |
| 520 document().frame()->eventHandler().handleGestureEvent(touchScrollBegin); | |
| 521 document().frame()->eventHandler().handleGestureEvent(touchScrollEnd); | |
| 522 histogramTester.expectBucketCount( | |
| 523 "Renderer4.MainThreadGestureScrollReason", | |
| 524 getBucketIndex(MainThreadScrollingReason::kHasOpacityAndLCDText), 1); | |
| 525 | |
| 526 document().frame()->eventHandler().handleGestureEvent(touchScrollBegin); | |
| 527 document().frame()->eventHandler().handleGestureEvent(touchScrollEnd); | |
|
bokan
2017/04/07 21:05:56
I'd throw two GestureScrollUpdates between this, j
yigu
2017/04/10 20:39:05
Done.
| |
| 528 histogramTester.expectBucketCount( | |
| 529 "Renderer4.MainThreadGestureScrollReason", | |
| 530 getBucketIndex(MainThreadScrollingReason::kHasOpacityAndLCDText), 2); | |
| 531 | |
| 532 // Test wheel scroll. | |
| 533 ScrollBeginEventBuilder wheelScrollBegin( | |
| 534 IntPoint(50, 50), FloatPoint(0.f, 1.f), WebGestureDeviceTouchpad); | |
| 535 ScrollEndEventBuilder wheelScrollEnd; | |
| 536 document().frame()->eventHandler().handleGestureEvent(wheelScrollBegin); | |
| 537 document().frame()->eventHandler().handleGestureEvent(wheelScrollEnd); | |
| 538 histogramTester.expectBucketCount( | |
| 539 "Renderer4.MainThreadWheelScrollReason", | |
|
bokan
2017/04/07 21:05:57
You can improve readability of your expectations w
yigu
2017/04/10 20:39:05
It looks MUCH better with this improvement. Thanks
| |
| 540 getBucketIndex(MainThreadScrollingReason::kHasOpacityAndLCDText), 1); | |
| 541 histogramTester.expectBucketCount( | |
| 542 "Renderer4.MainThreadWheelScrollReason", | |
| 543 getBucketIndex( | |
| 544 MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText), | |
|
bokan
2017/04/07 21:05:57
Why do we get this reason for touch but not wheel?
yigu
2017/04/10 20:39:05
Done.
| |
| 545 1); | |
| 546 histogramTester.expectTotalCount("Renderer4.MainThreadWheelScrollReason", 2); | |
| 547 } | |
| 548 | |
| 549 TEST_F(EventHandlerTest, | |
| 550 NonCompositedMainThreadScrollingReasonWithCompositedScrollableAreaTest) { | |
| 551 setHtmlInnerHTML( | |
| 552 "<style>" | |
| 553 " .box { overflow:scroll; width: 100px; height: 100px; }" | |
| 554 " .translucent { opacity: 0.5; }" | |
| 555 " .composited { will-change: transform; }" | |
| 556 " .spacer { height: 1000px; }" | |
| 557 "</style>" | |
| 558 "<div id='box' class='translucent box'>" | |
| 559 " <div class='spacer'></div>" | |
| 560 "</div>"); | |
| 561 | |
| 562 page().settings().setAcceleratedCompositingEnabled(true); | |
| 563 document().view()->setParentVisible(true); | |
|
bokan
2017/04/07 21:05:57
Why is setParentVisible and setSelfVisible needed?
yigu
2017/04/10 20:39:05
We have to use these to make sure the test box get
| |
| 564 document().view()->setSelfVisible(true); | |
| 565 document().view()->updateAllLifecyclePhases(); | |
| 566 | |
| 567 HistogramTester histogramTester; | |
| 568 | |
| 569 ScrollBeginEventBuilder wheelScrollBegin( | |
| 570 IntPoint(50, 50), FloatPoint(0.f, 1.f), WebGestureDeviceTouchpad); | |
| 571 ScrollEndEventBuilder wheelScrollEnd; | |
| 572 document().frame()->eventHandler().handleGestureEvent(wheelScrollBegin); | |
| 573 document().frame()->eventHandler().handleGestureEvent(wheelScrollEnd); | |
|
bokan
2017/04/07 21:05:57
Another way to make this more readable is to wrap
yigu
2017/04/10 20:39:05
Done.
| |
| 574 histogramTester.expectBucketCount( | |
| 575 "Renderer4.MainThreadWheelScrollReason", | |
| 576 getBucketIndex(MainThreadScrollingReason::kHasOpacityAndLCDText), 1); | |
| 577 | |
| 578 Element* box = document().getElementById("box"); | |
| 579 box->setAttribute("class", "composited translucent box"); | |
| 580 document().view()->updateAllLifecyclePhases(); | |
| 581 document().frame()->eventHandler().handleGestureEvent(wheelScrollBegin); | |
| 582 document().frame()->eventHandler().handleGestureEvent(wheelScrollEnd); | |
|
bokan
2017/04/07 21:05:57
Lets also EXPECT box's PLSA::getNonCompositedMainT
yigu
2017/04/10 20:39:04
Done.
| |
| 583 histogramTester.expectBucketCount( | |
| 584 "Renderer4.MainThreadWheelScrollReason", | |
| 585 getBucketIndex(MainThreadScrollingReason::kHasOpacityAndLCDText), 1); | |
|
bokan
2017/04/07 21:05:57
It'd be safer to check that the total count didn't
yigu
2017/04/10 20:39:04
Done.
| |
| 586 } | |
| 587 | |
| 588 TEST_F(EventHandlerTest, | |
| 589 NonCompositedMainThreadScrollingReasonWithNotScrollableAreaTest) { | |
| 590 setHtmlInnerHTML( | |
| 591 "<style>.box { overflow:scroll; width: 100px; height: 100px; }" | |
| 592 " .translucent { opacity: 0.5; }" | |
| 593 " .hidden { overflow: hidden; }" | |
| 594 " .spacer { height: 1000px; }" | |
| 595 "</style>" | |
| 596 "<div id='box' class='translucent box'>" | |
| 597 " <div class='spacer'></div>" | |
| 598 "</div>"); | |
| 599 | |
| 600 document().view()->updateAllLifecyclePhases(); | |
| 601 | |
| 602 HistogramTester histogramTester; | |
| 603 | |
| 604 ScrollBeginEventBuilder wheelScrollBegin( | |
| 605 IntPoint(50, 50), FloatPoint(0.f, 1.f), WebGestureDeviceTouchpad); | |
| 606 ScrollEndEventBuilder wheelScrollEnd; | |
| 607 document().frame()->eventHandler().handleGestureEvent(wheelScrollBegin); | |
| 608 document().frame()->eventHandler().handleGestureEvent(wheelScrollEnd); | |
| 609 histogramTester.expectBucketCount( | |
| 610 "Renderer4.MainThreadWheelScrollReason", | |
| 611 getBucketIndex(MainThreadScrollingReason::kHasOpacityAndLCDText), 1); | |
| 612 | |
| 613 Element* box = document().getElementById("box"); | |
| 614 box->setAttribute("class", "hidden translucent box"); | |
| 615 document().view()->updateAllLifecyclePhases(); | |
| 616 document().frame()->eventHandler().handleGestureEvent(wheelScrollBegin); | |
| 617 document().frame()->eventHandler().handleGestureEvent(wheelScrollEnd); | |
| 618 histogramTester.expectBucketCount( | |
|
bokan
2017/04/07 21:05:57
Check total count.
yigu
2017/04/10 20:39:05
Done.
| |
| 619 "Renderer4.MainThreadWheelScrollReason", | |
| 620 getBucketIndex(MainThreadScrollingReason::kHasOpacityAndLCDText), 1); | |
| 621 } | |
| 622 | |
| 623 TEST_F(EventHandlerTest, | |
| 624 NonCompositedMainThreadScrollingReasonWithNestedScrollersTest) { | |
| 625 setHtmlInnerHTML( | |
| 626 "<style>" | |
| 627 " .container { overflow:scroll; width: 200px; height: 200px; }" | |
| 628 " .box { overflow:scroll; width: 100px; height: 100px; }" | |
| 629 " .translucent { opacity: 0.5; }" | |
| 630 " .transform { transform: scale(0.8); }" | |
| 631 " .with-border-radius { border: 5px solid; border-radius: 5px; }" | |
| 632 " .spacer { height: 1000px; }" | |
| 633 " .composited { will-change: transform; }" | |
| 634 "</style>" | |
| 635 "<div id='container' class='container with-border-radius'>" | |
| 636 " <div class='translucent box'>" | |
| 637 " <div class='composited transform box'>" | |
| 638 " <div class='spacer'></div>" | |
| 639 " </div>" | |
| 640 " </div>" | |
| 641 " <div class='spacer'></div>" | |
| 642 "</div>"); | |
| 643 | |
| 644 page().settings().setAcceleratedCompositingEnabled(true); | |
| 645 document().view()->setParentVisible(true); | |
| 646 document().view()->setSelfVisible(true); | |
| 647 document().view()->updateAllLifecyclePhases(); | |
| 648 | |
| 649 HistogramTester histogramTester; | |
| 650 | |
| 651 ScrollBeginEventBuilder wheelScrollBegin( | |
| 652 IntPoint(50, 50), FloatPoint(0.f, 1.f), WebGestureDeviceTouchpad); | |
| 653 ScrollEndEventBuilder wheelScrollEnd; | |
| 654 document().frame()->eventHandler().handleGestureEvent(wheelScrollBegin); | |
| 655 document().frame()->eventHandler().handleGestureEvent(wheelScrollEnd); | |
| 656 histogramTester.expectBucketCount( | |
|
bokan
2017/04/07 21:05:57
This test is a little more complex, some comments
yigu
2017/04/10 20:39:05
Done.
| |
| 657 "Renderer4.MainThreadWheelScrollReason", | |
| 658 getBucketIndex(MainThreadScrollingReason::kHasOpacityAndLCDText), 1); | |
|
bokan
2017/04/07 21:05:57
This one comes from "translucent box" right? Isn't
yigu
2017/04/10 20:39:05
It's actually scrollable (see jsbin.com/muluhes).
| |
| 659 histogramTester.expectBucketCount( | |
| 660 "Renderer4.MainThreadWheelScrollReason", | |
| 661 getBucketIndex( | |
| 662 MainThreadScrollingReason::kBackgroundNotOpaqueInRectAndLCDText), | |
|
bokan
2017/04/07 21:05:57
This one comes from all of them, right?
yigu
2017/04/10 20:39:05
In this case yes. Usually we set this reason whene
| |
| 663 1); | |
| 664 histogramTester.expectBucketCount( | |
| 665 "Renderer4.MainThreadWheelScrollReason", | |
| 666 getBucketIndex(MainThreadScrollingReason::kHasBorderRadius), 1); | |
| 667 histogramTester.expectBucketCount( | |
| 668 "Renderer4.MainThreadWheelScrollReason", | |
| 669 getBucketIndex(MainThreadScrollingReason::kHasTransformAndLCDText), 0); | |
| 670 histogramTester.expectTotalCount("Renderer4.MainThreadWheelScrollReason", 3); | |
| 671 } | |
| 672 | |
| 464 class TooltipCapturingChromeClient : public EmptyChromeClient { | 673 class TooltipCapturingChromeClient : public EmptyChromeClient { |
| 465 public: | 674 public: |
| 466 TooltipCapturingChromeClient() {} | 675 TooltipCapturingChromeClient() {} |
| 467 | 676 |
| 468 void setToolTip(LocalFrame&, const String& str, TextDirection) override { | 677 void setToolTip(LocalFrame&, const String& str, TextDirection) override { |
| 469 m_lastToolTip = str; | 678 m_lastToolTip = str; |
| 470 } | 679 } |
| 471 | 680 |
| 472 String& lastToolTip() { return m_lastToolTip; } | 681 String& lastToolTip() { return m_lastToolTip; } |
| 473 | 682 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 514 WebInputEvent::MouseLeave, WebFloatPoint(0, 0), WebFloatPoint(0, 0), | 723 WebInputEvent::MouseLeave, WebFloatPoint(0, 0), WebFloatPoint(0, 0), |
| 515 WebPointerProperties::Button::NoButton, 0, WebInputEvent::NoModifiers, | 724 WebPointerProperties::Button::NoButton, 0, WebInputEvent::NoModifiers, |
| 516 TimeTicks::Now().InSeconds()); | 725 TimeTicks::Now().InSeconds()); |
| 517 mouseLeaveEvent.setFrameScale(1); | 726 mouseLeaveEvent.setFrameScale(1); |
| 518 document().frame()->eventHandler().handleMouseLeaveEvent(mouseLeaveEvent); | 727 document().frame()->eventHandler().handleMouseLeaveEvent(mouseLeaveEvent); |
| 519 | 728 |
| 520 EXPECT_EQ(WTF::String(), lastToolTip()); | 729 EXPECT_EQ(WTF::String(), lastToolTip()); |
| 521 } | 730 } |
| 522 | 731 |
| 523 } // namespace blink | 732 } // namespace blink |
| OLD | NEW |