Commit f569b4f6 authored by lazyboy's avatar lazyboy Committed by Commit bot

<webview> fix drag and drop issues.

This CL makes sure following scenarios work properly on mac/linux/cros/win:
1. Dragging and dropping within a <webview> works
2. Dragging from one <webview> to another <webview> works.
3. Dragging from one <webview> and cancelling it by releasing mouse
  on non-droppable target works where there can be 3 cases:
    a. the release is done within the same <webview>
    b. the release is done within a different <webview>
    c. the release is done outside of any <webview>, i.e. the embedder.

The key fix here is to call guest RVH->DragSourceSystemDragEnded() correctly
on the guest where the drag was initiated. Calling DragSourceSystemDragEnded()
correctly means we call it in all cases and also make sure we only call it once.
This ensures that the input state of the guest stays correct, otherwise it will go
stale and won't accept any further input events.

The strategy I've used to call DragSourceSystemDragEnded() on a guest RVH when
the following conditions are met:
a. Embedder has seen SystemDragEnded()
b. Embedder has seen DragSourceEndedAt()
c. The guest has seen some drag status update other than WebDragStatusUnknown.

Note that c) should ideally be done differently: The guest has seen at least one of
{WebDragStatusOver, WebDragStatusDrop}. However, if a user drags a source
quickly outside of <webview> bounds, then the BrowserPluginGuest never sees
any of these drag status updates.

BUG=450175
Test=
1) On webview based signin page, try dragging some text from the signin page to user name field, it should now work.
2) Load a chrome app with two <webview>s
e.g. https://github.com/lazyboy/chromium/tree/master/tests/chrome-apps/webview_input
Now see there are two <webview>s, one red and one blue, perform following and expect things to work correctly:

a. select and drag text from red webview, e.g. "this is guest", to an tex box within the same webview, expect it to insert that text to the <input> box.
b. now do the same as a), but drag it to the text box within the second/blue <webview>, expect that text to be inserted.
c. select and drag text from red <webview>, drag it but stay within the red <webview> and release it somewhere where there's no text box, expect the drag operation to be cancelled properly, make sure you can still type in the text box of that <webview>.
d. do the same as c) but release it somewhere in the blue <webview> where there's no input box, expect the same, make sure you can type in both <webview>'s input box.
e. do the same as c), but release it somewhere in the app where there's no input box (white background), expect the same and make sure you can type in both <webview>'s input box.

Review URL: https://codereview.chromium.org/885803002

