Chromium Code Reviews| 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 |