diff options
Diffstat (limited to 'chrome_frame/chrome_frame_automation.h')
-rw-r--r-- | chrome_frame/chrome_frame_automation.h | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h new file mode 100644 index 0000000..796facb --- /dev/null +++ b/chrome_frame/chrome_frame_automation.h @@ -0,0 +1,356 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_ +#define CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_ + +#include <atlbase.h> +#include <atlwin.h> +#include <string> +#include <map> + +#include "base/lock.h" +#include "base/ref_counted.h" +#include "base/scoped_handle.h" +#include "base/stack_container.h" +#include "base/task.h" +#include "base/timer.h" +#include "base/thread.h" +#include "chrome/test/automation/automation_proxy.h" +#include "chrome/test/automation/tab_proxy.h" +#include "chrome_frame/chrome_frame_delegate.h" +#include "chrome_frame/chrome_frame_histograms.h" +#include "chrome_frame/plugin_url_request.h" + +const unsigned long kCommandExecutionTimeout = 4000; // NOLINT, 4 seconds + +class ProxyFactory; + +struct DECLSPEC_NOVTABLE ChromeFrameAutomationProxy { + virtual bool Send(IPC::Message* msg) = 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 std::string server_version() = 0; + + virtual void SendProxyConfig(const std::string&) = 0; + virtual void SetEnableExtensionAutomation(bool enable) = 0; + protected: + ~ChromeFrameAutomationProxy() {} +}; + +// We extend the AutomationProxy class to handle our custom +// IPC messages +class ChromeFrameAutomationProxyImpl : public ChromeFrameAutomationProxy, + // We have to derive from automationproxy since we want access to some members + // (tracker_ & channel_) - simple aggregation wont work; + // .. and non-public inheritance is verboten. + public AutomationProxy { + public: + virtual void SendAsAsync(IPC::SyncMessage* msg, void* callback, void* key); + + virtual void CancelAsync(void* key); + + virtual scoped_refptr<TabProxy> CreateTabProxy(int handle); + virtual std::string server_version() { + return AutomationProxy::server_version(); + } + + + virtual bool Send(IPC::Message* msg) { + return AutomationProxy::Send(msg); + } + + virtual void SendProxyConfig(const std::string& p) { + AutomationProxy::SendProxyConfig(p); + } + + virtual void SetEnableExtensionAutomation(bool e) { + AutomationProxy::SetEnableExtensionAutomation(e); + } + + protected: + explicit ChromeFrameAutomationProxyImpl(int launch_timeout); + ~ChromeFrameAutomationProxyImpl(); + class CFMsgDispatcher; + scoped_refptr<CFMsgDispatcher> sync_; + friend class ProxyFactory; +}; + +// We must create and destroy automation proxy in a thread with a message loop. +// Hence thread cannot be a member of the proxy. +class ProxyFactory { + public: + // Callback when chrome process launch is complete and automation handshake + // (Hello message) is established. + struct DECLSPEC_NOVTABLE LaunchDelegate { + virtual void LaunchComplete(ChromeFrameAutomationProxy* proxy, + AutomationLaunchResult result) = 0; + }; + + ProxyFactory(); + ~ProxyFactory(); + // FIXME: we should pass the result as output parameter, not as return value + // since, LaunchDelegate can be invoked before this function returns. + virtual void* GetAutomationServer(int launch_timeout, + const std::wstring& profile_name, + // Extra command line argument when launching Chrome + const std::wstring& extra_argument, + bool perform_version_check, + LaunchDelegate* delegate); + virtual bool ReleaseAutomationServer(void* server_id); + + private: + struct ProxyCacheEntry { + std::wstring profile_name; + int ref_count; + scoped_ptr<base::Thread> thread; + ChromeFrameAutomationProxyImpl* proxy; + AutomationLaunchResult launch_result; + explicit ProxyCacheEntry(const std::wstring& profile); + }; + + void CreateProxy(ProxyCacheEntry* entry, + int launch_timeout, + const std::wstring& extra_chrome_arguments, + bool perform_version_check, + LaunchDelegate* delegate); + void DestroyProxy(ProxyCacheEntry* entry); + + void SendUMAData(ProxyCacheEntry* proxy_entry); + + typedef StackVector<ProxyCacheEntry*, 4> Vector; + Vector proxies_; + // Lock if we are going to call GetAutomationServer from more than one thread. + Lock lock_; + + // Used for UMA histogram logging to measure the time for the chrome + // automation server to start; + base::TimeTicks automation_server_launch_start_time_; + + // Gathers histograms to be sent to Chrome. + ChromeFrameHistogramSnapshots chrome_frame_histograms_; + + // Interval for sending UMA data + int uma_send_interval_; +}; + +// T is expected to be something CWindowImpl derived, or at least to have +// PostMessage(UINT, WPARAM) method. Do not forget to CHAIN_MSG_MAP +template <class T> class TaskMarshallerThroughWindowsMessages { + public: + void PostTask(const tracked_objects::Location& from_here, Task* task) { + task->SetBirthPlace(from_here); + T* this_ptr = static_cast<T*>(this); + if (this_ptr->IsWindow()) { + this_ptr->PostMessage(MSG_EXECUTE_TASK, reinterpret_cast<WPARAM>(task)); + } else { + DLOG(INFO) << "Dropping MSG_EXECUTE_TASK message for destroyed window."; + } + } + + BEGIN_MSG_MAP(PostMessageMarshaller) + MESSAGE_HANDLER(MSG_EXECUTE_TASK, ExecuteTask) + END_MSG_MAP() + + private: + enum { MSG_EXECUTE_TASK = WM_APP + 6 }; + inline LRESULT ExecuteTask(UINT, WPARAM wparam, LPARAM, + BOOL& handled) { // NOLINT + Task* task = reinterpret_cast<Task*>(wparam); + task->Run(); + delete task; + return 0; + } +}; + +// Handles all automation requests initiated from the chrome frame objects. +// These include the chrome tab/chrome frame activex/chrome frame npapi +// plugin objects. +class ChromeFrameAutomationClient + : public CWindowImpl<ChromeFrameAutomationClient>, + public TaskMarshallerThroughWindowsMessages<ChromeFrameAutomationClient>, + public PluginRequestHandler, + public TabProxy::TabProxyDelegate, + public ProxyFactory::LaunchDelegate { + public: + ChromeFrameAutomationClient(); + ~ChromeFrameAutomationClient(); + + // Called from UI thread. + virtual bool Initialize(ChromeFrameDelegate* chrome_frame_delegate, + int automation_server_launch_timeout, + bool perform_version_check, + const std::wstring& profile_name, + const std::wstring& extra_chrome_arguments, + bool incognito); + void Uninitialize(); + + virtual bool InitiateNavigation(const std::string& url); + virtual bool NavigateToIndex(int index); + bool ForwardMessageFromExternalHost(const std::string& message, + const std::string& origin, + const std::string& target); + bool SetProxySettings(const std::string& json_encoded_proxy_settings); + + virtual void SetEnableExtensionAutomation(bool enable_automation); + + void FindInPage(const std::wstring& search_string, + FindInPageDirection forward, + FindInPageCase match_case, + bool find_next); + + TabProxy* tab() const { return tab_.get(); } + + BEGIN_MSG_MAP(ChromeFrameAutomationClient) + CHAIN_MSG_MAP( + TaskMarshallerThroughWindowsMessages<ChromeFrameAutomationClient>) + END_MSG_MAP() + + void set_delegate(ChromeFrameDelegate* d) { + chrome_frame_delegate_ = d; + } + + // Resizes the hosted chrome window. This is brokered to the chrome + // automation instance as the host browser could be running under low IL, + // which would cause the SetWindowPos call to fail. + void Resize(int width, int height, int flags); + + // Sets the passed in window as the parent of the external tab. + void SetParentWindow(HWND parent_window); + + void SendContextMenuCommandToChromeFrame(int selected_command); + + HWND tab_window() const { + return tab_window_; + } + + void ReleaseAutomationServer(); + + // Returns the version number of plugin dll. + std::wstring GetVersion() const; + + // BitBlts the contents of the chrome window to the print dc. + void Print(HDC print_dc, const RECT& print_bounds); + + // Called in full tab mode and indicates a request to chrome to print + // the whole tab. + void PrintTab(); + + // PluginRequestHandler + bool AddRequest(PluginUrlRequest* request); + void RemoveRequest(PluginUrlRequest* request); + virtual bool Send(IPC::Message* msg); + + // URL request related + bool ReadRequest(int request_id, int bytes_to_read); + void RemoveRequest(int request_id, int reason, bool abort); + PluginUrlRequest* LookupRequest(int request_id) const; + bool IsValidRequest(PluginUrlRequest* request) const; + void CleanupRequests(); + + void set_use_chrome_network(bool use_chrome_network) { + use_chrome_network_ = use_chrome_network; + } + bool use_chrome_network() const { + return use_chrome_network_; + } + +#ifdef UNIT_TEST + void set_proxy_factory(ProxyFactory* factory) { + proxy_factory_ = factory; + } +#endif + + void set_handle_top_level_requests(bool handle_top_level_requests) { + handle_top_level_requests_ = handle_top_level_requests; + } + + // Called if the same instance of the ChromeFrameAutomationClient object + // is reused. + bool Reinitialize(ChromeFrameDelegate* chrome_frame_delegate); + + // Attaches an existing external tab to this automation client instance. + void AttachExternalTab(intptr_t external_tab_cookie); + + protected: + // ChromeFrameAutomationProxy::LaunchDelegate implementation. + virtual void LaunchComplete(ChromeFrameAutomationProxy* proxy, + AutomationLaunchResult result); + // TabProxyDelegate implementation + virtual void OnMessageReceived(TabProxy* tab, const IPC::Message& msg); + + void CreateExternalTab(); + void CreateExternalTabComplete(HWND chrome_window, HWND tab_window, + int tab_handle); + // Called in UI thread. Here we fire event to the client notifying for + // the result of Initialize() method call. + void InitializeComplete(AutomationLaunchResult result); + + private: + typedef std::map<int, scoped_refptr<PluginUrlRequest> > RequestMap; + + // Usage: From bkgnd thread invoke: + // CallDelegate(FROM_HERE, NewRunnableMethod(chrome_frame_delegate_, + // ChromeFrameDelegate::Something, + // param1, + // param2)); + void CallDelegate(const tracked_objects::Location& from_here, + Task* delegate_task); + // The workhorse method called in main/GUI thread which is going to + // execute ChromeFrameDelegate method encapsulated in delegate_task. + void CallDelegateImpl(Task* delegate_task); + + HWND chrome_window() const { return chrome_window_; } + void BeginNavigate(const GURL& url); + void BeginNavigateCompleted(AutomationMsg_NavigationResponseValues result); + + // Helpers + void ReportNavigationError(AutomationMsg_NavigationResponseValues error_code, + const std::string& url); + + bool is_initialized() const { + return init_state_ == INITIALIZED; + } + + bool incognito_; + HWND parent_window_; + PlatformThreadId ui_thread_id_; + + void* automation_server_id_; + ChromeFrameAutomationProxy* automation_server_; + HWND chrome_window_; + scoped_refptr<TabProxy> tab_; + ChromeFrameDelegate* chrome_frame_delegate_; + GURL url_; + + // Handle to the underlying chrome window. This is a child of the external + // tab window. + HWND tab_window_; + + // Keeps track of the version of Chrome we're talking to. + std::string automation_server_version_; + + // Map of outstanding requests + RequestMap request_map_; + + typedef enum InitializationState { + UNINITIALIZED = 0, + INITIALIZING, + INITIALIZED, + UNINITIALIZING, + }; + + InitializationState init_state_; + bool use_chrome_network_; + bool handle_top_level_requests_; + ProxyFactory* proxy_factory_; + int tab_handle_; + // Only used if we attach to an existing tab. + intptr_t external_tab_cookie_; +}; + +#endif // CHROME_FRAME_CHROME_FRAME_AUTOMATION_H_ |