Skip to content

Commit

Permalink
Add support for files to drag interception
Browse files Browse the repository at this point in the history
Currently, the drag interception API in CDP can only drop
text based things like url lists or html. This patch extends
it to also support dropping files from the file system.

Bug: 1225587
Change-Id: I046f3e337cc10141ae2b33eef37cc3670647b0d5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2983535
Commit-Queue: Jan Scheffler <janscheffler@chromium.org>
Reviewed-by: Devlin <rdevlin.cronin@chromium.org>
Reviewed-by: Andrey Kosyakov <caseq@chromium.org>
Reviewed-by: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#905231}
  • Loading branch information
jschfflr authored and Chromium LUCI CQ committed Jul 26, 2021
1 parent af94fa2 commit ba7a853
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 11 deletions.
20 changes: 17 additions & 3 deletions content/browser/devtools/protocol/input_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,15 @@ DropData ProtocolDragDataToDropData(std::unique_ptr<Input::DragData> data) {
blink::mojom::DragDataPtr mojo_data =
blink::mojom::DragData::New(std::move(items), absl::nullopt,
network::mojom::ReferrerPolicy::kDefault);
return DragDataToDropData(*mojo_data);
DropData drop_data = DragDataToDropData(*mojo_data);

protocol::Array<protocol::String> default_value;
for (const auto& file : *data->GetFiles(&default_value)) {
drop_data.filenames.emplace_back(base::FilePath::FromUTF8Unsafe(file),
base::FilePath());
}

return drop_data;
}

} // namespace
Expand Down Expand Up @@ -517,11 +525,12 @@ class InputHandler::InputInjector
DISALLOW_COPY_AND_ASSIGN(InputInjector);
};

InputHandler::InputHandler()
InputHandler::InputHandler(bool allow_file_access)
: DevToolsDomainHandler(Input::Metainfo::domainName),
host_(nullptr),
page_scale_factor_(1.0),
last_id_(0) {}
last_id_(0),
allow_file_access_(allow_file_access) {}

InputHandler::~InputHandler() = default;

Expand Down Expand Up @@ -816,6 +825,11 @@ void InputHandler::DispatchDragEvent(
std::unique_ptr<Input::DragData> data,
Maybe<int> modifiers,
std::unique_ptr<DispatchDragEventCallback> callback) {
if (!allow_file_access_ && data->HasFiles()) {
callback->sendFailure(Response::InvalidParams("Not allowed"));
return;
}

RenderWidgetHostImpl* widget_host =
host_ ? host_->GetRenderWidgetHost() : nullptr;
if (!widget_host || !widget_host->delegate() ||
Expand Down
3 changes: 2 additions & 1 deletion content/browser/devtools/protocol/input_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ namespace protocol {

class InputHandler : public DevToolsDomainHandler, public Input::Backend {
public:
InputHandler();
explicit InputHandler(bool allow_file_access);
~InputHandler() override;

static std::vector<InputHandler*> ForAgentHost(DevToolsAgentHostImpl* host);
Expand Down Expand Up @@ -234,6 +234,7 @@ class InputHandler : public DevToolsDomainHandler, public Input::Backend {
int last_id_;
bool ignore_input_events_ = false;
bool intercept_drags_ = false;
const bool allow_file_access_;
std::set<int> pointer_ids_;
std::unique_ptr<SyntheticPointerDriver> synthetic_pointer_driver_;
base::flat_map<int, blink::WebTouchPoint> touch_points_;
Expand Down
3 changes: 2 additions & 1 deletion content/browser/devtools/render_frame_devtools_agent_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,8 @@ bool RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session,
session->AddHandler(std::make_unique<protocol::DOMHandler>(
session->GetClient()->MayReadLocalFiles()));
session->AddHandler(std::move(emulation_handler));
auto input_handler = std::make_unique<protocol::InputHandler>();
auto input_handler = std::make_unique<protocol::InputHandler>(
session->GetClient()->MayReadLocalFiles());
input_handler->OnPageScaleFactorChanged(page_scale_factor_);
session->AddHandler(std::move(input_handler));
session->AddHandler(std::make_unique<protocol::InspectorHandler>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3944,6 +3944,8 @@ domain Input
experimental type DragData extends object
properties
array of DragDataItem items
# List of filenames that should be included when dropping
optional array of string files
# Bit field representing allowed drag operations. Copy = 1, Link = 2, Move = 16
integer dragOperationsMask

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ div innerHTML:
wrong dragOperationsMask should not drop
div innerHTML:

Dropping files
div innerHTML: path1<br>

Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
(async function(testRunner) {
var {page, session, dp} = await testRunner.startHTML(`
var {page, session, dp} = await testRunner.startHTML(
`
<div contenteditable></div>
`, `Tests Input.dispatchDragEvent method.`);
`,
`Tests Input.dispatchDragEvent method.`);


function dumpError(message) {
if (message.error)
testRunner.log('Error: ' + message.error.message);
}
await session.evaluate(`document.querySelector('div').addEventListener('dragover', event => {
await session.evaluate(`
document.querySelector('div').addEventListener('dragover', event => {
event.dataTransfer.dropEffect = 'copy';
});
document.querySelector('div').addEventListener('drop', event => {
for (const item of event.dataTransfer.items) {
if (item.kind === 'file') {
event.target.innerHTML += item.getAsFile().name + '<br/>';
event.preventDefault();
}
}
})`);

testRunner.log('\nDropping plain text');
Expand All @@ -25,7 +37,6 @@
baseURL: 'https://example.com',
});


testRunner.log('\nDropping a link to example.com');
await drop({
mimeType: 'text/uri-list',
Expand All @@ -45,13 +56,17 @@
data: 'should not see this',
}, 2);

testRunner.log('\nDropping files');
await drop(null, 1, ['path1']);

testRunner.completeTest();


async function drop(item, dragOperationsMask = 1) {
async function drop(item, dragOperationsMask = 1, files = undefined) {
await session.evaluate(`document.querySelector('div').textContent = ''`);
const data = {
items: [item],
items: item ? [item] : [],
files,
dragOperationsMask,
};
dumpError(await dp.Input.dispatchDragEvent({
Expand Down

0 comments on commit ba7a853

Please sign in to comment.