Index: chrome/test/base/interactive_test_utils_mac.mm |
diff --git a/chrome/test/base/interactive_test_utils_mac.mm b/chrome/test/base/interactive_test_utils_mac.mm |
index 0d00f3a6614e3aacd4c9141ed971ae02590ea1d1..283c5cf00f4c312cdeb87de01814b7aa8091b07d 100644 |
--- a/chrome/test/base/interactive_test_utils_mac.mm |
+++ b/chrome/test/base/interactive_test_utils_mac.mm |
@@ -7,12 +7,93 @@ |
#include <Carbon/Carbon.h> |
#import <Cocoa/Cocoa.h> |
-#include "base/message_loop/message_loop.h" |
#include "chrome/app/chrome_command_ids.h" |
#import "ui/base/test/windowed_nsnotification_observer.h" |
+#include "ui/gfx/animation/tween.h" |
namespace ui_test_utils { |
+namespace { |
+ |
+// Runs a list of drag and drop |operations| on a single RunLoop. |
+// |
+// We need to execute drag and drop operations as a batch, so the nested |
+// RunMoveLoop()'s RunLoop is cancelled before the top-level one from which we |
+// post the simulated events, otherwise we'll deadlock. |
+class OperationRunner { |
+ public: |
+ static void Run(const std::list<DragAndDropOperation>& operations) { |
+ OperationRunner runner(operations); |
+ base::RunLoop run_loop; |
+ runner.quit_closure_ = run_loop.QuitClosure(); |
+ base::MessageLoop::current()->PostTask( |
+ FROM_HERE, |
+ base::Bind(&OperationRunner::Next, base::Unretained(&runner))); |
+ run_loop.Run(); |
+ } |
+ |
+ private: |
+ explicit OperationRunner(const std::list<DragAndDropOperation>& operations) |
+ : operations_(operations) {} |
+ |
+ void Next() { |
+ if (operations_.empty()) { |
+ base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure_); |
+ return; |
+ } |
+ |
+ const DragAndDropOperation op = operations_.front(); |
+ operations_.pop_front(); |
+ auto next = base::Bind(&OperationRunner::Next, base::Unretained(this)); |
+ switch (op.type()) { |
+ case DragAndDropOperation::Type::Move: |
+ ui_controls::SendMouseMoveNotifyWhenDone(op.point().x(), op.point().y(), |
+ next); |
+ break; |
+ |
+ case DragAndDropOperation::Type::MouseDown: |
+ ui_controls::SendMouseEventsNotifyWhenDone(ui_controls::LEFT, |
+ ui_controls::DOWN, next); |
+ break; |
+ |
+ case DragAndDropOperation::Type::MouseUp: |
+ ui_controls::SendMouseEventsNotifyWhenDone(ui_controls::LEFT, |
+ ui_controls::UP, next); |
+ break; |
+ } |
+ } |
+ |
+ ~OperationRunner() { DCHECK(operations_.empty()); } |
+ |
+ base::Closure quit_closure_; |
+ std::list<DragAndDropOperation> operations_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(OperationRunner); |
+}; |
+ |
+} // namespace |
+ |
+void DragAndDropSequence(const std::list<DragAndDropOperation>& operations) { |
+ OperationRunner::Run(operations); |
+} |
+ |
+void DragAndDrop(const gfx::Point& from, const gfx::Point& to, int steps) { |
+ DCHECK_GE(steps, 1); |
+ std::list<DragAndDropOperation> operations; |
+ operations.push_back(DragAndDropOperation::Move(from)); |
+ operations.push_back(DragAndDropOperation::MouseDown()); |
+ |
+ for (int i = 1; i <= steps; ++i) { |
+ const double progress = static_cast<double>(i) / steps; |
+ operations.push_back(DragAndDropOperation::Move( |
+ gfx::Point(gfx::Tween::IntValueBetween(progress, from.x(), to.x()), |
+ gfx::Tween::IntValueBetween(progress, from.y(), to.y())))); |
+ } |
+ |
+ operations.push_back(DragAndDropOperation::MouseUp()); |
+ DragAndDropSequence(operations); |
+} |
+ |
void HideNativeWindow(gfx::NativeWindow window) { |
[window orderOut:nil]; |
} |
@@ -44,4 +125,19 @@ bool ShowAndFocusNativeWindow(gfx::NativeWindow window) { |
return !async_waiter || notification_observed; |
} |
+// static |
+DragAndDropOperation DragAndDropOperation::Move(const gfx::Point& p) { |
tapted
2016/06/06 07:12:36
nit (per previous comment) This should move up as
themblsha
2016/06/06 17:20:27
Whoops, sorry.
|
+ return DragAndDropOperation(Type::Move, p); |
+} |
+ |
+// static |
+DragAndDropOperation DragAndDropOperation::MouseDown() { |
+ return DragAndDropOperation(Type::MouseDown, gfx::Point()); |
+} |
+ |
+// static |
+DragAndDropOperation DragAndDropOperation::MouseUp() { |
+ return DragAndDropOperation(Type::MouseUp, gfx::Point()); |
+} |
+ |
} // namespace ui_test_utils |