Cr-Commit-Position: refs/heads/master@{#314356}
parent 5c9c165e
...@@ -124,7 +124,8 @@ void BrowserPluginEmbedder::SystemDragEnded() { ...@@ -124,7 +124,8 @@ void BrowserPluginEmbedder::SystemDragEnded() {
// to the guest that initiated the drag/drop operation. This will ensure that // to the guest that initiated the drag/drop operation. This will ensure that
// the guest's RVH state is reset properly. // the guest's RVH state is reset properly.
if (guest_started_drag_) if (guest_started_drag_)
guest_started_drag_->EndSystemDrag(); guest_started_drag_->EmbedderSystemDragEnded();
guest_dragging_over_.reset(); guest_dragging_over_.reset();
ClearGuestDragStateIfApplicable(); ClearGuestDragStateIfApplicable();
} }
......
...@@ -91,6 +91,9 @@ BrowserPluginGuest::BrowserPluginGuest(bool has_render_view, ...@@ -91,6 +91,9 @@ BrowserPluginGuest::BrowserPluginGuest(bool has_render_view,
last_input_flags_(0), last_input_flags_(0),
last_can_compose_inline_(true), last_can_compose_inline_(true),
guest_proxy_routing_id_(MSG_ROUTING_NONE), guest_proxy_routing_id_(MSG_ROUTING_NONE),
last_drag_status_(blink::WebDragStatusUnknown),
seen_embedder_system_drag_ended_(false),
seen_embedder_drag_source_ended_at_(false),
delegate_(delegate), delegate_(delegate),
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
DCHECK(web_contents); DCHECK(web_contents);
...@@ -417,12 +420,45 @@ void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y, ...@@ -417,12 +420,45 @@ void BrowserPluginGuest::DragSourceEndedAt(int client_x, int client_y,
int screen_x, int screen_y, blink::WebDragOperation operation) { int screen_x, int screen_y, blink::WebDragOperation operation) {
web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y, web_contents()->GetRenderViewHost()->DragSourceEndedAt(client_x, client_y,
screen_x, screen_y, operation); screen_x, screen_y, operation);
seen_embedder_drag_source_ended_at_ = true;
EndSystemDragIfApplicable();
} }
void BrowserPluginGuest::EndSystemDrag() { void BrowserPluginGuest::EndSystemDragIfApplicable() {
RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>( // Ideally we'd want either WebDragStatusDrop or WebDragStatusLeave...
GetWebContents()->GetRenderViewHost()); // Call guest RVH->DragSourceSystemDragEnded() correctly on the guest where
guest_rvh->DragSourceSystemDragEnded(); // the drag was initiated. Calling DragSourceSystemDragEnded() correctly
// means we call it in all cases and also make sure we only call it once.
// This ensures that the input state of the guest stays correct, otherwise
// it will go stale and won't accept any further input events.
//
// The strategy used here to call DragSourceSystemDragEnded() on the RVH
// is when the following conditions are met:
// a. Embedder has seen SystemDragEnded()
// b. Embedder has seen DragSourceEndedAt()
// c. The guest has seen some drag status update other than
// WebDragStatusUnknown. Note that this step should ideally be done
// differently: The guest has seen at least one of
// {WebDragStatusOver, WebDragStatusDrop}. However, if a user drags
// a source quickly outside of <webview> bounds, then the
// BrowserPluginGuest never sees any of these drag status updates,
// there we just check whether we've seen any drag status update or
// not.
if (last_drag_status_ != blink::WebDragStatusOver &&
seen_embedder_drag_source_ended_at_ && seen_embedder_system_drag_ended_) {
RenderViewHostImpl* guest_rvh = static_cast<RenderViewHostImpl*>(
GetWebContents()->GetRenderViewHost());
guest_rvh->DragSourceSystemDragEnded();
last_drag_status_ = blink::WebDragStatusUnknown;
seen_embedder_system_drag_ended_ = false;
seen_embedder_drag_source_ended_at_ = false;
}
}
void BrowserPluginGuest::EmbedderSystemDragEnded() {
seen_embedder_system_drag_ended_ = true;
EndSystemDragIfApplicable();
} }
void BrowserPluginGuest::SendQueuedMessages() { void BrowserPluginGuest::SendQueuedMessages() {
...@@ -649,11 +685,12 @@ void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id, ...@@ -649,11 +685,12 @@ void BrowserPluginGuest::OnDragStatusUpdate(int browser_plugin_instance_id,
break; break;
case blink::WebDragStatusDrop: case blink::WebDragStatusDrop:
host->DragTargetDrop(location, location, 0); host->DragTargetDrop(location, location, 0);
EndSystemDrag();
break; break;
case blink::WebDragStatusUnknown: case blink::WebDragStatusUnknown:
NOTREACHED(); NOTREACHED();
} }
last_drag_status_ = drag_status;
EndSystemDragIfApplicable();
} }
void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id, void BrowserPluginGuest::OnExecuteEditCommand(int browser_plugin_instance_id,
......
...@@ -198,7 +198,8 @@ class CONTENT_EXPORT BrowserPluginGuest : public GuestSizer, ...@@ -198,7 +198,8 @@ class CONTENT_EXPORT BrowserPluginGuest : public GuestSizer,
int screen_y, blink::WebDragOperation operation); int screen_y, blink::WebDragOperation operation);
// Called when the drag started by this guest ends at an OS-level. // Called when the drag started by this guest ends at an OS-level.
void EndSystemDrag(); void EmbedderSystemDragEnded();
void EndSystemDragIfApplicable();
void RespondToPermissionRequest(int request_id, void RespondToPermissionRequest(int request_id,
bool should_allow, bool should_allow,
...@@ -387,6 +388,12 @@ class CONTENT_EXPORT BrowserPluginGuest : public GuestSizer, ...@@ -387,6 +388,12 @@ class CONTENT_EXPORT BrowserPluginGuest : public GuestSizer,
// The is the routing ID for a swapped out RenderView for the guest // The is the routing ID for a swapped out RenderView for the guest
// WebContents in the embedder's process. // WebContents in the embedder's process.
int guest_proxy_routing_id_; int guest_proxy_routing_id_;
// Last seen state of drag status update.
blink::WebDragStatus last_drag_status_;
// Whether or not our embedder has seen a SystemDragEnded() call.
bool seen_embedder_system_drag_ended_;
// Whether or not our embedder has seen a DragSourceEndedAt() call.
bool seen_embedder_drag_source_ended_at_;
// Guests generate frames and send a CompositorFrameSwapped (CFS) message // Guests generate frames and send a CompositorFrameSwapped (CFS) message
// indicating the next frame is ready to be positioned and composited. // indicating the next frame is ready to be positioned and composited.
......
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