1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <algorithm>
6 #include <initializer_list>
7 #include <memory>
8 #include <string>
9 #include <vector>
10 
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/files/file_path.h"
14 #include "base/macros.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/strings/pattern.h"
18 #include "base/strings/string_piece.h"
19 #include "base/strings/stringprintf.h"
20 #include "base/strings/utf_string_conversions.h"
21 #include "base/test/test_timeouts.h"
22 #include "base/threading/sequenced_task_runner_handle.h"
23 #include "build/build_config.h"
24 #include "chrome/browser/ui/browser.h"
25 #include "chrome/browser/ui/browser_commands.h"
26 #include "chrome/browser/ui/browser_window.h"
27 #include "chrome/browser/ui/tabs/tab_strip_model.h"
28 #include "chrome/browser/ui/view_ids.h"
29 #include "chrome/test/base/in_process_browser_test.h"
30 #include "chrome/test/base/interactive_test_utils.h"
31 #include "chrome/test/base/ui_test_utils.h"
32 #include "content/public/browser/navigation_controller.h"
33 #include "content/public/browser/render_frame_host.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/browser/web_contents.h"
36 #include "content/public/test/browser_test.h"
37 #include "content/public/test/browser_test_utils.h"
38 #include "content/public/test/content_browser_test.h"
39 #include "content/public/test/content_browser_test_utils.h"
40 #include "content/public/test/hit_test_region_observer.h"
41 #include "content/public/test/test_frame_navigation_observer.h"
42 #include "content/public/test/test_navigation_observer.h"
43 #include "content/public/test/test_utils.h"
44 #include "net/base/escape.h"
45 #include "net/base/filename_util.h"
46 #include "net/dns/mock_host_resolver.h"
47 #include "net/test/embedded_test_server/embedded_test_server.h"
48 #include "testing/gmock/include/gmock/gmock.h"
49 #include "testing/gtest/include/gtest/gtest.h"
50 #include "ui/aura/client/drag_drop_client.h"
51 #include "ui/aura/client/drag_drop_delegate.h"
52 #include "ui/aura/client/screen_position_client.h"
53 #include "ui/aura/window.h"
54 #include "ui/base/dragdrop/drag_drop_types.h"
55 #include "ui/base/dragdrop/drop_target_event.h"
56 #include "ui/base/dragdrop/os_exchange_data.h"
57 #include "ui/gfx/geometry/point.h"
58 #include "ui/gfx/geometry/rect.h"
59 #include "url/gurl.h"
60 
61 namespace chrome {
62 
63 namespace {
64 
65 // TODO(lukasza): Support testing on non-Aura platforms (i.e. Android + Mac?).
66 //
67 // Notes for the TODO above:
68 //
69 // - Why inject/simulate drag-and-drop events at the aura::Window* level.
70 //
71 //   - It seems better to inject into UI libraries to cover code *inside* these
72 //     libraries.  This might complicate simulation a little bit (i.e. picking
73 //     the right aura::Window and/or aura::client::DragDropDelegate to target),
74 //     but otherwise important bits of code wouldn't get test coverage (i.e.
75 //     directly injecting into RenderViewHost->DragTargetDragEnter seems wrong).
76 //
77 //   - In theory, we could introduce WebContentsImpl::DragTargetDragEnter (to be
78 //     used by all UI platforms - so reused by web_contents_view_android.cc,
79 //     web_contents_view_aura.cc, web_drag_dest_mac.mm), but it feels wrong - UI
80 //     libraries should already know which widget is the target of the event and
81 //     so should be able to talk directly to the right widget (i.e. WebContents
82 //     should not be responsible for mapping coordinates to a widget - this is
83 //     the job of the UI library).
84 //
85 // - Unknowns:
86 //
87 //   - Will this work for WebView and Plugin testing.
88 
89 // Test helper for simulating drag and drop happening in WebContents.
90 class DragAndDropSimulator {
91  public:
DragAndDropSimulator(content::WebContents * web_contents)92   explicit DragAndDropSimulator(content::WebContents* web_contents)
93       : web_contents_(web_contents) {}
94 
95   // Simulates notification that |text| was dragged from outside of the browser,
96   // into the specified |location| inside |web_contents|.
97   // |location| is relative to |web_contents|.
98   // Returns true upon success.
SimulateDragEnter(const gfx::Point & location,const std::string & text)99   bool SimulateDragEnter(const gfx::Point& location, const std::string& text) {
100     os_exchange_data_ = std::make_unique<ui::OSExchangeData>();
101     os_exchange_data_->SetString(base::UTF8ToUTF16(text));
102     return SimulateDragEnter(location, *os_exchange_data_);
103   }
104 
105   // Simulates notification that |url| was dragged from outside of the browser,
106   // into the specified |location| inside |web_contents|.
107   // |location| is relative to |web_contents|.
108   // Returns true upon success.
SimulateDragEnter(const gfx::Point & location,const GURL & url)109   bool SimulateDragEnter(const gfx::Point& location, const GURL& url) {
110     os_exchange_data_ = std::make_unique<ui::OSExchangeData>();
111     os_exchange_data_->SetURL(url, base::UTF8ToUTF16(url.spec()));
112     return SimulateDragEnter(location, *os_exchange_data_);
113   }
114 
115   // Simulates notification that |file| was dragged from outside of the browser,
116   // into the specified |location| inside |web_contents|.
117   // |location| is relative to |web_contents|.
118   // Returns true upon success.
SimulateDragEnter(const gfx::Point & location,const base::FilePath & file)119   bool SimulateDragEnter(const gfx::Point& location,
120                          const base::FilePath& file) {
121     os_exchange_data_ = std::make_unique<ui::OSExchangeData>();
122     os_exchange_data_->SetFilename(file);
123     return SimulateDragEnter(location, *os_exchange_data_);
124   }
125 
126   // Simulates dropping of the drag-and-dropped item.
127   // SimulateDragEnter needs to be called first.
128   // Returns true upon success.
SimulateDrop(const gfx::Point & location)129   bool SimulateDrop(const gfx::Point& location) {
130     if (!active_drag_event_) {
131       ADD_FAILURE() << "Cannot drop a drag that hasn't started yet.";
132       return false;
133     }
134 
135     aura::client::DragDropDelegate* delegate = GetDragDropDelegate();
136     if (!delegate)
137       return false;
138 
139     gfx::PointF event_location;
140     gfx::PointF event_root_location;
141     CalculateEventLocations(location, &event_location, &event_root_location);
142     active_drag_event_->set_location_f(event_location);
143     active_drag_event_->set_root_location_f(event_root_location);
144 
145     delegate->OnDragUpdated(*active_drag_event_);
146     delegate->OnPerformDrop(*active_drag_event_, std::move(os_exchange_data_));
147     return true;
148   }
149 
150  private:
SimulateDragEnter(const gfx::Point & location,const ui::OSExchangeData & data)151   bool SimulateDragEnter(const gfx::Point& location,
152                          const ui::OSExchangeData& data) {
153     if (active_drag_event_) {
154       ADD_FAILURE() << "Cannot start a new drag when old one hasn't ended yet.";
155       return false;
156     }
157 
158     aura::client::DragDropDelegate* delegate = GetDragDropDelegate();
159     if (!delegate)
160       return false;
161 
162     gfx::PointF event_location;
163     gfx::PointF event_root_location;
164     CalculateEventLocations(location, &event_location, &event_root_location);
165     active_drag_event_.reset(new ui::DropTargetEvent(
166         data, event_location, event_root_location, kDefaultSourceOperations));
167 
168     delegate->OnDragEntered(*active_drag_event_);
169     delegate->OnDragUpdated(*active_drag_event_);
170     return true;
171   }
172 
GetDragDropDelegate()173   aura::client::DragDropDelegate* GetDragDropDelegate() {
174     gfx::NativeView view = web_contents_->GetContentNativeView();
175     aura::client::DragDropDelegate* delegate =
176         aura::client::GetDragDropDelegate(view);
177     EXPECT_TRUE(delegate) << "Expecting WebContents to have DragDropDelegate";
178     return delegate;
179   }
180 
CalculateEventLocations(const gfx::Point & web_contents_relative_location,gfx::PointF * out_event_location,gfx::PointF * out_event_root_location)181   void CalculateEventLocations(const gfx::Point& web_contents_relative_location,
182                                gfx::PointF* out_event_location,
183                                gfx::PointF* out_event_root_location) {
184     gfx::NativeView view = web_contents_->GetNativeView();
185 
186     *out_event_location = gfx::PointF(web_contents_relative_location);
187 
188     gfx::Point root_location = web_contents_relative_location;
189     aura::Window::ConvertPointToTarget(view, view->GetRootWindow(),
190                                        &root_location);
191     *out_event_root_location = gfx::PointF(root_location);
192   }
193 
194   // These are ui::DropTargetEvent::source_operations_ being sent when manually
195   // trying out drag&drop of an image file from Nemo (Ubuntu's file explorer)
196   // into a content_shell.
197   static constexpr int kDefaultSourceOperations = ui::DragDropTypes::DRAG_MOVE |
198                                                   ui::DragDropTypes::DRAG_COPY |
199                                                   ui::DragDropTypes::DRAG_LINK;
200 
201   content::WebContents* web_contents_;
202   std::unique_ptr<ui::DropTargetEvent> active_drag_event_;
203   std::unique_ptr<ui::OSExchangeData> os_exchange_data_;
204 
205   DISALLOW_COPY_AND_ASSIGN(DragAndDropSimulator);
206 };
207 
208 // Helper for waiting until a drag-and-drop starts (e.g. in response to a
209 // mouse-down + mouse-move simulated by the test).
210 class DragStartWaiter : public aura::client::DragDropClient {
211  public:
212   // Starts monitoring |web_contents| for a start of a drag-and-drop.
DragStartWaiter(content::WebContents * web_contents)213   explicit DragStartWaiter(content::WebContents* web_contents)
214       : web_contents_(web_contents),
215         message_loop_runner_(new content::MessageLoopRunner),
216         suppress_passing_of_start_drag_further_(false),
217         drag_started_(false) {
218     DCHECK(web_contents_);
219 
220     // Intercept calls to the old DragDropClient.
221     gfx::NativeWindow root_window =
222         web_contents_->GetContentNativeView()->GetRootWindow();
223     old_client_ = aura::client::GetDragDropClient(root_window);
224     aura::client::SetDragDropClient(root_window, this);
225   }
226 
~DragStartWaiter()227   ~DragStartWaiter() override {
228     // Restore the original DragDropClient.
229     gfx::NativeWindow root_window =
230         web_contents_->GetContentNativeView()->GetRootWindow();
231     aura::client::SetDragDropClient(root_window, old_client_);
232   }
233 
234   // Waits until we almost report a drag-and-drop start to the OS.
235   // At that point
236   // 1) the callback from PostTaskWhenDragStarts will be posted.
237   // 2) the drag-start request will be forwarded to the OS
238   //    (unless SuppressPassingStartDragFurther method was called).
239   //
240   // Note that if SuppressPassingStartDragFurther was not called then
241   // WaitUntilDragStart can take a long time to return (it returns only after
242   // the OS decides that the drag-and-drop has ended).
243   //
244   // Before returning populates |text|, |html| and other parameters with data
245   // that would have been passed to the OS).  If the caller is not interested in
246   // this data, then the corresponding argument can be null.
WaitUntilDragStart(std::string * text,std::string * html,int * operation,gfx::Point * location_inside_web_contents)247   void WaitUntilDragStart(std::string* text,
248                           std::string* html,
249                           int* operation,
250                           gfx::Point* location_inside_web_contents) {
251     message_loop_runner_->Run();
252 
253     // message_loop_runner_->Quit is only called from StartDragAndDrop.
254     DCHECK(drag_started_);
255 
256     if (text)
257       *text = text_;
258     if (html)
259       *html = html_;
260     if (operation)
261       *operation = operation_;
262     if (location_inside_web_contents)
263       *location_inside_web_contents = location_inside_web_contents_;
264   }
265 
SuppressPassingStartDragFurther()266   void SuppressPassingStartDragFurther() {
267     suppress_passing_of_start_drag_further_ = true;
268   }
269 
PostTaskWhenDragStarts(const base::Closure & callback)270   void PostTaskWhenDragStarts(const base::Closure& callback) {
271     callback_to_run_inside_drag_and_drop_message_loop_ = callback;
272   }
273 
274   // aura::client::DragDropClient overrides:
StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,aura::Window * root_window,aura::Window * source_window,const gfx::Point & screen_location,int operation,ui::mojom::DragEventSource source)275   int StartDragAndDrop(std::unique_ptr<ui::OSExchangeData> data,
276                        aura::Window* root_window,
277                        aura::Window* source_window,
278                        const gfx::Point& screen_location,
279                        int operation,
280                        ui::mojom::DragEventSource source) override {
281     DCHECK(!drag_started_);
282     if (!drag_started_) {
283       drag_started_ = true;
284       message_loop_runner_->Quit();
285 
286       base::string16 text;
287       if (data->GetString(&text))
288         text_ = base::UTF16ToUTF8(text);
289       else
290         text_ = "<no text>";
291 
292       GURL base_url;
293       base::string16 html;
294       if (data->GetHtml(&html, &base_url))
295         html_ = base::UTF16ToUTF8(html);
296       else
297         html_ = "<no html>";
298 
299       gfx::Rect bounds =
300           web_contents_->GetContentNativeView()->GetBoundsInScreen();
301       location_inside_web_contents_ =
302           screen_location - gfx::Vector2d(bounds.x(), bounds.y());
303 
304       operation_ = operation;
305     }
306 
307     if (!callback_to_run_inside_drag_and_drop_message_loop_.is_null()) {
308       base::SequencedTaskRunnerHandle::Get()->PostTask(
309           FROM_HERE,
310           std::move(callback_to_run_inside_drag_and_drop_message_loop_));
311       callback_to_run_inside_drag_and_drop_message_loop_.Reset();
312     }
313 
314     if (suppress_passing_of_start_drag_further_)
315       return 0;
316 
317     // Start a nested drag-and-drop loop (might not return for a long time).
318     return old_client_->StartDragAndDrop(std::move(data), root_window,
319                                          source_window, screen_location,
320                                          operation, source);
321   }
322 
DragCancel()323   void DragCancel() override {
324     ADD_FAILURE() << "Unexpected call to DragCancel";
325   }
326 
IsDragDropInProgress()327   bool IsDragDropInProgress() override { return drag_started_; }
328 
AddObserver(aura::client::DragDropClientObserver * observer)329   void AddObserver(aura::client::DragDropClientObserver* observer) override {}
RemoveObserver(aura::client::DragDropClientObserver * observer)330   void RemoveObserver(aura::client::DragDropClientObserver* observer) override {
331   }
332 
333  private:
334   content::WebContents* web_contents_;
335   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
336   aura::client::DragDropClient* old_client_;
337   base::Closure callback_to_run_inside_drag_and_drop_message_loop_;
338   bool suppress_passing_of_start_drag_further_;
339 
340   // Data captured during the first intercepted StartDragAndDrop call.
341   bool drag_started_;
342   std::string text_;
343   std::string html_;
344   int operation_;
345   gfx::Point location_inside_web_contents_;
346 
347   DISALLOW_COPY_AND_ASSIGN(DragStartWaiter);
348 };
349 
350 // Helper for waiting for notifications from
351 // content/test/data/drag_and_drop/event_monitoring.js
352 class DOMDragEventWaiter {
353  public:
DOMDragEventWaiter(const std::string & event_type_to_wait_for,const content::ToRenderFrameHost & target)354   DOMDragEventWaiter(const std::string& event_type_to_wait_for,
355                      const content::ToRenderFrameHost& target)
356       : target_frame_name_(target.render_frame_host()->GetFrameName()),
357         event_type_to_wait_for_(event_type_to_wait_for),
358         dom_message_queue_(content::WebContents::FromRenderFrameHost(
359             target.render_frame_host())) {}
360 
361   // Waits until |target| calls reportDragEvent in
362   // chrome/test/data/drag_and_drop/event_monitoring.js with event_type
363   // property set to |event_type_to_wait_for|.  (|target| and
364   // |event_type_to_wait_for| are passed to the constructor).
365   //
366   // Returns the event details via |found_event| (in form of a JSON-encoded
367   // object).  See chrome/test/data/drag_and_drop/event_monitoring.js for keys
368   // and properties that |found_event| is expected to have.
369   //
370   // Returns true upon success.  It is okay if |response| is null.
WaitForNextMatchingEvent(std::string * found_event)371   bool WaitForNextMatchingEvent(std::string* found_event) WARN_UNUSED_RESULT {
372     std::string candidate_event;
373     bool got_right_event_type = false;
374     bool got_right_window_name = false;
375     do {
376       if (!dom_message_queue_.WaitForMessage(&candidate_event))
377         return false;
378 
379       got_right_event_type =
380           IsExpectedEventType(candidate_event, event_type_to_wait_for_);
381       got_right_window_name =
382           IsExpectedWindowName(candidate_event, target_frame_name_);
383     } while (!got_right_event_type || !got_right_window_name);
384 
385     if (found_event)
386       *found_event = candidate_event;
387 
388     return true;
389   }
390 
IsExpectedEventType(const std::string & actual_event_body,const std::string & expected_event_type)391   static bool IsExpectedEventType(const std::string& actual_event_body,
392                                   const std::string& expected_event_type) {
393     return IsExpectedPropertyValue(actual_event_body, "event_type",
394                                    expected_event_type);
395   }
396 
IsExpectedWindowName(const std::string & actual_event_body,const std::string & expected_window_name)397   static bool IsExpectedWindowName(const std::string& actual_event_body,
398                                    const std::string& expected_window_name) {
399     return IsExpectedPropertyValue(actual_event_body, "window_name",
400                                    expected_window_name);
401   }
402 
403  private:
IsExpectedPropertyValue(const std::string & actual_event_body,const std::string & property_name,const std::string & expected_property_value)404   static bool IsExpectedPropertyValue(
405       const std::string& actual_event_body,
406       const std::string& property_name,
407       const std::string& expected_property_value) {
408     return base::MatchPattern(
409         actual_event_body,
410         base::StringPrintf("*\"%s\":\"%s\"*", property_name.c_str(),
411                            expected_property_value.c_str()));
412   }
413 
414   std::string target_frame_name_;
415   std::string event_type_to_wait_for_;
416   content::DOMMessageQueue dom_message_queue_;
417 
418   DISALLOW_COPY_AND_ASSIGN(DOMDragEventWaiter);
419 };
420 
421 // Helper for verifying contents of DOM events associated with drag-and-drop.
422 class DOMDragEventVerifier {
423  public:
DOMDragEventVerifier()424   DOMDragEventVerifier() {}
425 
set_expected_client_position(const std::string & value)426   void set_expected_client_position(const std::string& value) {
427     expected_client_position_ = value;
428   }
429 
set_expected_drop_effect(const std::string & value)430   void set_expected_drop_effect(const std::string& value) {
431     expected_drop_effect_ = value;
432   }
433 
set_expected_effect_allowed(const std::string & value)434   void set_expected_effect_allowed(const std::string& value) {
435     expected_effect_allowed_ = value;
436   }
437 
set_expected_mime_types(const std::string & value)438   void set_expected_mime_types(const std::string& value) {
439     expected_mime_types_ = value;
440   }
441 
set_expected_page_position(const std::string & value)442   void set_expected_page_position(const std::string& value) {
443     expected_page_position_ = value;
444   }
445 
set_expected_screen_position(const std::string & value)446   void set_expected_screen_position(const std::string& value) {
447     expected_screen_position_ = value;
448   }
449 
450   // Returns a matcher that will match a std::string (drag event data - e.g.
451   // one returned by DOMDragEventWaiter::WaitForNextMatchingEvent) if it matches
452   // the expectations of this DOMDragEventVerifier.
Matches() const453   testing::Matcher<std::string> Matches() const {
454     return testing::AllOf(
455         FieldMatches("client_position", expected_client_position_),
456         FieldMatches("drop_effect", expected_drop_effect_),
457         FieldMatches("effect_allowed", expected_effect_allowed_),
458         FieldMatches("mime_types", expected_mime_types_),
459         FieldMatches("page_position", expected_page_position_),
460         FieldMatches("screen_position", expected_screen_position_));
461   }
462 
463  private:
FieldMatches(const std::string & field_name,const std::string & expected_value)464   static testing::Matcher<std::string> FieldMatches(
465       const std::string& field_name,
466       const std::string& expected_value) {
467     if (expected_value == "<no expectation>")
468       return testing::A<std::string>();
469 
470     return testing::HasSubstr(base::StringPrintf(
471         "\"%s\":\"%s\"", field_name.c_str(), expected_value.c_str()));
472   }
473 
474   std::string expected_drop_effect_ = "<no expectation>";
475   std::string expected_effect_allowed_ = "<no expectation>";
476   std::string expected_mime_types_ = "<no expectation>";
477   std::string expected_client_position_ = "<no expectation>";
478   std::string expected_page_position_ = "<no expectation>";
479   std::string expected_screen_position_ = "<no expectation>";
480 
481   DISALLOW_COPY_AND_ASSIGN(DOMDragEventVerifier);
482 };
483 
484 // Helper for monitoring event notifications from
485 // content/test/data/drag_and_drop/event_monitoring.js
486 // and counting how many events of a given type were received.
487 class DOMDragEventCounter {
488  public:
DOMDragEventCounter(const content::ToRenderFrameHost & target)489   explicit DOMDragEventCounter(const content::ToRenderFrameHost& target)
490       : target_frame_name_(target.render_frame_host()->GetFrameName()),
491         dom_message_queue_(content::WebContents::FromRenderFrameHost(
492             target.render_frame_host())) {}
493 
494   // Resets all the accumulated event counts to zeros.
Reset()495   void Reset() {
496     StoreAccumulatedEvents();
497     received_events_.clear();
498   }
499 
500   // Returns the number of events of the specified |event_type| received since
501   // construction, or since the last time Reset was called.  |event_type| should
502   // be one of possible |type| property values for a DOM drag-and-drop event -
503   // e.g.  "dragenter" or "dragover".
GetNumberOfReceivedEvents(const std::string & event_type)504   int GetNumberOfReceivedEvents(const std::string& event_type) {
505     std::vector<std::string> v({event_type});
506     return GetNumberOfReceivedEvents(v.begin(), v.end());
507   }
508 
509   // Returns the number of events of the specified |event_types| received since
510   // construction, or since the last time Reset was called.  Elements of
511   // |event_types| should be one of possible |type| property values for a DOM
512   // drag-and-drop event - e.g.  "dragenter" or "dragover".
GetNumberOfReceivedEvents(std::initializer_list<const char * > event_types)513   int GetNumberOfReceivedEvents(
514       std::initializer_list<const char*> event_types) {
515     return GetNumberOfReceivedEvents(event_types.begin(), event_types.end());
516   }
517 
518  private:
519   template <typename T>
GetNumberOfReceivedEvents(T event_types_begin,T event_types_end)520   int GetNumberOfReceivedEvents(T event_types_begin, T event_types_end) {
521     StoreAccumulatedEvents();
522 
523     auto received_event_has_matching_event_type =
524         [&event_types_begin,
525          &event_types_end](const std::string& received_event) {
526           return std::any_of(event_types_begin, event_types_end,
527                              [&received_event](const std::string& event_type) {
528                                return DOMDragEventWaiter::IsExpectedEventType(
529                                    received_event, event_type);
530                              });
531         };
532 
533     return std::count_if(received_events_.begin(), received_events_.end(),
534                          received_event_has_matching_event_type);
535   }
536 
StoreAccumulatedEvents()537   void StoreAccumulatedEvents() {
538     std::string candidate_event;
539     while (dom_message_queue_.PopMessage(&candidate_event)) {
540       if (DOMDragEventWaiter::IsExpectedWindowName(candidate_event,
541                                                    target_frame_name_)) {
542         received_events_.push_back(candidate_event);
543       }
544     }
545   }
546 
547   std::string target_frame_name_;
548   content::DOMMessageQueue dom_message_queue_;
549   std::vector<std::string> received_events_;
550 
551   DISALLOW_COPY_AND_ASSIGN(DOMDragEventCounter);
552 };
553 
554 const char kTestPagePath[] = "/drag_and_drop/page.html";
555 
556 }  // namespace
557 
558 class DragAndDropBrowserTest : public InProcessBrowserTest,
559                                public testing::WithParamInterface<bool> {
560  public:
DragAndDropBrowserTest()561   DragAndDropBrowserTest() {}
562 
563   struct DragImageBetweenFrames_TestState;
564   void DragImageBetweenFrames_Step2(DragImageBetweenFrames_TestState*);
565   void DragImageBetweenFrames_Step3(DragImageBetweenFrames_TestState*);
566 
567   struct DragImageFromDisappearingFrame_TestState;
568   void DragImageFromDisappearingFrame_Step2(
569       DragImageFromDisappearingFrame_TestState*);
570   void DragImageFromDisappearingFrame_Step3(
571       DragImageFromDisappearingFrame_TestState*);
572 
573   struct CrossSiteDrag_TestState;
574   void CrossSiteDrag_Step2(CrossSiteDrag_TestState*);
575   void CrossSiteDrag_Step3(CrossSiteDrag_TestState*);
576 
577  protected:
SetUpOnMainThread()578   void SetUpOnMainThread() override {
579     host_resolver()->AddRule("*", "127.0.0.1");
580     content::SetupCrossSiteRedirector(embedded_test_server());
581     ASSERT_TRUE(embedded_test_server()->Start());
582     drag_simulator_.reset(new DragAndDropSimulator(web_contents()));
583   }
584 
TearDownOnMainThread()585   void TearDownOnMainThread() override {
586     // For X11 need to tear down before UI goes away.
587     drag_simulator_.reset();
588   }
589 
use_cross_site_subframe()590   bool use_cross_site_subframe() {
591     // This is controlled by gtest's test param from INSTANTIATE_TEST_SUITE_P.
592     return GetParam();
593   }
594 
left_frame()595   content::RenderFrameHost* left_frame() {
596     AssertTestPageIsLoaded();
597     return GetFrameByName("left");
598   }
599 
right_frame()600   content::RenderFrameHost* right_frame() {
601     AssertTestPageIsLoaded();
602     return GetFrameByName("right");
603   }
604 
web_contents()605   content::WebContents* web_contents() {
606     return browser()->tab_strip_model()->GetActiveWebContents();
607   }
608 
609   //////////////////////
610   // Navigation helpers.
611 
NavigateToTestPage(const std::string & origin_of_main_frame)612   bool NavigateToTestPage(const std::string& origin_of_main_frame) {
613     GURL url =
614         embedded_test_server()->GetURL(origin_of_main_frame, kTestPagePath);
615     ui_test_utils::NavigateToURL(browser(), url);
616     return web_contents()->GetLastCommittedURL() == url;
617   }
618 
619   // Navigates the left frame to |filename| (found under
620   // chrome/test/data/drag_and_drop directory).
NavigateLeftFrame(const std::string & origin,const std::string & filename)621   bool NavigateLeftFrame(const std::string& origin,
622                          const std::string& filename) {
623     AssertTestPageIsLoaded();
624     return NavigateNamedFrame("left", origin, filename);
625   }
626 
627   // Navigates the right frame to |filename| (found under
628   // chrome/test/data/drag_and_drop directory).
NavigateRightFrame(const std::string & origin,const std::string & filename)629   bool NavigateRightFrame(const std::string& origin,
630                           const std::string& filename) {
631     AssertTestPageIsLoaded();
632     return NavigateNamedFrame("right", origin, filename);
633   }
634 
635   ////////////////////////////////////////////////////////////
636   // Simulation of starting a drag-and-drop (using the mouse).
637 
SimulateMouseDownAndDragStartInLeftFrame()638   bool SimulateMouseDownAndDragStartInLeftFrame() {
639     AssertTestPageIsLoaded();
640 
641     // Waiting until the mousemove and mousedown events reach the right renderer
642     // is needed to avoid flakiness reported in https://crbug.com/671445 (which
643     // has its root cause in https://crbug.com/647378).  Once the latter bug
644     // is fixed, we should no longer need to wait for these events (because
645     // fixing https://crbug.com/647378 should guarantee that events arrive
646     // to the renderer in the right order).
647     DOMDragEventWaiter mouse_move_event_waiter("mousemove", left_frame());
648     DOMDragEventWaiter mouse_down_event_waiter("mousedown", left_frame());
649 
650     if (!SimulateMouseMove(kMiddleOfLeftFrame))
651       return false;
652     if (!mouse_move_event_waiter.WaitForNextMatchingEvent(nullptr))
653       return false;
654 
655     if (!SimulateMouseDown())
656       return false;
657     if (!mouse_down_event_waiter.WaitForNextMatchingEvent(nullptr))
658       return false;
659 
660     if (!SimulateMouseMove(expected_location_of_drag_start_in_left_frame()))
661       return false;
662 
663     return true;
664   }
665 
expected_location_of_drag_start_in_left_frame()666   gfx::Point expected_location_of_drag_start_in_left_frame() {
667     // TODO(crbug.com/653490): The delta below should exceed kDragThresholdX and
668     // kDragThresholdY from MouseEventManager.cpp in blink.  Ideally, it would
669     // come from the OS instead.
670     return kMiddleOfLeftFrame + gfx::Vector2d(10, 10);
671   }
672 
SimulateMouseMoveToLeftFrame()673   bool SimulateMouseMoveToLeftFrame() {
674     AssertTestPageIsLoaded();
675     return SimulateMouseMove(kMiddleOfLeftFrame);
676   }
677 
SimulateMouseMoveToRightFrame()678   bool SimulateMouseMoveToRightFrame() {
679     AssertTestPageIsLoaded();
680     return SimulateMouseMove(kMiddleOfRightFrame);
681   }
682 
SimulateMouseUp()683   bool SimulateMouseUp() {
684     return ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
685                                               ui_controls::UP);
686   }
687 
688   ////////////////////////////////////////////////////////////////////
689   // Simulation of dragging from outside the browser into web contents
690   // (using DragAndDropSimulator, not simulating mouse events).
691 
SimulateDragEnterToRightFrame(const std::string & text)692   bool SimulateDragEnterToRightFrame(const std::string& text) {
693     AssertTestPageIsLoaded();
694     return drag_simulator_->SimulateDragEnter(kMiddleOfRightFrame, text);
695   }
696 
SimulateDragEnterToRightFrame(const GURL & url)697   bool SimulateDragEnterToRightFrame(const GURL& url) {
698     AssertTestPageIsLoaded();
699     return drag_simulator_->SimulateDragEnter(kMiddleOfRightFrame, url);
700   }
701 
SimulateDragEnterToRightFrame(const base::FilePath & file)702   bool SimulateDragEnterToRightFrame(const base::FilePath& file) {
703     AssertTestPageIsLoaded();
704     return drag_simulator_->SimulateDragEnter(kMiddleOfRightFrame, file);
705   }
706 
SimulateDropInRightFrame()707   bool SimulateDropInRightFrame() {
708     AssertTestPageIsLoaded();
709     return drag_simulator_->SimulateDrop(kMiddleOfRightFrame);
710   }
711 
GetMiddleOfRightFrameInScreenCoords()712   gfx::Point GetMiddleOfRightFrameInScreenCoords() {
713     aura::Window* window = web_contents()->GetNativeView();
714     aura::client::ScreenPositionClient* screen_position_client =
715         aura::client::GetScreenPositionClient(window->GetRootWindow());
716     gfx::Point screen_position(kMiddleOfRightFrame);
717     if (screen_position_client)
718       screen_position_client->ConvertPointToScreen(window, &screen_position);
719     return screen_position;
720   }
721 
722  private:
723   // Constants with coordinates within content/test/data/drag_and_drop/page.html
724   // The precise frame center is at 200,200 and 400,200 coordinates, but slight
725   // differences between left and right frame hopefully make it easier to detect
726   // incorrect dom_drag_and_drop_event.clientX/Y values in test asserts.
727   const gfx::Point kMiddleOfLeftFrame = gfx::Point(155, 150);
728   const gfx::Point kMiddleOfRightFrame = gfx::Point(455, 250);
729 
SimulateMouseDown()730   bool SimulateMouseDown() {
731     return ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
732                                               ui_controls::DOWN);
733   }
734 
SimulateMouseMove(const gfx::Point & location_inside_web_contents)735   bool SimulateMouseMove(const gfx::Point& location_inside_web_contents) {
736     gfx::Rect bounds = web_contents()->GetContainerBounds();
737     return ui_test_utils::SendMouseMoveSync(
738         gfx::Point(bounds.x() + location_inside_web_contents.x(),
739                    bounds.y() + location_inside_web_contents.y()));
740   }
741 
NavigateNamedFrame(const std::string & frame_name,const std::string & origin,const std::string & filename)742   bool NavigateNamedFrame(const std::string& frame_name,
743                           const std::string& origin,
744                           const std::string& filename) {
745     content::RenderFrameHost* frame = GetFrameByName(frame_name);
746     if (!frame)
747       return false;
748 
749     std::string script;
750     int response = 0;
751 
752     // Navigate the frame and wait for the load event.
753     script = base::StringPrintf(
754         "location.href = '/cross-site/%s/drag_and_drop/%s';\n"
755         "setTimeout(function() { domAutomationController.send(42); }, 0);",
756         origin.c_str(), filename.c_str());
757     content::TestFrameNavigationObserver observer(frame);
758     if (!content::ExecuteScriptAndExtractInt(frame, script, &response))
759       return false;
760     if (response != 42)
761       return false;
762     observer.Wait();
763 
764     // |frame| might have been swapped-out during a cross-site navigation,
765     // therefore we need to get the current RenderFrameHost to work against
766     // going forward.
767     frame = GetFrameByName(frame_name);
768     DCHECK(frame);
769 
770     // Wait until hit testing data is ready.
771     WaitForHitTestData(frame);
772 
773     return true;
774   }
775 
GetFrameByName(const std::string & name_to_find)776   content::RenderFrameHost* GetFrameByName(const std::string& name_to_find) {
777     return content::FrameMatchingPredicate(
778         web_contents(),
779         base::BindRepeating(&content::FrameMatchesName, name_to_find));
780   }
781 
AssertTestPageIsLoaded()782   void AssertTestPageIsLoaded() {
783     ASSERT_EQ(kTestPagePath, web_contents()->GetLastCommittedURL().path());
784   }
785 
786   std::unique_ptr<DragAndDropSimulator> drag_simulator_;
787 
788   DISALLOW_COPY_AND_ASSIGN(DragAndDropBrowserTest);
789 };
790 
791 // Scenario: drag text from outside the browser and drop to the right frame.
792 // Test coverage: dragover, drop DOM events.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,DropTextFromOutside)793 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DropTextFromOutside) {
794   std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
795   ASSERT_TRUE(NavigateToTestPage("a.com"));
796   ASSERT_TRUE(NavigateRightFrame(frame_site, "drop_target.html"));
797 
798   // Setup test expectations.
799   DOMDragEventVerifier expected_dom_event_data;
800   expected_dom_event_data.set_expected_client_position("(155, 150)");
801   expected_dom_event_data.set_expected_drop_effect("none");
802   expected_dom_event_data.set_expected_effect_allowed("all");
803   expected_dom_event_data.set_expected_mime_types("text/plain");
804   expected_dom_event_data.set_expected_page_position("(155, 150)");
805 
806   // Drag text from outside the browser into/over the right frame.
807   {
808     DOMDragEventWaiter dragover_waiter("dragover", right_frame());
809     ASSERT_TRUE(SimulateDragEnterToRightFrame("Dragged test text"));
810 
811     std::string dragover_event;
812     ASSERT_TRUE(dragover_waiter.WaitForNextMatchingEvent(&dragover_event));
813     EXPECT_THAT(dragover_event, expected_dom_event_data.Matches());
814   }
815 
816   // Drop into the right frame.
817   {
818     DOMDragEventWaiter drop_waiter("drop", right_frame());
819     ASSERT_TRUE(SimulateDropInRightFrame());
820 
821     std::string drop_event;
822     ASSERT_TRUE(drop_waiter.WaitForNextMatchingEvent(&drop_event));
823     EXPECT_THAT(drop_event, expected_dom_event_data.Matches());
824   }
825 }
826 
827 // Scenario: drag URL from outside the browser and drop to the right frame
828 // (e.g. this is similar to a drag that starts from the bookmarks bar, except
829 // that here there is no drag start event - as-if the drag was started in
830 // another application).
831 //
832 // This test mostly focuses on covering 1) the navigation path, 2) focus
833 // behavior.  This test explicitly does not cover the dragover and/or drop DOM
834 // events - they are already covered via the DropTextFromOutside test above.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,DropValidUrlFromOutside)835 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DropValidUrlFromOutside) {
836   std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
837   ASSERT_TRUE(NavigateToTestPage("a.com"));
838   ASSERT_TRUE(NavigateRightFrame(frame_site, "title1.html"));
839   content::WebContents* web_contents =
840       browser()->tab_strip_model()->GetActiveWebContents();
841   content::NavigationController& controller = web_contents->GetController();
842   int initial_history_count = controller.GetEntryCount();
843   GURL initial_url = web_contents->GetMainFrame()->GetLastCommittedURL();
844   ASSERT_EQ(1, browser()->tab_strip_model()->count());
845 
846   // Focus the omnibox.
847   chrome::FocusLocationBar(browser());
848   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
849   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
850 
851   // Drag a normal URL from outside the browser into/over the right frame.
852   GURL dragged_url = embedded_test_server()->GetURL("d.com", "/title2.html");
853   ASSERT_TRUE(SimulateDragEnterToRightFrame(dragged_url));
854 
855   ui_test_utils::TabAddedWaiter wait_for_new_tab(browser());
856 
857   // Drop into the right frame.
858   ASSERT_TRUE(SimulateDropInRightFrame());
859 
860   // Verify that dropping |dragged_url| creates a new tab and navigates it to
861   // that URL.
862   wait_for_new_tab.Wait();
863   EXPECT_EQ(2, browser()->tab_strip_model()->count());
864   content::WebContents* new_web_contents =
865       browser()->tab_strip_model()->GetActiveWebContents();
866   content::TestNavigationObserver(new_web_contents, 1).Wait();
867   EXPECT_EQ(dragged_url,
868             new_web_contents->GetMainFrame()->GetLastCommittedURL());
869 
870   // Verify that the initial tab didn't navigate.
871   EXPECT_EQ(initial_url, web_contents->GetMainFrame()->GetLastCommittedURL());
872   EXPECT_EQ(initial_history_count, controller.GetEntryCount());
873 
874   // Verify that the focus moved from the omnibox to the tab contents.
875   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
876   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
877 }
878 
879 // Scenario: drag a file from outside the browser and drop to the right frame
880 // (e.g. starting a drag in a separate file explorer application, like Nemo on
881 // gLinux).
882 //
883 // This test mostly focuses on covering 1) the navigation path, 2) focus
884 // behavior.  This test explicitly does not cover the dragover and/or drop DOM
885 // events - they are already covered via the DropTextFromOutside test above.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,DropFileFromOutside)886 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DropFileFromOutside) {
887   std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
888   ASSERT_TRUE(NavigateToTestPage("a.com"));
889   ASSERT_TRUE(NavigateRightFrame(frame_site, "title1.html"));
890   content::WebContents* web_contents =
891       browser()->tab_strip_model()->GetActiveWebContents();
892   content::NavigationController& controller = web_contents->GetController();
893   int initial_history_count = controller.GetEntryCount();
894   GURL initial_url = web_contents->GetMainFrame()->GetLastCommittedURL();
895   ASSERT_EQ(1, browser()->tab_strip_model()->count());
896 
897   // Focus the omnibox.
898   chrome::FocusLocationBar(browser());
899   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
900   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
901 
902   // Drag a file from outside the browser into/over the right frame.
903   base::FilePath dragged_file = ui_test_utils::GetTestFilePath(
904       base::FilePath(), base::FilePath().AppendASCII("title3.html"));
905   ASSERT_TRUE(SimulateDragEnterToRightFrame(dragged_file));
906 
907   ui_test_utils::TabAddedWaiter wait_for_new_tab(browser());
908 
909   // Drop into the right frame.
910   ASSERT_TRUE(SimulateDropInRightFrame());
911 
912   // Verify that dropping |dragged_file| creates a new tab and navigates it to
913   // the corresponding file: URL.
914   wait_for_new_tab.Wait();
915   EXPECT_EQ(2, browser()->tab_strip_model()->count());
916   content::WebContents* new_web_contents =
917       browser()->tab_strip_model()->GetActiveWebContents();
918   content::TestNavigationObserver(new_web_contents, 1).Wait();
919   EXPECT_EQ(net::FilePathToFileURL(dragged_file),
920             new_web_contents->GetMainFrame()->GetLastCommittedURL());
921 
922   // Verify that the initial tab didn't navigate.
923   EXPECT_EQ(initial_url, web_contents->GetMainFrame()->GetLastCommittedURL());
924   EXPECT_EQ(initial_history_count, controller.GetEntryCount());
925 
926   // Verify that the focus moved from the omnibox to the tab contents.
927   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
928   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_TAB_CONTAINER));
929 }
930 
931 #if defined(THREAD_SANITIZER)
932 // TSAN Race condition: crbug.com/1005095
933 #define MAYBE_DropForbiddenUrlFromOutside DISABLED_DropForbiddenUrlFromOutside
934 #else
935 #define MAYBE_DropForbiddenUrlFromOutside DropForbiddenUrlFromOutside
936 #endif
937 // Scenario: drag URL from outside the browser and drop to the right frame.
938 // Mostly focuses on covering the navigation path (the dragover and/or drop DOM
939 // events are already covered via the DropTextFromOutside test above).
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,MAYBE_DropForbiddenUrlFromOutside)940 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,
941                        MAYBE_DropForbiddenUrlFromOutside) {
942   std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
943   ASSERT_TRUE(NavigateToTestPage("a.com"));
944   ASSERT_TRUE(NavigateRightFrame(frame_site, "title1.html"));
945   content::WebContents* web_contents =
946       browser()->tab_strip_model()->GetActiveWebContents();
947   content::NavigationController& controller = web_contents->GetController();
948   int initial_history_count = controller.GetEntryCount();
949 
950   // Drag URL from outside the browser into/over the right frame.  The test uses
951   // a URL that:
952   // 1. Passes RenderWidgetHostImpl::FilterDropData checks.
953   // 2. Fails CanDisplay checks in Blink (e.g. in RemoteFrame::Navigate).
954   //    - This condition trigger the crash from https://crbug.com/1003169
955   // 3. Passes BeginNavigation checks
956   //    - This rules out "chrome-error://blah".
957   GURL dragged_url("blob:null/some-guid");
958   ASSERT_TRUE(SimulateDragEnterToRightFrame(dragged_url));
959 
960   // Drop into the right frame - this should *not* initiate navigating the main
961   // frame to |dragged_url| (because this would be a forbidden, web->file
962   // navigation).
963   ASSERT_TRUE(SimulateDropInRightFrame());
964 
965   // Verify that the right frame is still responsive (this is a regression test
966   // for https://crbug.com/1003169.
967   ASSERT_TRUE(right_frame()->GetProcess()->IsInitializedAndNotDead());
968   EXPECT_EQ(123, content::EvalJs(right_frame(), "123"));
969 
970   // Verify that the history remains unchanged.
971   EXPECT_NE(dragged_url, web_contents->GetMainFrame()->GetLastCommittedURL());
972   EXPECT_EQ(initial_history_count, controller.GetEntryCount());
973 }
974 
975 // Scenario: starting a drag in left frame
976 // Test coverage: dragstart DOM event, dragstart data passed to the OS.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,DragStartInFrame)977 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DragStartInFrame) {
978   std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
979   ASSERT_TRUE(NavigateToTestPage("a.com"));
980   ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html"));
981 
982   // Setup test expectations.
983   DOMDragEventVerifier expected_dom_event_data;
984   expected_dom_event_data.set_expected_client_position("(55, 50)");
985   expected_dom_event_data.set_expected_drop_effect("none");
986   // (dragstart event handler in image_source.html is asking for "copy" only).
987   expected_dom_event_data.set_expected_effect_allowed("copy");
988   expected_dom_event_data.set_expected_page_position("(55, 50)");
989 
990   // TODO(lukasza): Figure out why the dragstart event
991   // - lists "Files" on the mime types list,
992   // - doesn't list "text/plain" on the mime types list.
993   // (i.e. why expectations below differ from expectations for dragenter,
994   // dragover, dragend and/or drop events in DragImageBetweenFrames test).
995   expected_dom_event_data.set_expected_mime_types(
996       "Files,text/html,text/uri-list");
997 
998   // Start the drag in the left frame.
999   DragStartWaiter drag_start_waiter(web_contents());
1000   drag_start_waiter.SuppressPassingStartDragFurther();
1001   DOMDragEventWaiter dragstart_event_waiter("dragstart", left_frame());
1002   EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame());
1003 
1004   // Verify Javascript event data.
1005   {
1006     std::string dragstart_event;
1007     EXPECT_TRUE(
1008         dragstart_event_waiter.WaitForNextMatchingEvent(&dragstart_event));
1009     EXPECT_THAT(dragstart_event, expected_dom_event_data.Matches());
1010   }
1011 
1012   // Verify data being passed to the OS.
1013   {
1014     std::string text;
1015     std::string html;
1016     int operation = 0;
1017     gfx::Point location_inside_web_contents;
1018     drag_start_waiter.WaitUntilDragStart(&text, &html, &operation,
1019                                          &location_inside_web_contents);
1020     EXPECT_EQ(embedded_test_server()->GetURL(frame_site,
1021                                              "/image_decoding/droids.jpg"),
1022               text);
1023     EXPECT_THAT(html,
1024                 testing::MatchesRegex("<img .*src=\""
1025                                       "http://.*/image_decoding/droids.jpg"
1026                                       "\">"));
1027     EXPECT_EQ(expected_location_of_drag_start_in_left_frame(),
1028               location_inside_web_contents);
1029     EXPECT_EQ(ui::DragDropTypes::DRAG_COPY, operation);
1030   }
1031 
1032   // Try to leave everything in a clean state.
1033   SimulateMouseUp();
1034 }
1035 
1036 #if defined(OS_WIN)
1037 // There is no known way to execute test-controlled tasks during
1038 // a drag-and-drop loop run by Windows OS.
1039 #define MAYBE_DragImageBetweenFrames DISABLED_DragImageBetweenFrames
1040 #elif defined(OS_LINUX) || defined(OS_CHROMEOS)
1041 #define MAYBE_DragImageBetweenFrames DISABLED_DragImageBetweenFrames
1042 #else
1043 #define MAYBE_DragImageBetweenFrames DragImageBetweenFrames
1044 #endif
1045 
1046 // Data that needs to be shared across multiple test steps below
1047 // (i.e. across DragImageBetweenFrames_Step2 and DragImageBetweenFrames_Step3).
1048 struct DragAndDropBrowserTest::DragImageBetweenFrames_TestState {
1049   DOMDragEventVerifier expected_dom_event_data;
1050   std::unique_ptr<DOMDragEventWaiter> dragstart_event_waiter;
1051   std::unique_ptr<DOMDragEventWaiter> drop_event_waiter;
1052   std::unique_ptr<DOMDragEventWaiter> dragend_event_waiter;
1053   std::unique_ptr<DOMDragEventCounter> left_frame_events_counter;
1054   std::unique_ptr<DOMDragEventCounter> right_frame_events_counter;
1055 };
1056 
1057 // Scenario: drag an image from the left into the right frame.
1058 // Test coverage: dragleave, dragenter, dragover, dragend, drop DOM events.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,MAYBE_DragImageBetweenFrames)1059 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, MAYBE_DragImageBetweenFrames) {
1060   // Note that drag and drop will not expose data across cross-site frames on
1061   // the same page - this is why the same |frame_site| is used below both for
1062   // the left and the right frame.  See also https://crbug.com/59081.
1063   std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
1064   ASSERT_TRUE(NavigateToTestPage("a.com"));
1065   ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html"));
1066   ASSERT_TRUE(NavigateRightFrame(frame_site, "drop_target.html"));
1067 
1068   // Setup test expectations.
1069   DragAndDropBrowserTest::DragImageBetweenFrames_TestState state;
1070   state.left_frame_events_counter.reset(new DOMDragEventCounter(left_frame()));
1071   state.right_frame_events_counter.reset(
1072       new DOMDragEventCounter(right_frame()));
1073   state.expected_dom_event_data.set_expected_client_position("(55, 50)");
1074   state.expected_dom_event_data.set_expected_drop_effect("none");
1075   // (dragstart event handler in image_source.html is asking for "copy" only).
1076   state.expected_dom_event_data.set_expected_effect_allowed("copy");
1077   state.expected_dom_event_data.set_expected_mime_types(
1078       "text/html,text/plain,text/uri-list");
1079   state.expected_dom_event_data.set_expected_page_position("(55, 50)");
1080 
1081   // Start the drag in the left frame.
1082   DragStartWaiter drag_start_waiter(web_contents());
1083   drag_start_waiter.PostTaskWhenDragStarts(
1084       base::Bind(&DragAndDropBrowserTest::DragImageBetweenFrames_Step2,
1085                  base::Unretained(this), base::Unretained(&state)));
1086   state.dragstart_event_waiter.reset(
1087       new DOMDragEventWaiter("dragstart", left_frame()));
1088   EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame());
1089 
1090   // The next step of the test (DragImageBetweenFrames_Step2) runs inside the
1091   // nested drag-and-drop message loop - the call below won't return until the
1092   // drag-and-drop has already ended.
1093   drag_start_waiter.WaitUntilDragStart(nullptr, nullptr, nullptr, nullptr);
1094 
1095   DragImageBetweenFrames_Step3(&state);
1096 }
1097 
DragImageBetweenFrames_Step2(DragAndDropBrowserTest::DragImageBetweenFrames_TestState * state)1098 void DragAndDropBrowserTest::DragImageBetweenFrames_Step2(
1099     DragAndDropBrowserTest::DragImageBetweenFrames_TestState* state) {
1100   // Verify dragstart DOM event.
1101   {
1102     std::string dragstart_event;
1103     EXPECT_TRUE(state->dragstart_event_waiter->WaitForNextMatchingEvent(
1104         &dragstart_event));
1105     state->dragstart_event_waiter.reset();
1106 
1107     // Only a single "dragstart" should have fired in the left frame since the
1108     // start of the test.  We also allow any number of "dragover" events.
1109     EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1110                      "dragstart"));
1111     EXPECT_EQ(0, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1112                      {"dragleave", "dragenter", "drop", "dragend"}));
1113 
1114     // No events should have fired in the right frame yet.
1115     EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1116                      {"dragstart", "dragleave", "dragenter", "dragover", "drop",
1117                       "dragend"}));
1118   }
1119 
1120   // While dragging, move mouse within the left frame.
1121   // Without this extra mouse move we wouldn't get a dragleave event later on.
1122   ASSERT_TRUE(SimulateMouseMoveToLeftFrame());
1123 
1124   // While dragging, move mouse from the left into the right frame.
1125   // This should trigger dragleave and dragenter events.
1126   {
1127     DOMDragEventWaiter dragleave_event_waiter("dragleave", left_frame());
1128     DOMDragEventWaiter dragenter_event_waiter("dragenter", right_frame());
1129     state->left_frame_events_counter->Reset();
1130     state->right_frame_events_counter->Reset();
1131     ASSERT_TRUE(SimulateMouseMoveToRightFrame());
1132 
1133     {  // Verify dragleave DOM event.
1134       std::string dragleave_event;
1135 
1136       state->expected_dom_event_data.set_expected_client_position("(355, 150)");
1137       state->expected_dom_event_data.set_expected_page_position("(355, 150)");
1138 
1139       EXPECT_TRUE(
1140           dragleave_event_waiter.WaitForNextMatchingEvent(&dragleave_event));
1141       EXPECT_THAT(dragleave_event, state->expected_dom_event_data.Matches());
1142     }
1143 
1144     {  // Verify dragenter DOM event.
1145       std::string dragenter_event;
1146 
1147       // Update expected event coordinates after SimulateMouseMoveToRightFrame
1148       // (these coordinates are relative to the right frame).
1149       state->expected_dom_event_data.set_expected_client_position("(155, 150)");
1150       state->expected_dom_event_data.set_expected_page_position("(155, 150)");
1151 
1152       EXPECT_TRUE(
1153           dragenter_event_waiter.WaitForNextMatchingEvent(&dragenter_event));
1154       EXPECT_THAT(dragenter_event, state->expected_dom_event_data.Matches());
1155     }
1156 
1157     // Note that ash (unlike aura/x11) will not fire dragover event in response
1158     // to the same mouse event that trigerred a dragenter.  Because of that, we
1159     // postpone dragover testing until the next test step below.  See
1160     // implementation of ash::DragDropController::DragUpdate for details.
1161   }
1162 
1163   // Move the mouse twice in the right frame.  The 1st move will ensure that
1164   // allowed operations communicated by the renderer will be stored in
1165   // WebContentsViewAura::current_drag_op_.  The 2nd move will ensure that this
1166   // gets be copied into DesktopDragDropClientAuraX11::negotiated_operation_.
1167   for (int i = 0; i < 2; i++) {
1168     DOMDragEventWaiter dragover_event_waiter("dragover", right_frame());
1169     ASSERT_TRUE(SimulateMouseMoveToRightFrame());
1170 
1171     {  // Verify dragover DOM event.
1172       std::string dragover_event;
1173       EXPECT_TRUE(
1174           dragover_event_waiter.WaitForNextMatchingEvent(&dragover_event));
1175       EXPECT_THAT(dragover_event, state->expected_dom_event_data.Matches());
1176     }
1177   }
1178 
1179   // Only a single "dragleave" should have fired in the left frame since the
1180   // last checkpoint.  We also allow any number of "dragover" events.
1181   EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1182                    "dragleave"));
1183   EXPECT_EQ(0, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1184                    {"dragstart", "dragenter", "drop", "dragend"}));
1185 
1186   // A single "dragenter" + at least one "dragover" event should have fired in
1187   // the right frame since the last checkpoint.
1188   EXPECT_EQ(1, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1189                    "dragenter"));
1190   EXPECT_LE(1, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1191                    "dragover"));
1192   EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1193                    {"dragstart", "dragleave", "drop", "dragend"}));
1194 
1195   // Release the mouse button to end the drag.
1196   state->drop_event_waiter.reset(new DOMDragEventWaiter("drop", right_frame()));
1197   state->dragend_event_waiter.reset(
1198       new DOMDragEventWaiter("dragend", left_frame()));
1199   state->left_frame_events_counter->Reset();
1200   state->right_frame_events_counter->Reset();
1201   SimulateMouseUp();
1202   // The test will continue in DragImageBetweenFrames_Step3.
1203 }
1204 
DragImageBetweenFrames_Step3(DragAndDropBrowserTest::DragImageBetweenFrames_TestState * state)1205 void DragAndDropBrowserTest::DragImageBetweenFrames_Step3(
1206     DragAndDropBrowserTest::DragImageBetweenFrames_TestState* state) {
1207   // Verify drop DOM event.
1208   {
1209     std::string drop_event;
1210     EXPECT_TRUE(
1211         state->drop_event_waiter->WaitForNextMatchingEvent(&drop_event));
1212     state->drop_event_waiter.reset();
1213     EXPECT_THAT(drop_event, state->expected_dom_event_data.Matches());
1214   }
1215 
1216   // Verify dragend DOM event.
1217   {
1218     // TODO(lukasza): Figure out why the drop event sees different values of
1219     // DataTransfer.dropEffect and DataTransfer.types properties.
1220     state->expected_dom_event_data.set_expected_drop_effect("copy");
1221     state->expected_dom_event_data.set_expected_mime_types("");
1222 
1223     // TODO: https://crbug.com/686136: dragEnd coordinates for non-OOPIF
1224     // scenarios are currently broken.
1225     state->expected_dom_event_data.set_expected_client_position(
1226         "<no expectation>");
1227     state->expected_dom_event_data.set_expected_page_position(
1228         "<no expectation>");
1229 
1230     std::string dragend_event;
1231     EXPECT_TRUE(
1232         state->dragend_event_waiter->WaitForNextMatchingEvent(&dragend_event));
1233     state->dragend_event_waiter.reset();
1234     EXPECT_THAT(dragend_event, state->expected_dom_event_data.Matches());
1235   }
1236 
1237   // Only a single "dragend" should have fired in the left frame since the last
1238   // checkpoint.
1239   EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1240                    "dragend"));
1241   EXPECT_EQ(0,
1242             state->left_frame_events_counter->GetNumberOfReceivedEvents(
1243                 {"dragstart", "dragleave", "dragenter", "dragover", "drop"}));
1244 
1245   // A single "drop" + possibly some "dragover" events should have fired in the
1246   // right frame since the last checkpoint.
1247   EXPECT_EQ(
1248       1, state->right_frame_events_counter->GetNumberOfReceivedEvents("drop"));
1249   EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1250                    {"dragstart", "dragleave", "dragenter", "dragend"}));
1251 }
1252 
1253 #if defined(OS_WIN)
1254 // There is no known way to execute test-controlled tasks during
1255 // a drag-and-drop loop run by Windows OS.
1256 #define MAYBE_DragImageFromDisappearingFrame \
1257   DISABLED_DragImageFromDisappearingFrame
1258 #else
1259 #define MAYBE_DragImageFromDisappearingFrame DragImageFromDisappearingFrame
1260 #endif
1261 
1262 // Data that needs to be shared across multiple test steps below
1263 // (i.e. across DragImageFromDisappearingFrame_Step2 and
1264 // DragImageFromDisappearingFrame_Step3).
1265 struct DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState {
1266   DOMDragEventVerifier expected_dom_event_data;
1267   std::unique_ptr<DOMDragEventWaiter> drop_event_waiter;
1268 };
1269 
1270 // Scenario: drag an image from the left into the right frame and delete the
1271 // left frame during the drag.  This is a regression test for
1272 // https://crbug.com/670123.
1273 // Test coverage: dragenter, dragover, drop DOM events.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,MAYBE_DragImageFromDisappearingFrame)1274 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,
1275                        MAYBE_DragImageFromDisappearingFrame) {
1276   // Load the test page.
1277   std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
1278   ASSERT_TRUE(NavigateToTestPage("a.com"));
1279   ASSERT_TRUE(NavigateLeftFrame(frame_site, "image_source.html"));
1280   ASSERT_TRUE(NavigateRightFrame(frame_site, "drop_target.html"));
1281 
1282   // Setup test expectations.
1283   DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState state;
1284   state.expected_dom_event_data.set_expected_drop_effect("none");
1285   // (dragstart event handler in image_source.html is asking for "copy" only).
1286   state.expected_dom_event_data.set_expected_effect_allowed("copy");
1287   state.expected_dom_event_data.set_expected_mime_types(
1288       "text/html,text/plain,text/uri-list");
1289   state.expected_dom_event_data.set_expected_client_position("(155, 150)");
1290   state.expected_dom_event_data.set_expected_page_position("(155, 150)");
1291 
1292   // Start the drag in the left frame.
1293   DragStartWaiter drag_start_waiter(web_contents());
1294   drag_start_waiter.PostTaskWhenDragStarts(
1295       base::Bind(&DragAndDropBrowserTest::DragImageFromDisappearingFrame_Step2,
1296                  base::Unretained(this), base::Unretained(&state)));
1297   EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame());
1298 
1299   // The next step of the test (DragImageFromDisappearingFrame_Step2) runs
1300   // inside the nested drag-and-drop message loop - the call below won't return
1301   // until the drag-and-drop has already ended.
1302   drag_start_waiter.WaitUntilDragStart(nullptr, nullptr, nullptr, nullptr);
1303 
1304   DragImageFromDisappearingFrame_Step3(&state);
1305 }
1306 
DragImageFromDisappearingFrame_Step2(DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState * state)1307 void DragAndDropBrowserTest::DragImageFromDisappearingFrame_Step2(
1308     DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState* state) {
1309   // Delete the left frame in an attempt to repro https://crbug.com/670123.
1310   content::RenderFrameDeletedObserver frame_deleted_observer(left_frame());
1311   ASSERT_TRUE(ExecuteScript(web_contents()->GetMainFrame(),
1312                             "frame = document.getElementById('left');\n"
1313                             "frame.parentNode.removeChild(frame);\n"));
1314   frame_deleted_observer.WaitUntilDeleted();
1315 
1316   // While dragging, move mouse from the left into the right frame.
1317   // This should trigger dragleave and dragenter events.
1318   {
1319     DOMDragEventWaiter dragenter_event_waiter("dragenter", right_frame());
1320     ASSERT_TRUE(SimulateMouseMoveToRightFrame());
1321 
1322     {  // Verify dragenter DOM event.
1323       std::string dragenter_event;
1324       EXPECT_TRUE(
1325           dragenter_event_waiter.WaitForNextMatchingEvent(&dragenter_event));
1326       EXPECT_THAT(dragenter_event, state->expected_dom_event_data.Matches());
1327     }
1328 
1329     // Note that ash (unlike aura/x11) will not fire dragover event in response
1330     // to the same mouse event that trigerred a dragenter.  Because of that, we
1331     // postpone dragover testing until the next test step below.  See
1332     // implementation of ash::DragDropController::DragUpdate for details.
1333   }
1334 
1335   // Move the mouse twice in the right frame.  The 1st move will ensure that
1336   // allowed operations communicated by the renderer will be stored in
1337   // WebContentsViewAura::current_drag_op_.  The 2nd move will ensure that this
1338   // gets be copied into DesktopDragDropClientAuraX11::negotiated_operation_.
1339   for (int i = 0; i < 2; i++) {
1340     DOMDragEventWaiter dragover_event_waiter("dragover", right_frame());
1341     ASSERT_TRUE(SimulateMouseMoveToRightFrame());
1342 
1343     {  // Verify dragover DOM event.
1344       std::string dragover_event;
1345       EXPECT_TRUE(
1346           dragover_event_waiter.WaitForNextMatchingEvent(&dragover_event));
1347       EXPECT_THAT(dragover_event, state->expected_dom_event_data.Matches());
1348     }
1349   }
1350 
1351   // Release the mouse button to end the drag.
1352   state->drop_event_waiter.reset(new DOMDragEventWaiter("drop", right_frame()));
1353   SimulateMouseUp();
1354   // The test will continue in DragImageFromDisappearingFrame_Step3.
1355 }
1356 
DragImageFromDisappearingFrame_Step3(DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState * state)1357 void DragAndDropBrowserTest::DragImageFromDisappearingFrame_Step3(
1358     DragAndDropBrowserTest::DragImageFromDisappearingFrame_TestState* state) {
1359   // Verify drop DOM event.
1360   {
1361     std::string drop_event;
1362     EXPECT_TRUE(
1363         state->drop_event_waiter->WaitForNextMatchingEvent(&drop_event));
1364     state->drop_event_waiter.reset();
1365     EXPECT_THAT(drop_event, state->expected_dom_event_data.Matches());
1366   }
1367 }
1368 
1369 // There is no known way to execute test-controlled tasks during
1370 // a drag-and-drop loop run by Windows OS.
1371 #if defined(OS_WIN)
1372 #define MAYBE_CrossSiteDrag DISABLED_CrossSiteDrag
1373 #else
1374 #define MAYBE_CrossSiteDrag CrossSiteDrag
1375 #endif
1376 
1377 // Data that needs to be shared across multiple test steps below
1378 // (i.e. across CrossSiteDrag_Step2 and CrossSiteDrag_Step3).
1379 struct DragAndDropBrowserTest::CrossSiteDrag_TestState {
1380   std::unique_ptr<DOMDragEventWaiter> dragend_event_waiter;
1381   std::unique_ptr<DOMDragEventCounter> left_frame_events_counter;
1382   std::unique_ptr<DOMDragEventCounter> right_frame_events_counter;
1383 };
1384 
1385 // Scenario: drag an image from the left into the right frame when the
1386 // left-vs-right frames are cross-site.  This is a regression test for
1387 // https://crbug.com/59081.
1388 //
1389 // Test coverage: absence of dragenter, dragover, drop DOM events
1390 // + presence of dragstart, dragleave and dragend.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,MAYBE_CrossSiteDrag)1391 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, MAYBE_CrossSiteDrag) {
1392   std::string left_frame_site = "c.com";  // Always cross-site VS main frame.
1393   std::string right_frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
1394   ASSERT_TRUE(NavigateToTestPage("a.com"));
1395   ASSERT_TRUE(NavigateLeftFrame(left_frame_site, "image_source.html"));
1396   ASSERT_TRUE(NavigateRightFrame(right_frame_site, "drop_target.html"));
1397 
1398   // Setup test expectations.
1399   DragAndDropBrowserTest::CrossSiteDrag_TestState state;
1400   state.left_frame_events_counter.reset(new DOMDragEventCounter(left_frame()));
1401   state.right_frame_events_counter.reset(
1402       new DOMDragEventCounter(right_frame()));
1403 
1404   // Start the drag in the left frame.
1405   DragStartWaiter drag_start_waiter(web_contents());
1406   drag_start_waiter.PostTaskWhenDragStarts(
1407       base::Bind(&DragAndDropBrowserTest::CrossSiteDrag_Step2,
1408                  base::Unretained(this), base::Unretained(&state)));
1409   EXPECT_TRUE(SimulateMouseDownAndDragStartInLeftFrame());
1410 
1411   // The next step of the test (CrossSiteDrag_Step2) runs inside the
1412   // nested drag-and-drop message loop - the call below won't return until the
1413   // drag-and-drop has already ended.
1414   drag_start_waiter.WaitUntilDragStart(nullptr, nullptr, nullptr, nullptr);
1415 
1416   CrossSiteDrag_Step3(&state);
1417 }
1418 
CrossSiteDrag_Step2(DragAndDropBrowserTest::CrossSiteDrag_TestState * state)1419 void DragAndDropBrowserTest::CrossSiteDrag_Step2(
1420     DragAndDropBrowserTest::CrossSiteDrag_TestState* state) {
1421   // While "dragleave" and "drop" events are not expected in this test, we
1422   // simulate extra mouse operations for consistency with
1423   // DragImageBetweenFrames_Step2.
1424   ASSERT_TRUE(SimulateMouseMoveToLeftFrame());
1425   for (int i = 0; i < 3; i++) {
1426     content::DOMMessageQueue dom_message_queue(web_contents());
1427     ASSERT_TRUE(SimulateMouseMoveToRightFrame());
1428 
1429     // No events are expected from the right frame, so we can't wait for a
1430     // dragover event here.  Still - we do want to wait until the right frame
1431     // has had a chance to process any previous browser IPCs, so that in case
1432     // there *is* a bug and a dragover event *does* happen, we won't terminate
1433     // the test before the event has had a chance to be reported back to the
1434     // browser.
1435     std::string expected_response = base::StringPrintf("\"i%d\"", i);
1436     right_frame()->ExecuteJavaScriptWithUserGestureForTests(
1437         base::UTF8ToUTF16(base::StringPrintf(
1438             "domAutomationController.send(%s);", expected_response.c_str())));
1439 
1440     // Wait until our response comes back (it might be mixed with responses
1441     // carrying events that are sent by event_monitoring.js).
1442     std::string actual_response;
1443     do {
1444       ASSERT_TRUE(dom_message_queue.WaitForMessage(&actual_response));
1445     } while (actual_response != expected_response);
1446   }
1447 
1448   // Release the mouse button to end the drag.
1449   state->dragend_event_waiter.reset(
1450       new DOMDragEventWaiter("dragend", left_frame()));
1451   SimulateMouseUp();
1452   // The test will continue in DragImageBetweenFrames_Step3.
1453 }
1454 
CrossSiteDrag_Step3(DragAndDropBrowserTest::CrossSiteDrag_TestState * state)1455 void DragAndDropBrowserTest::CrossSiteDrag_Step3(
1456     DragAndDropBrowserTest::CrossSiteDrag_TestState* state) {
1457   EXPECT_TRUE(state->dragend_event_waiter->WaitForNextMatchingEvent(nullptr));
1458 
1459   // Since the start of the test the left frame should have seen a single
1460   // "dragstart",
1461   // and a "dragend" event (and possibly a "dragleave" and some "dragover"
1462   // events).
1463   EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1464                    "dragstart"));
1465   EXPECT_EQ(1, state->left_frame_events_counter->GetNumberOfReceivedEvents(
1466                    "dragend"));
1467   EXPECT_EQ(
1468       0, state->left_frame_events_counter->GetNumberOfReceivedEvents("drop"));
1469 
1470   // No events should have fired in the right frame, because it is cross-site
1471   // from the source of the drag.  This is the essence of this test.
1472   EXPECT_EQ(0, state->right_frame_events_counter->GetNumberOfReceivedEvents(
1473                    {"dragstart", "dragleave", "dragenter", "dragover", "drop",
1474                     "dragend"}));
1475 }
1476 
1477 // Test that screenX/screenY for drag updates are in screen coordinates.
1478 // See https://crbug.com/600402 where we mistook the root window coordinate
1479 // space for the screen coordinate space.
IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest,DragUpdateScreenCoordinates)1480 IN_PROC_BROWSER_TEST_P(DragAndDropBrowserTest, DragUpdateScreenCoordinates) {
1481   // Reposition the window so that the root window coordinate space and the
1482   // screen coordinate space are clearly distinct. Otherwise this test would
1483   // be inconclusive.
1484   // In addition to offsetting the window, use a small window size to avoid
1485   // rejection of the new bounds by the system.
1486   browser()->window()->SetBounds(gfx::Rect(200, 100, 700, 500));
1487   do {
1488     base::RunLoop run_loop;
1489     base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1490         FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
1491     run_loop.Run();
1492   } while (browser()->window()->GetBounds().origin() != gfx::Point(200, 100));
1493 
1494   std::string frame_site = use_cross_site_subframe() ? "b.com" : "a.com";
1495   ASSERT_TRUE(NavigateToTestPage("a.com"));
1496   ASSERT_TRUE(NavigateRightFrame(frame_site, "drop_target.html"));
1497 
1498   const gfx::Point screen_position = GetMiddleOfRightFrameInScreenCoords();
1499 
1500   DOMDragEventVerifier expected_dom_event_data;
1501   expected_dom_event_data.set_expected_client_position("(155, 150)");
1502   expected_dom_event_data.set_expected_screen_position(
1503       base::StringPrintf("(%d, %d)", screen_position.x(), screen_position.y()));
1504 
1505   DOMDragEventWaiter dragover_waiter("dragover", right_frame());
1506   ASSERT_TRUE(SimulateDragEnterToRightFrame("Dragged test text"));
1507 
1508   std::string dragover_event;
1509   ASSERT_TRUE(dragover_waiter.WaitForNextMatchingEvent(&dragover_event));
1510   EXPECT_THAT(dragover_event, expected_dom_event_data.Matches());
1511 }
1512 
1513 // TODO(paulmeyer): Should test the case of navigation happening in the middle
1514 // of a drag operation, and cross-site drags should be allowed across a
1515 // navigation.
1516 
1517 INSTANTIATE_TEST_SUITE_P(SameSiteSubframe,
1518                          DragAndDropBrowserTest,
1519                          ::testing::Values(false));
1520 
1521 INSTANTIATE_TEST_SUITE_P(CrossSiteSubframe,
1522                          DragAndDropBrowserTest,
1523                          ::testing::Values(true));
1524 
1525 }  // namespace chrome
1526