Commit 1760ef3d authored by chaopeng's avatar chaopeng Committed by Commit Bot

Store the last_show_press_timestamp_ in root frame EventHandler

This issue is caused by:

1. When user tap on screen, we receive TapDown, ShowPress, Tap.
   TapDown and ShowPress will active the tapped element. Then Tap
   checks the LastShowPressTimeStamp() to stay active or cancel.
2. Each frame has GestureManager and we store LastShowPressTimeStamp()
   in GestureManager.
3. We check the root frame GestureManager LastShowPressTimeStamp()
   before hit test so we read the wrong LastShowPressTimeStamp().

In this patch, we move last_show_press_timestamp_ to root frame
EventHandler so we don't need to hit test and figure which
GestureManager should use.

Bug: 714573
Change-Id: I80c75bf2f0493a6cbfd3b24873e1127da4fd7a27
Test: EventHandlerSimTest_TapActiveInFrame
Test: Manual test for OOPIF
Reviewed-on: https://chromium-review.googlesource.com/1041065Reviewed-by: default avatarDavid Bokan <bokan@chromium.org>
Commit-Queue: Jianpeng Chao <chaopeng@chromium.org>
Cr-Commit-Position: refs/heads/master@{#555719}
parent 1cecc366
...@@ -209,6 +209,7 @@ void EventHandler::Clear() { ...@@ -209,6 +209,7 @@ void EventHandler::Clear() {
gesture_manager_->Clear(); gesture_manager_->Clear();
mouse_event_manager_->Clear(); mouse_event_manager_->Clear();
mouse_wheel_event_manager_->Clear(); mouse_wheel_event_manager_->Clear();
last_show_press_timestamp_.reset();
last_deferred_tap_element_ = nullptr; last_deferred_tap_element_ = nullptr;
event_handler_will_reset_capturing_mouse_events_node_ = false; event_handler_will_reset_capturing_mouse_events_node_ = false;
should_use_touch_event_adjusted_point_ = false; should_use_touch_event_adjusted_point_ = false;
...@@ -1323,6 +1324,9 @@ WebInputEventResult EventHandler::HandleGestureEvent( ...@@ -1323,6 +1324,9 @@ WebInputEventResult EventHandler::HandleGestureEvent(
// etc. // etc.
DCHECK(!targeted_event.Event().IsScrollEvent()); DCHECK(!targeted_event.Event().IsScrollEvent());
if (targeted_event.Event().GetType() == WebInputEvent::kGestureShowPress)
last_show_press_timestamp_ = CurrentTimeTicks();
// Update mouseout/leave/over/enter events before jumping directly to the // Update mouseout/leave/over/enter events before jumping directly to the
// inner most frame. // inner most frame.
if (targeted_event.Event().GetType() == WebInputEvent::kGestureTap) if (targeted_event.Event().GetType() == WebInputEvent::kGestureTap)
...@@ -1641,12 +1645,11 @@ GestureEventWithHitTestResults EventHandler::TargetGestureEvent( ...@@ -1641,12 +1645,11 @@ GestureEventWithHitTestResults EventHandler::TargetGestureEvent(
if (read_only) { if (read_only) {
hit_type |= HitTestRequest::kReadOnly; hit_type |= HitTestRequest::kReadOnly;
} else if (gesture_event.GetType() == WebInputEvent::kGestureTap && } else if (gesture_event.GetType() == WebInputEvent::kGestureTap &&
gesture_manager_->GetLastShowPressTimestamp()) { last_show_press_timestamp_) {
// If the Tap is received very shortly after ShowPress, we want to // If the Tap is received very shortly after ShowPress, we want to
// delay clearing of the active state so that it's visible to the user // delay clearing of the active state so that it's visible to the user
// for at least a couple of frames. // for at least a couple of frames.
active_interval = CurrentTimeTicks() - active_interval = CurrentTimeTicks() - last_show_press_timestamp_.value();
gesture_manager_->GetLastShowPressTimestamp().value();
should_keep_active_for_min_interval = should_keep_active_for_min_interval =
active_interval < kMinimumActiveInterval; active_interval < kMinimumActiveInterval;
if (should_keep_active_for_min_interval) if (should_keep_active_for_min_interval)
...@@ -1657,9 +1660,10 @@ GestureEventWithHitTestResults EventHandler::TargetGestureEvent( ...@@ -1657,9 +1660,10 @@ GestureEventWithHitTestResults EventHandler::TargetGestureEvent(
HitTestResultForGestureEvent(gesture_event, hit_type); HitTestResultForGestureEvent(gesture_event, hit_type);
// Now apply hover/active state to the final target. // Now apply hover/active state to the final target.
HitTestRequest request(hit_type | HitTestRequest::kAllowChildFrameContent); HitTestRequest request(hit_type | HitTestRequest::kAllowChildFrameContent);
if (!request.ReadOnly()) if (!request.ReadOnly()) {
UpdateGestureHoverActiveState( UpdateGestureHoverActiveState(
request, event_with_hit_test_results.GetHitTestResult().InnerElement()); request, event_with_hit_test_results.GetHitTestResult().InnerElement());
}
if (should_keep_active_for_min_interval) { if (should_keep_active_for_min_interval) {
last_deferred_tap_element_ = last_deferred_tap_element_ =
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "third_party/blink/public/platform/web_input_event.h" #include "third_party/blink/public/platform/web_input_event.h"
#include "third_party/blink/public/platform/web_input_event_result.h" #include "third_party/blink/public/platform/web_input_event_result.h"
#include "third_party/blink/public/platform/web_menu_source_type.h" #include "third_party/blink/public/platform/web_menu_source_type.h"
...@@ -51,6 +52,7 @@ ...@@ -51,6 +52,7 @@
#include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h" #include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/hash_traits.h" #include "third_party/blink/renderer/platform/wtf/hash_traits.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace blink { namespace blink {
...@@ -398,7 +400,13 @@ class CORE_EXPORT EventHandler final ...@@ -398,7 +400,13 @@ class CORE_EXPORT EventHandler final
bool long_tap_should_invoke_context_menu_; bool long_tap_should_invoke_context_menu_;
TaskRunnerTimer<EventHandler> active_interval_timer_; TaskRunnerTimer<EventHandler> active_interval_timer_;
double last_show_press_timestamp_;
// last_show_press_timestamp_ prevents the active state rewrited by following
// events too soon (less than 0.15s).
// It is ok we only record last_show_press_timestamp_ in root frame since
// root frame will have subframe as active element if subframe has active
// element.
base::Optional<WTF::TimeTicks> last_show_press_timestamp_;
Member<Element> last_deferred_tap_element_; Member<Element> last_deferred_tap_element_;
// Set on GestureTapDown if unique_touch_event_id_ matches cached adjusted // Set on GestureTapDown if unique_touch_event_id_ matches cached adjusted
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/testing/page_test_base.h" #include "third_party/blink/renderer/core/testing/page_test_base.h"
#include "third_party/blink/renderer/core/testing/sim/sim_request.h" #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h" #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
namespace blink { namespace blink {
...@@ -55,6 +56,36 @@ class TapEventBuilder : public WebGestureEvent { ...@@ -55,6 +56,36 @@ class TapEventBuilder : public WebGestureEvent {
} }
}; };
class TapDownEventBuilder : public WebGestureEvent {
public:
TapDownEventBuilder(FloatPoint position)
: WebGestureEvent(WebInputEvent::kGestureTapDown,
WebInputEvent::kNoModifiers,
CurrentTimeTicks(),
kWebGestureDeviceTouchscreen) {
SetPositionInWidget(position);
SetPositionInScreen(position);
data.tap_down.width = 5;
data.tap_down.height = 5;
frame_scale_ = 1;
}
};
class ShowPressEventBuilder : public WebGestureEvent {
public:
ShowPressEventBuilder(FloatPoint position)
: WebGestureEvent(WebInputEvent::kGestureShowPress,
WebInputEvent::kNoModifiers,
CurrentTimeTicks(),
kWebGestureDeviceTouchscreen) {
SetPositionInWidget(position);
SetPositionInScreen(position);
data.show_press.width = 5;
data.show_press.height = 5;
frame_scale_ = 1;
}
};
class LongPressEventBuilder : public WebGestureEvent { class LongPressEventBuilder : public WebGestureEvent {
public: public:
LongPressEventBuilder(FloatPoint position) LongPressEventBuilder(FloatPoint position)
...@@ -1154,4 +1185,68 @@ TEST_F(EventHandlerSimTest, CursorStyleBeforeStartDragging) { ...@@ -1154,4 +1185,68 @@ TEST_F(EventHandlerSimTest, CursorStyleBeforeStartDragging) {
.GetType()); .GetType());
} }
// Ensure that tap on element in iframe should apply active state.
TEST_F(EventHandlerSimTest, TapActiveInFrame) {
WebView().Resize(WebSize(800, 600));
SimRequest main_resource("https://example.com/test.html", "text/html");
SimRequest frame_resource("https://example.com/iframe.html", "text/html");
LoadURL("https://example.com/test.html");
main_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
iframe {
width: 200px;
height: 200px;
}
</style>
<iframe id='iframe' src='iframe.html'>
</iframe>
)HTML");
frame_resource.Complete(R"HTML(
<!DOCTYPE html>
<style>
body {
margin: 0;
}
div {
width: 100px;
height: 100px;
}
</style>
<div></div>
)HTML");
Compositor().BeginFrame();
auto* iframe_element =
ToHTMLIFrameElement(GetDocument().getElementById("iframe"));
Document* iframe_doc = iframe_element->contentDocument();
TapDownEventBuilder tap_down(FloatPoint(10, 10));
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(tap_down);
ShowPressEventBuilder show_press(FloatPoint(10, 10));
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(show_press);
// TapDown and ShowPress active the iframe.
EXPECT_TRUE(GetDocument().GetActiveElement());
EXPECT_TRUE(iframe_doc->GetActiveElement());
TapEventBuilder tap(FloatPoint(10, 10), 1);
GetDocument().GetFrame()->GetEventHandler().HandleGestureEvent(tap);
// Should still active.
EXPECT_TRUE(GetDocument().GetActiveElement());
EXPECT_TRUE(iframe_doc->GetActiveElement());
// The active will cancel after 15ms.
test::RunDelayedTasks(TimeDelta::FromSecondsD(0.2));
EXPECT_FALSE(GetDocument().GetActiveElement());
EXPECT_FALSE(iframe_doc->GetActiveElement());
}
} // namespace blink } // namespace blink
...@@ -49,7 +49,6 @@ GestureManager::GestureManager(LocalFrame& frame, ...@@ -49,7 +49,6 @@ GestureManager::GestureManager(LocalFrame& frame,
void GestureManager::Clear() { void GestureManager::Clear() {
suppress_mouse_events_from_gestures_ = false; suppress_mouse_events_from_gestures_ = false;
long_tap_should_invoke_context_menu_ = false; long_tap_should_invoke_context_menu_ = false;
last_show_press_timestamp_.reset();
} }
void GestureManager::Trace(blink::Visitor* visitor) { void GestureManager::Trace(blink::Visitor* visitor) {
...@@ -430,8 +429,6 @@ WebInputEventResult GestureManager::SendContextMenuEventForGesture( ...@@ -430,8 +429,6 @@ WebInputEventResult GestureManager::SendContextMenuEventForGesture(
} }
WebInputEventResult GestureManager::HandleGestureShowPress() { WebInputEventResult GestureManager::HandleGestureShowPress() {
last_show_press_timestamp_ = CurrentTimeTicks();
LocalFrameView* view = frame_->View(); LocalFrameView* view = frame_->View();
if (!view) if (!view)
return WebInputEventResult::kNotHandled; return WebInputEventResult::kNotHandled;
...@@ -448,11 +445,6 @@ WebInputEventResult GestureManager::HandleGestureShowPress() { ...@@ -448,11 +445,6 @@ WebInputEventResult GestureManager::HandleGestureShowPress() {
return WebInputEventResult::kNotHandled; return WebInputEventResult::kNotHandled;
} }
base::Optional<WTF::TimeTicks> GestureManager::GetLastShowPressTimestamp()
const {
return last_show_press_timestamp_;
}
void GestureManager::ShowUnhandledTapUIIfNeeded( void GestureManager::ShowUnhandledTapUIIfNeeded(
bool dom_tree_changed, bool dom_tree_changed,
bool style_changed, bool style_changed,
......
...@@ -6,13 +6,11 @@ ...@@ -6,13 +6,11 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_INPUT_GESTURE_MANAGER_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_INPUT_GESTURE_MANAGER_H_
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h"
#include "third_party/blink/public/platform/web_input_event_result.h" #include "third_party/blink/public/platform/web_input_event_result.h"
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/layout/hit_test_request.h" #include "third_party/blink/renderer/core/layout/hit_test_request.h"
#include "third_party/blink/renderer/core/page/event_with_hit_test_results.h" #include "third_party/blink/renderer/core/page/event_with_hit_test_results.h"
#include "third_party/blink/renderer/platform/wtf/time.h"
namespace blink { namespace blink {
...@@ -41,11 +39,6 @@ class CORE_EXPORT GestureManager ...@@ -41,11 +39,6 @@ class CORE_EXPORT GestureManager
WebInputEventResult HandleGestureEventInFrame( WebInputEventResult HandleGestureEventInFrame(
const GestureEventWithHitTestResults&); const GestureEventWithHitTestResults&);
// TODO(nzolghadr): This can probably be hidden and the related logic
// be moved to this class (see crrev.com/112023010). Since that might cause
// regression it's better to move that logic in another change.
base::Optional<WTF::TimeTicks> GetLastShowPressTimestamp() const;
private: private:
WebInputEventResult HandleGestureShowPress(); WebInputEventResult HandleGestureShowPress();
WebInputEventResult HandleGestureTapDown( WebInputEventResult HandleGestureTapDown(
...@@ -85,7 +78,6 @@ class CORE_EXPORT GestureManager ...@@ -85,7 +78,6 @@ class CORE_EXPORT GestureManager
const Member<SelectionController> selection_controller_; const Member<SelectionController> selection_controller_;
base::Optional<WTF::TimeTicks> last_show_press_timestamp_;
DISALLOW_COPY_AND_ASSIGN(GestureManager); DISALLOW_COPY_AND_ASSIGN(GestureManager);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment