diff options
Diffstat (limited to 'chrome_frame')
-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, 219 insertions, 145 deletions
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc index 8d89cbd..bccdcc8 100644 --- a/chrome_frame/chrome_frame_automation.cc +++ b/chrome_frame/chrome_frame_automation.cc @@ -24,7 +24,6 @@ #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 @@ -92,33 +91,135 @@ 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, - const MessageSent& origin) { - switch (origin.type) { + SyncMessageCallContext* context) { + switch (context->message_type()) { case AutomationMsg_CreateExternalTab::ID: case AutomationMsg_ConnectExternalTab::ID: - InvokeCallback<Tuple3<HWND, HWND, int> >(msg, origin); + InvokeCallback<CreateExternalTabContext>(msg, context); break; case AutomationMsg_NavigateExternalTabAtIndex::ID: case AutomationMsg_NavigateInExternalTab::ID: - InvokeCallback<Tuple1<AutomationMsg_NavigationResponseValues> >(msg, - origin); + InvokeCallback<BeginNavigateContext>(msg, context); break; case AutomationMsg_InstallExtension::ID: - InvokeCallback<Tuple1<AutomationMsg_ExtensionResponseValues> >(msg, - origin); + InvokeCallback<InstallExtensionContext>(msg, context); break; case AutomationMsg_LoadExpandedExtension::ID: - InvokeCallback<Tuple1<AutomationMsg_ExtensionResponseValues> >(msg, - origin); + InvokeCallback<InstallExtensionContext>(msg, context); break; case AutomationMsg_GetEnabledExtensions::ID: - InvokeCallback<Tuple1<std::vector<FilePath> > >(msg, origin); + InvokeCallback<GetEnabledExtensionsContext>(msg, context); break; default: NOTREACHED(); @@ -143,9 +244,10 @@ ChromeFrameAutomationProxyImpl::~ChromeFrameAutomationProxyImpl() { TRACE_EVENT_END("chromeframe.automationproxy", this, ""); } -void ChromeFrameAutomationProxyImpl::SendAsAsync(IPC::SyncMessage* msg, - void* callback, void* key) { - sync_->Push(msg, callback, key); +void ChromeFrameAutomationProxyImpl::SendAsAsync( + IPC::SyncMessage* msg, + SyncMessageReplyDispatcher::SyncMessageCallContext* context, void* key) { + sync_->Push(msg, context, key); channel_->ChannelProxy::Send(msg); } @@ -613,8 +715,8 @@ bool ChromeFrameAutomationClient::NavigateToIndex(int index) { IPC::SyncMessage* msg = new AutomationMsg_NavigateExternalTabAtIndex( 0, tab_->handle(), index, NULL); - automation_server_->SendAsAsync(msg, NewCallback(this, - &ChromeFrameAutomationClient::BeginNavigateCompleted), this); + automation_server_->SendAsAsync(msg, new BeginNavigateContext(this), + this); return true; } @@ -656,8 +758,7 @@ void ChromeFrameAutomationClient::BeginNavigate(const GURL& url, IPC::SyncMessage* msg = new AutomationMsg_NavigateInExternalTab(0, tab_->handle(), url, referrer, NULL); - automation_server_->SendAsAsync(msg, NewCallback(this, - &ChromeFrameAutomationClient::BeginNavigateCompleted), this); + automation_server_->SendAsAsync(msg, new BeginNavigateContext(this), this); RECT client_rect = {0}; chrome_frame_delegate_->GetBounds(&client_rect); @@ -693,32 +794,6 @@ 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) { @@ -736,8 +811,7 @@ void ChromeFrameAutomationClient::InstallExtension( new AutomationMsg_InstallExtension(0, crx_path, NULL); // The context will delete itself after it is called. - automation_server_->SendAsAsync(msg, NewCallback(ctx, - &InstallExtensionContext::InstallExtensionComplete), this); + automation_server_->SendAsAsync(msg, ctx, this); } void ChromeFrameAutomationClient::InstallExtensionComplete( @@ -751,42 +825,6 @@ 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>()); @@ -800,8 +838,7 @@ void ChromeFrameAutomationClient::GetEnabledExtensions(void* user_data) { 0, ctx->extension_directories()); // The context will delete itself after it is called. - automation_server_->SendAsAsync(msg, NewCallback(ctx, - &GetEnabledExtensionsContext::GetEnabledExtensionsComplete), this); + automation_server_->SendAsAsync(msg, ctx, this); } void ChromeFrameAutomationClient::GetEnabledExtensionsComplete( @@ -845,8 +882,7 @@ void ChromeFrameAutomationClient::LoadExpandedExtension( new AutomationMsg_LoadExpandedExtension(0, path, NULL); // The context will delete itself after it is called. - automation_server_->SendAsAsync(msg, NewCallback(ctx, - &InstallExtensionContext::InstallExtensionComplete), this); + automation_server_->SendAsAsync(msg, ctx, this); } void ChromeFrameAutomationClient::CreateExternalTab() { @@ -877,8 +913,8 @@ void ChromeFrameAutomationClient::CreateExternalTab() { IPC::SyncMessage* message = new AutomationMsg_CreateExternalTab(0, settings, NULL, NULL, NULL); - automation_server_->SendAsAsync(message, NewCallback(this, - &ChromeFrameAutomationClient::CreateExternalTabComplete), this); + automation_server_->SendAsAsync(message, new CreateExternalTabContext(this), + this); } void ChromeFrameAutomationClient::CreateExternalTabComplete(HWND chrome_window, @@ -901,8 +937,7 @@ void ChromeFrameAutomationClient::CreateExternalTabComplete(HWND chrome_window, tab_handle_ = tab_handle; } - PostTask(FROM_HERE, NewRunnableMethod(this, - &ChromeFrameAutomationClient::InitializeComplete, launch_result)); + InitializeComplete(launch_result); } void ChromeFrameAutomationClient::SetEnableExtensionAutomation( @@ -948,8 +983,9 @@ void ChromeFrameAutomationClient::LaunchComplete( IPC::SyncMessage* message = new AutomationMsg_ConnectExternalTab(0, external_tab_cookie_, true, NULL, NULL, NULL); - automation_server_->SendAsAsync(message, NewCallback(this, - &ChromeFrameAutomationClient::CreateExternalTabComplete), this); + automation_server_->SendAsAsync(message, + new CreateExternalTabContext(this), + this); DLOG(INFO) << __FUNCTION__ << ": sending CreateExternalTabComplete"; } } diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h index 01a64ac..3461eba2 100644 --- a/chrome_frame/chrome_frame_automation.h +++ b/chrome_frame/chrome_frame_automation.h @@ -23,6 +23,7 @@ #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 @@ -35,8 +36,10 @@ enum AutomationPageFontSize; struct DECLSPEC_NOVTABLE ChromeFrameAutomationProxy { // NOLINT virtual bool Send(IPC::Message* msg) = 0; - virtual void SendAsAsync(IPC::SyncMessage* msg, void* callback, - void* key) = 0; + virtual void SendAsAsync( + IPC::SyncMessage* msg, + SyncMessageReplyDispatcher::SyncMessageCallContext* context, + void* key) = 0; virtual void CancelAsync(void* key) = 0; virtual scoped_refptr<TabProxy> CreateTabProxy(int handle) = 0; virtual void ReleaseTabProxy(AutomationHandle handle) = 0; @@ -55,7 +58,10 @@ class ChromeFrameAutomationProxyImpl : public ChromeFrameAutomationProxy, // .. and non-public inheritance is verboten. public AutomationProxy { public: - virtual void SendAsAsync(IPC::SyncMessage* msg, void* callback, void* key); + virtual void SendAsAsync( + IPC::SyncMessage* msg, + SyncMessageReplyDispatcher::SyncMessageCallContext* context, + void* key); virtual void CancelAsync(void* key); @@ -362,6 +368,9 @@ 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 b301698..1b51516 100644 --- a/chrome_frame/sync_msg_reply_dispatcher.cc +++ b/chrome_frame/sync_msg_reply_dispatcher.cc @@ -6,56 +6,61 @@ #include "ipc/ipc_sync_message.h" -void SyncMessageReplyDispatcher::Push(IPC::SyncMessage* msg, void* callback, +void SyncMessageReplyDispatcher::Push(IPC::SyncMessage* msg, + SyncMessageCallContext* context, void* key) { - MessageSent pending(IPC::SyncMessage::GetMessageId(*msg), - msg->type(), callback, key); + context->message_type_ = msg->type(); + context->id_ = IPC::SyncMessage::GetMessageId(*msg); + context->key_ = key; + AutoLock lock(message_queue_lock_); - message_queue_.push_back(pending); + message_queue_.push_back(context); } -bool SyncMessageReplyDispatcher::HandleMessageType(const IPC::Message& msg, - const MessageSent& origin) { +bool SyncMessageReplyDispatcher::HandleMessageType( + const IPC::Message& msg, SyncMessageCallContext* context) { return false; } bool SyncMessageReplyDispatcher::OnMessageReceived(const IPC::Message& msg) { - MessageSent origin; - if (!Pop(msg, &origin)) { + SyncMessageCallContext* context = GetContext(msg); + // No context e.g. no return values and/or don't care + if (!context) { return false; } - // No callback e.g. no return values and/or don't care - if (origin.callback == NULL) - return true; - - return HandleMessageType(msg, origin); + return HandleMessageType(msg, context); } void SyncMessageReplyDispatcher::Cancel(void* key) { DCHECK(key != NULL); AutoLock lock(message_queue_lock_); - PendingSyncMessageQueue::iterator it; - for (it = message_queue_.begin(); it != message_queue_.end(); ++it) { - if (it->key == key) { - it->key = NULL; + 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; } } } -bool SyncMessageReplyDispatcher::Pop(const IPC::Message& msg, MessageSent* t) { +SyncMessageReplyDispatcher::SyncMessageCallContext* + SyncMessageReplyDispatcher::GetContext(const IPC::Message& msg) { if (!msg.is_reply()) - return false; + return NULL; int id = IPC::SyncMessage::GetMessageId(msg); AutoLock lock(message_queue_lock_); PendingSyncMessageQueue::iterator it; for (it = message_queue_.begin(); it != message_queue_.end(); ++it) { - if (it->id == id) { - *t = *it; + SyncMessageCallContext* context = *it; + if (context->id_ == id) { message_queue_.erase(it); - return true; + return context; } } - return false; + return NULL; } diff --git a/chrome_frame/sync_msg_reply_dispatcher.h b/chrome_frame/sync_msg_reply_dispatcher.h index 724c007..7d47bd1 100644 --- a/chrome_frame/sync_msg_reply_dispatcher.h +++ b/chrome_frame/sync_msg_reply_dispatcher.h @@ -23,14 +23,22 @@ // 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, -// const MessageSent& origin) { -// switch (origin.type) { +// SyncMessageReplyDispatcher* context) { +// switch (context->message_type()) { // case AutomationMsg_CreateExternalTab::ID: -// InvokeCallback<Tuple3<HWND, HWND, int> >(msg, origin); +// InvokeCallback<CreateExternalTabContext>(msg, context); // break; // [HANDLING FOR OTHER EXPECTED MESSAGE TYPES] // } @@ -40,29 +48,42 @@ // IPC::SyncChannel channel_; // channel_.AddFilter(new SyncMessageReplyDispatcherImpl()); // -// sync_->Push(msg, NewCallback(this, CallbackMethod, this); +// sync_->Push(msg, new SampleContext, 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, void* callback, void* key); + void Push(IPC::SyncMessage* msg, SyncMessageCallContext* context, + void* key); void Cancel(void* key); protected: - 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; - }; + typedef std::deque<SyncMessageCallContext*> PendingSyncMessageQueue; - typedef std::deque<MessageSent> PendingSyncMessageQueue; + SyncMessageCallContext* GetContext(const IPC::Message& msg); - 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 @@ -70,21 +91,22 @@ 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, - const MessageSent& origin); + SyncMessageCallContext* context); template <typename T> - 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 + void InvokeCallback(const IPC::Message& msg, + SyncMessageCallContext* call_context) { + if (!call_context || !call_context->key_) { + NOTREACHED() << "Invalid context parameter"; return; } - T tmp; // Acts as "initializer" for output parameters. - IPC::ParamDeserializer<T> deserializer(tmp); + T* context = static_cast<T*>(call_context); + T::output_type tmp; // Acts as "initializer" for output parameters. + IPC::ParamDeserializer<T::output_type> deserializer(tmp); if (deserializer.MessageReplyDeserializer::SerializeOutputParameters(msg)) { - c->RunWithParams(deserializer.out_); + DispatchToMethod(context, &T::Completed, deserializer.out_); + delete context; } 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 d08d62d3..09b1484 100644 --- a/chrome_frame/test/automation_client_mock.h +++ b/chrome_frame/test/automation_client_mock.h @@ -90,8 +90,10 @@ struct MockCFDelegate : public ChromeFrameDelegateImpl { class MockAutomationProxy : public ChromeFrameAutomationProxy { public: MOCK_METHOD1(Send, bool(IPC::Message*)); - MOCK_METHOD3(SendAsAsync, void(IPC::SyncMessage* msg, void* callback, - void* key)); + MOCK_METHOD3(SendAsAsync, + void(IPC::SyncMessage* msg, + SyncMessageReplyDispatcher::SyncMessageCallContext* context, + void* key)); MOCK_METHOD1(CancelAsync, void(void* key)); MOCK_METHOD1(CreateTabProxy, scoped_refptr<TabProxy>(int handle)); MOCK_METHOD1(ReleaseTabProxy, void(AutomationHandle handle)); |