diff options
-rw-r--r-- | chrome_frame/chrome_frame_automation.cc | 220 | ||||
-rw-r--r-- | chrome_frame/chrome_frame_automation.h | 15 | ||||
-rw-r--r-- | chrome_frame/sync_msg_reply_dispatcher.cc | 51 | ||||
-rw-r--r-- | chrome_frame/sync_msg_reply_dispatcher.h | 72 | ||||
-rw-r--r-- | chrome_frame/test/automation_client_mock.h | 6 |
5 files changed, 145 insertions, 219 deletions
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc index bccdcc8..8d89cbd 100644 --- a/chrome_frame/chrome_frame_automation.cc +++ b/chrome_frame/chrome_frame_automation.cc @@ -24,6 +24,7 @@ #include "chrome/test/automation/tab_proxy.h" #include "chrome_frame/chrome_launcher.h" #include "chrome_frame/utils.h" +#include "chrome_frame/sync_msg_reply_dispatcher.h" #ifdef NDEBUG int64 kAutomationServerReasonableLaunchDelay = 1000; // in milliseconds @@ -91,135 +92,33 @@ class ChromeFrameAutomationProxyImpl::TabProxyNotificationMessageFilter std::list<AutomationHandle> tabs_list_; }; -// Class that maintains context during the async load/install extension -// operation. When done, InstallExtensionComplete is posted back to the UI -// thread so that the users of ChromeFrameAutomationClient can be notified. -class InstallExtensionContext - : public SyncMessageReplyDispatcher::SyncMessageCallContext { - public: - typedef Tuple1<AutomationMsg_ExtensionResponseValues> output_type; - - InstallExtensionContext(ChromeFrameAutomationClient* client, - const FilePath& crx_path, void* user_data) : client_(client), - crx_path_(crx_path), user_data_(user_data) { - } - - ~InstallExtensionContext() { - } - - void Completed(AutomationMsg_ExtensionResponseValues res) { - client_->PostTask(FROM_HERE, NewRunnableMethod(client_.get(), - &ChromeFrameAutomationClient::InstallExtensionComplete, crx_path_, - user_data_, res)); - } - - private: - scoped_refptr<ChromeFrameAutomationClient> client_; - FilePath crx_path_; - void* user_data_; -}; - -// Class that maintains context during the async retrieval of fetching the -// list of enabled extensions. When done, GetEnabledExtensionsComplete is -// posted back to the UI thread so that the users of -// ChromeFrameAutomationClient can be notified. -class GetEnabledExtensionsContext - : public SyncMessageReplyDispatcher::SyncMessageCallContext { - public: - typedef Tuple1<std::vector<FilePath> > output_type; - - GetEnabledExtensionsContext( - ChromeFrameAutomationClient* client, void* user_data) : client_(client), - user_data_(user_data) { - extension_directories_ = new std::vector<FilePath>(); - } - - ~GetEnabledExtensionsContext() { - // ChromeFrameAutomationClient::GetEnabledExtensionsComplete takes - // ownership of extension_directories_. - } - - std::vector<FilePath>* extension_directories() { - return extension_directories_; - } - - void Completed( - std::vector<FilePath> result) { - (*extension_directories_) = result; - client_->PostTask(FROM_HERE, NewRunnableMethod(client_.get(), - &ChromeFrameAutomationClient::GetEnabledExtensionsComplete, - user_data_, extension_directories_)); - } - - private: - scoped_refptr<ChromeFrameAutomationClient> client_; - std::vector<FilePath>* extension_directories_; - void* user_data_; -}; - -// Class that maintains contextual information for the create and connect -// external tab operations. -class CreateExternalTabContext - : public SyncMessageReplyDispatcher::SyncMessageCallContext { - public: - typedef Tuple3<HWND, HWND, int> output_type; - explicit CreateExternalTabContext(ChromeFrameAutomationClient* client) - : client_(client) { - } - - void Completed(HWND chrome_window, HWND tab_window, int tab_handle) { - client_->PostTask(FROM_HERE, - NewRunnableMethod(client_.get(), - &ChromeFrameAutomationClient::CreateExternalTabComplete, - chrome_window, tab_window, tab_handle)); - } - - private: - scoped_refptr<ChromeFrameAutomationClient> client_; -}; - -// This class maintains context information for the BeginNavigate operations -// pertaining to the external tab. -class BeginNavigateContext - : public SyncMessageReplyDispatcher::SyncMessageCallContext { - public: - explicit BeginNavigateContext(ChromeFrameAutomationClient* client) - : client_(client) {} - - typedef Tuple1<AutomationMsg_NavigationResponseValues> output_type; - - void Completed(AutomationMsg_NavigationResponseValues response) { - client_->BeginNavigateCompleted(response); - } - - private: - scoped_refptr<ChromeFrameAutomationClient> client_; -}; - class ChromeFrameAutomationProxyImpl::CFMsgDispatcher : public SyncMessageReplyDispatcher { public: CFMsgDispatcher() : SyncMessageReplyDispatcher() {} protected: virtual bool HandleMessageType(const IPC::Message& msg, - SyncMessageCallContext* context) { - switch (context->message_type()) { + const MessageSent& origin) { + switch (origin.type) { case AutomationMsg_CreateExternalTab::ID: case AutomationMsg_ConnectExternalTab::ID: - InvokeCallback<CreateExternalTabContext>(msg, context); + InvokeCallback<Tuple3<HWND, HWND, int> >(msg, origin); break; case AutomationMsg_NavigateExternalTabAtIndex::ID: case AutomationMsg_NavigateInExternalTab::ID: - InvokeCallback<BeginNavigateContext>(msg, context); + InvokeCallback<Tuple1<AutomationMsg_NavigationResponseValues> >(msg, + origin); break; case AutomationMsg_InstallExtension::ID: - InvokeCallback<InstallExtensionContext>(msg, context); + InvokeCallback<Tuple1<AutomationMsg_ExtensionResponseValues> >(msg, + origin); break; case AutomationMsg_LoadExpandedExtension::ID: - InvokeCallback<InstallExtensionContext>(msg, context); + InvokeCallback<Tuple1<AutomationMsg_ExtensionResponseValues> >(msg, + origin); break; case AutomationMsg_GetEnabledExtensions::ID: - InvokeCallback<GetEnabledExtensionsContext>(msg, context); + InvokeCallback<Tuple1<std::vector<FilePath> > >(msg, origin); break; default: NOTREACHED(); @@ -244,10 +143,9 @@ ChromeFrameAutomationProxyImpl::~ChromeFrameAutomationProxyImpl() { TRACE_EVENT_END("chromeframe.automationproxy", this, ""); } -void ChromeFrameAutomationProxyImpl::SendAsAsync( - IPC::SyncMessage* msg, - SyncMessageReplyDispatcher::SyncMessageCallContext* context, void* key) { - sync_->Push(msg, context, key); +void ChromeFrameAutomationProxyImpl::SendAsAsync(IPC::SyncMessage* msg, + void* callback, void* key) { + sync_->Push(msg, callback, key); channel_->ChannelProxy::Send(msg); } @@ -715,8 +613,8 @@ bool ChromeFrameAutomationClient::NavigateToIndex(int index) { IPC::SyncMessage* msg = new AutomationMsg_NavigateExternalTabAtIndex( 0, tab_->handle(), index, NULL); - automation_server_->SendAsAsync(msg, new BeginNavigateContext(this), - this); + automation_server_->SendAsAsync(msg, NewCallback(this, + &ChromeFrameAutomationClient::BeginNavigateCompleted), this); return true; } @@ -758,7 +656,8 @@ void ChromeFrameAutomationClient::BeginNavigate(const GURL& url, IPC::SyncMessage* msg = new AutomationMsg_NavigateInExternalTab(0, tab_->handle(), url, referrer, NULL); - automation_server_->SendAsAsync(msg, new BeginNavigateContext(this), this); + automation_server_->SendAsAsync(msg, NewCallback(this, + &ChromeFrameAutomationClient::BeginNavigateCompleted), this); RECT client_rect = {0}; chrome_frame_delegate_->GetBounds(&client_rect); @@ -794,6 +693,32 @@ void ChromeFrameAutomationClient::FindInPage(const std::wstring& search_string, automation_server_->SendAsAsync(msg, NULL, this); } +// Class that maintains context during the async load/install extension +// operation. When done, InstallExtensionComplete is posted back to the UI +// thread so that the users of ChromeFrameAutomationClient can be notified. +class InstallExtensionContext { + public: + InstallExtensionContext(ChromeFrameAutomationClient* client, + const FilePath& crx_path, void* user_data) : client_(client), + crx_path_(crx_path), user_data_(user_data) { + } + + ~InstallExtensionContext() { + } + + void InstallExtensionComplete(AutomationMsg_ExtensionResponseValues res) { + client_->PostTask(FROM_HERE, NewRunnableMethod(client_.get(), + &ChromeFrameAutomationClient::InstallExtensionComplete, crx_path_, + user_data_, res)); + delete this; + } + + private: + scoped_refptr<ChromeFrameAutomationClient> client_; + FilePath crx_path_; + void* user_data_; +}; + void ChromeFrameAutomationClient::InstallExtension( const FilePath& crx_path, void* user_data) { @@ -811,7 +736,8 @@ void ChromeFrameAutomationClient::InstallExtension( new AutomationMsg_InstallExtension(0, crx_path, NULL); // The context will delete itself after it is called. - automation_server_->SendAsAsync(msg, ctx, this); + automation_server_->SendAsAsync(msg, NewCallback(ctx, + &InstallExtensionContext::InstallExtensionComplete), this); } void ChromeFrameAutomationClient::InstallExtensionComplete( @@ -825,6 +751,42 @@ void ChromeFrameAutomationClient::InstallExtensionComplete( } } +// Class that maintains context during the async retrieval of fetching the +// list of enabled extensions. When done, GetEnabledExtensionsComplete is +// posted back to the UI thread so that the users of +// ChromeFrameAutomationClient can be notified. +class GetEnabledExtensionsContext { + public: + GetEnabledExtensionsContext( + ChromeFrameAutomationClient* client, void* user_data) : client_(client), + user_data_(user_data) { + extension_directories_ = new std::vector<FilePath>(); + } + + ~GetEnabledExtensionsContext() { + // ChromeFrameAutomationClient::GetEnabledExtensionsComplete takes + // ownership of extension_directories_. + } + + std::vector<FilePath>* extension_directories() { + return extension_directories_; + } + + void GetEnabledExtensionsComplete( + std::vector<FilePath> result) { + (*extension_directories_) = result; + client_->PostTask(FROM_HERE, NewRunnableMethod(client_.get(), + &ChromeFrameAutomationClient::GetEnabledExtensionsComplete, + user_data_, extension_directories_)); + delete this; + } + + private: + scoped_refptr<ChromeFrameAutomationClient> client_; + std::vector<FilePath>* extension_directories_; + void* user_data_; +}; + void ChromeFrameAutomationClient::GetEnabledExtensions(void* user_data) { if (automation_server_ == NULL) { GetEnabledExtensionsComplete(user_data, &std::vector<FilePath>()); @@ -838,7 +800,8 @@ void ChromeFrameAutomationClient::GetEnabledExtensions(void* user_data) { 0, ctx->extension_directories()); // The context will delete itself after it is called. - automation_server_->SendAsAsync(msg, ctx, this); + automation_server_->SendAsAsync(msg, NewCallback(ctx, + &GetEnabledExtensionsContext::GetEnabledExtensionsComplete), this); } void ChromeFrameAutomationClient::GetEnabledExtensionsComplete( @@ -882,7 +845,8 @@ void ChromeFrameAutomationClient::LoadExpandedExtension( new AutomationMsg_LoadExpandedExtension(0, path, NULL); // The context will delete itself after it is called. - automation_server_->SendAsAsync(msg, ctx, this); + automation_server_->SendAsAsync(msg, NewCallback(ctx, + &InstallExtensionContext::InstallExtensionComplete), this); } void ChromeFrameAutomationClient::CreateExternalTab() { @@ -913,8 +877,8 @@ void ChromeFrameAutomationClient::CreateExternalTab() { IPC::SyncMessage* message = new AutomationMsg_CreateExternalTab(0, settings, NULL, NULL, NULL); - automation_server_->SendAsAsync(message, new CreateExternalTabContext(this), - this); + automation_server_->SendAsAsync(message, NewCallback(this, + &ChromeFrameAutomationClient::CreateExternalTabComplete), this); } void ChromeFrameAutomationClient::CreateExternalTabComplete(HWND chrome_window, @@ -937,7 +901,8 @@ void ChromeFrameAutomationClient::CreateExternalTabComplete(HWND chrome_window, tab_handle_ = tab_handle; } - InitializeComplete(launch_result); + PostTask(FROM_HERE, NewRunnableMethod(this, + &ChromeFrameAutomationClient::InitializeComplete, launch_result)); } void ChromeFrameAutomationClient::SetEnableExtensionAutomation( @@ -983,9 +948,8 @@ void ChromeFrameAutomationClient::LaunchComplete( IPC::SyncMessage* message = new AutomationMsg_ConnectExternalTab(0, external_tab_cookie_, true, NULL, NULL, NULL); - automation_server_->SendAsAsync(message, - new CreateExternalTabContext(this), - this); + automation_server_->SendAsAsync(message, NewCallback(this, + &ChromeFrameAutomationClient::CreateExternalTabComplete), this); DLOG(INFO) << __FUNCTION__ << ": sending CreateExternalTabComplete"; } } diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h index 3461eba2..01a64ac 100644 --- a/chrome_frame/chrome_frame_automation.h +++ b/chrome_frame/chrome_frame_automation.h @@ -23,7 +23,6 @@ #include "chrome_frame/chrome_frame_delegate.h" #include "chrome_frame/chrome_frame_histograms.h" #include "chrome_frame/plugin_url_request.h" -#include "chrome_frame/sync_msg_reply_dispatcher.h" // By a convoluated route, this timeout also winds up being the sync automation // message timeout. See the ChromeFrameAutomationProxyImpl ctor and the @@ -36,10 +35,8 @@ enum AutomationPageFontSize; struct DECLSPEC_NOVTABLE ChromeFrameAutomationProxy { // NOLINT virtual bool Send(IPC::Message* msg) = 0; - virtual void SendAsAsync( - IPC::SyncMessage* msg, - SyncMessageReplyDispatcher::SyncMessageCallContext* context, - void* key) = 0; + virtual void SendAsAsync(IPC::SyncMessage* msg, void* callback, + void* key) = 0; virtual void CancelAsync(void* key) = 0; virtual scoped_refptr<TabProxy> CreateTabProxy(int handle) = 0; virtual void ReleaseTabProxy(AutomationHandle handle) = 0; @@ -58,10 +55,7 @@ class ChromeFrameAutomationProxyImpl : public ChromeFrameAutomationProxy, // .. and non-public inheritance is verboten. public AutomationProxy { public: - virtual void SendAsAsync( - IPC::SyncMessage* msg, - SyncMessageReplyDispatcher::SyncMessageCallContext* context, - void* key); + virtual void SendAsAsync(IPC::SyncMessage* msg, void* callback, void* key); virtual void CancelAsync(void* key); @@ -368,9 +362,6 @@ class ChromeFrameAutomationClient virtual void OnCookiesRetrieved(bool success, const GURL& url, const std::string& cookie_string, int cookie_id); - friend class BeginNavigateContext; - friend class CreateExternalTabContext; - public: void SetUrlFetcher(PluginUrlRequestManager* url_fetcher) { DCHECK(url_fetcher != NULL); diff --git a/chrome_frame/sync_msg_reply_dispatcher.cc b/chrome_frame/sync_msg_reply_dispatcher.cc index 1b51516..b301698 100644 --- a/chrome_frame/sync_msg_reply_dispatcher.cc +++ b/chrome_frame/sync_msg_reply_dispatcher.cc @@ -6,61 +6,56 @@ #include "ipc/ipc_sync_message.h" -void SyncMessageReplyDispatcher::Push(IPC::SyncMessage* msg, - SyncMessageCallContext* context, +void SyncMessageReplyDispatcher::Push(IPC::SyncMessage* msg, void* callback, void* key) { - context->message_type_ = msg->type(); - context->id_ = IPC::SyncMessage::GetMessageId(*msg); - context->key_ = key; - + MessageSent pending(IPC::SyncMessage::GetMessageId(*msg), + msg->type(), callback, key); AutoLock lock(message_queue_lock_); - message_queue_.push_back(context); + message_queue_.push_back(pending); } -bool SyncMessageReplyDispatcher::HandleMessageType( - const IPC::Message& msg, SyncMessageCallContext* context) { +bool SyncMessageReplyDispatcher::HandleMessageType(const IPC::Message& msg, + const MessageSent& origin) { return false; } bool SyncMessageReplyDispatcher::OnMessageReceived(const IPC::Message& msg) { - SyncMessageCallContext* context = GetContext(msg); - // No context e.g. no return values and/or don't care - if (!context) { + MessageSent origin; + if (!Pop(msg, &origin)) { return false; } - return HandleMessageType(msg, context); + // No callback e.g. no return values and/or don't care + if (origin.callback == NULL) + return true; + + return HandleMessageType(msg, origin); } void SyncMessageReplyDispatcher::Cancel(void* key) { DCHECK(key != NULL); AutoLock lock(message_queue_lock_); - PendingSyncMessageQueue::iterator it = message_queue_.begin(); - while (it != message_queue_.end()) { - SyncMessageCallContext* context = *it; - if (context->key_ == key) { - it = message_queue_.erase(it); - delete context; - } else { - ++it; + PendingSyncMessageQueue::iterator it; + for (it = message_queue_.begin(); it != message_queue_.end(); ++it) { + if (it->key == key) { + it->key = NULL; } } } -SyncMessageReplyDispatcher::SyncMessageCallContext* - SyncMessageReplyDispatcher::GetContext(const IPC::Message& msg) { +bool SyncMessageReplyDispatcher::Pop(const IPC::Message& msg, MessageSent* t) { if (!msg.is_reply()) - return NULL; + return false; int id = IPC::SyncMessage::GetMessageId(msg); AutoLock lock(message_queue_lock_); PendingSyncMessageQueue::iterator it; for (it = message_queue_.begin(); it != message_queue_.end(); ++it) { - SyncMessageCallContext* context = *it; - if (context->id_ == id) { + if (it->id == id) { + *t = *it; message_queue_.erase(it); - return context; + return true; } } - return NULL; + return false; } diff --git a/chrome_frame/sync_msg_reply_dispatcher.h b/chrome_frame/sync_msg_reply_dispatcher.h index 7d47bd1..724c007 100644 --- a/chrome_frame/sync_msg_reply_dispatcher.h +++ b/chrome_frame/sync_msg_reply_dispatcher.h @@ -23,22 +23,14 @@ // cases where you care about the return values of synchronous messages. // // Sample usage pattern: -// Define a class which inherits from SyncMessageCallContext which specifies -// the output_type tuple and has a Completed member function. -// class SampleContext -// : public SyncMessageReplyDispatcher::SyncMessageCallContext { -// public: -// typedef Tuple1<int> output_type; -// void Completed(int arg) {} -// }; // // // Add handling for desired message types. // class SyncMessageReplyDispatcherImpl : public SyncMessageReplyDispatcher { // virtual bool HandleMessageType(const IPC::Message& msg, -// SyncMessageReplyDispatcher* context) { -// switch (context->message_type()) { +// const MessageSent& origin) { +// switch (origin.type) { // case AutomationMsg_CreateExternalTab::ID: -// InvokeCallback<CreateExternalTabContext>(msg, context); +// InvokeCallback<Tuple3<HWND, HWND, int> >(msg, origin); // break; // [HANDLING FOR OTHER EXPECTED MESSAGE TYPES] // } @@ -48,42 +40,29 @@ // IPC::SyncChannel channel_; // channel_.AddFilter(new SyncMessageReplyDispatcherImpl()); // -// sync_->Push(msg, new SampleContext, this); +// sync_->Push(msg, NewCallback(this, CallbackMethod, this); // channel_->ChannelProxy::Send(msg); // class SyncMessageReplyDispatcher : public IPC::ChannelProxy::MessageFilter { public: - class SyncMessageCallContext { - public: - SyncMessageCallContext() - : id_(0), - message_type_(0), - key_(NULL) {} - - virtual ~SyncMessageCallContext() {} - - uint32 message_type() const { - return message_type_; - } - - private: - int id_; - uint32 message_type_; - void* key_; - - friend class SyncMessageReplyDispatcher; - }; - SyncMessageReplyDispatcher() {} - void Push(IPC::SyncMessage* msg, SyncMessageCallContext* context, - void* key); + void Push(IPC::SyncMessage* msg, void* callback, void* key); void Cancel(void* key); protected: - typedef std::deque<SyncMessageCallContext*> PendingSyncMessageQueue; + struct MessageSent { + MessageSent() {} + MessageSent(int id, uint32 type, void* callback, void* key) + : id(id), callback(callback), type(type), key(key) {} + int id; + void* callback; + void* key; + uint32 type; + }; - SyncMessageCallContext* GetContext(const IPC::Message& msg); + typedef std::deque<MessageSent> PendingSyncMessageQueue; + bool Pop(const IPC::Message& msg, MessageSent* t); virtual bool OnMessageReceived(const IPC::Message& msg); // Child classes must implement a handler for the message types they are @@ -91,22 +70,21 @@ class SyncMessageReplyDispatcher : public IPC::ChannelProxy::MessageFilter { // to any of the sync messages you are handling, then you don't have to // implement this. virtual bool HandleMessageType(const IPC::Message& msg, - SyncMessageCallContext* context); + const MessageSent& origin); template <typename T> - void InvokeCallback(const IPC::Message& msg, - SyncMessageCallContext* call_context) { - if (!call_context || !call_context->key_) { - NOTREACHED() << "Invalid context parameter"; + void InvokeCallback(const IPC::Message& msg, const MessageSent& origin) { + // Ensure we delete the callback + scoped_ptr<CallbackRunner<T> > c( + reinterpret_cast<CallbackRunner<T>*>(origin.callback)); + if (origin.key == NULL) { // Canceled return; } - T* context = static_cast<T*>(call_context); - T::output_type tmp; // Acts as "initializer" for output parameters. - IPC::ParamDeserializer<T::output_type> deserializer(tmp); + T tmp; // Acts as "initializer" for output parameters. + IPC::ParamDeserializer<T> deserializer(tmp); if (deserializer.MessageReplyDeserializer::SerializeOutputParameters(msg)) { - DispatchToMethod(context, &T::Completed, deserializer.out_); - delete context; + c->RunWithParams(deserializer.out_); } else { // TODO(stoyan): How to handle errors? } diff --git a/chrome_frame/test/automation_client_mock.h b/chrome_frame/test/automation_client_mock.h index 09b1484..d08d62d3 100644 --- a/chrome_frame/test/automation_client_mock.h +++ b/chrome_frame/test/automation_client_mock.h @@ -90,10 +90,8 @@ struct MockCFDelegate : public ChromeFrameDelegateImpl { class MockAutomationProxy : public ChromeFrameAutomationProxy { public: MOCK_METHOD1(Send, bool(IPC::Message*)); - MOCK_METHOD3(SendAsAsync, - void(IPC::SyncMessage* msg, - SyncMessageReplyDispatcher::SyncMessageCallContext* context, - void* key)); + MOCK_METHOD3(SendAsAsync, void(IPC::SyncMessage* msg, void* callback, + void* key)); MOCK_METHOD1(CancelAsync, void(void* key)); MOCK_METHOD1(CreateTabProxy, scoped_refptr<TabProxy>(int handle)); MOCK_METHOD1(ReleaseTabProxy, void(AutomationHandle handle)); |