1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef CHROME_FRAME_CHROME_FRAME_DELEGATE_H_
6#define CHROME_FRAME_CHROME_FRAME_DELEGATE_H_
7
8#include <atlbase.h>
9#include <atlwin.h>
10#include <queue>
11#include <string>
12#include <vector>
13
14#include "base/callback.h"
15#include "base/files/file_path.h"
16#include "base/location.h"
17#include "base/pending_task.h"
18#include "base/synchronization/lock.h"
19#include "chrome/common/automation_constants.h"
20#include "ipc/ipc_message.h"
21
22class GURL;
23struct AttachExternalTabParams;
24struct AutomationURLRequest;
25struct ContextMenuModel;
26struct MiniContextMenuParams;
27struct NavigationInfo;
28
29namespace net {
30class URLRequestStatus;
31}
32
33namespace gfx {
34class Rect;
35}
36
37// A common interface supported by all the browser specific ChromeFrame
38// implementations.
39class ChromeFrameDelegate {
40 public:
41  typedef HWND WindowType;
42
43  virtual WindowType GetWindow() const = 0;
44  virtual void GetBounds(RECT* bounds) = 0;
45  virtual std::string GetDocumentUrl() = 0;
46  virtual void OnAutomationServerReady() = 0;
47  virtual void OnAutomationServerLaunchFailed(
48      AutomationLaunchResult reason, const std::string& server_version) = 0;
49  virtual bool OnMessageReceived(const IPC::Message& msg) = 0;
50  virtual void OnChannelError() = 0;
51
52  // This remains in interface since we call it if Navigate()
53  // returns immediate error.
54  virtual void OnLoadFailed(int error_code, const std::string& url) = 0;
55
56  // Returns true if this instance is alive and well for processing automation
57  // messages.
58  virtual bool IsValid() const = 0;
59
60  // To be called when the top-most window of an application hosting
61  // ChromeFrame is moved.
62  virtual void OnHostMoved() = 0;
63
64 protected:
65  virtual ~ChromeFrameDelegate() {}
66};
67
68extern UINT kAutomationServerReady;
69extern UINT kMessageFromChromeFrame;
70
71class ChromeFrameDelegateImpl : public ChromeFrameDelegate {
72 public:
73  virtual WindowType GetWindow() { return NULL; }
74  virtual void GetBounds(RECT* bounds) {}
75  virtual std::string GetDocumentUrl() { return std::string(); }
76  virtual void OnAutomationServerReady() {}
77  virtual void OnAutomationServerLaunchFailed(
78      AutomationLaunchResult reason, const std::string& server_version) {}
79  virtual void OnLoadFailed(int error_code, const std::string& url) {}
80  virtual bool OnMessageReceived(const IPC::Message& msg);
81  virtual void OnChannelError() {}
82
83  static bool IsTabMessage(const IPC::Message& message);
84
85  virtual bool IsValid() const {
86    return true;
87  }
88
89  virtual void OnHostMoved() {}
90
91 protected:
92  // Protected methods to be overridden.
93  virtual void OnNavigationStateChanged(
94      int flags, const NavigationInfo& nav_info) {}
95  virtual void OnUpdateTargetUrl(const std::wstring& new_target_url) {}
96  virtual void OnAcceleratorPressed(const MSG& accel_message) {}
97  virtual void OnTabbedOut(bool reverse) {}
98  virtual void OnOpenURL(
99      const GURL& url, const GURL& referrer, int open_disposition) {}
100  virtual void OnDidNavigate(const NavigationInfo& navigation_info) {}
101  virtual void OnNavigationFailed(int error_code, const GURL& gurl) {}
102  virtual void OnLoad(const GURL& url) {}
103  virtual void OnMoveWindow(const gfx::Rect& pos) {}
104  virtual void OnMessageFromChromeFrame(const std::string& message,
105                                        const std::string& origin,
106                                        const std::string& target) {}
107  virtual void OnHandleContextMenu(const ContextMenuModel& context_menu_model,
108                                   int align_flags,
109                                   const MiniContextMenuParams& params) {}
110  virtual void OnRequestStart(
111      int request_id, const AutomationURLRequest& request) {}
112  virtual void OnRequestRead(int request_id, int bytes_to_read) {}
113  virtual void OnRequestEnd(int request_id,
114                            const net::URLRequestStatus& status) {}
115  virtual void OnDownloadRequestInHost(int request_id) {}
116  virtual void OnAttachExternalTab(
117      const AttachExternalTabParams& attach_params) {}
118  virtual void OnGoToHistoryEntryOffset(int offset) {}
119  virtual void OnCloseTab() {}
120};
121
122// This interface enables tasks to be marshaled to desired threads.
123class TaskMarshaller {  // NOLINT
124 public:
125  virtual void PostTask(const tracked_objects::Location& from_here,
126                        const base::Closure& task) = 0;
127};
128
129// T is expected to be something CWindowImpl derived, or at least to have
130// PostMessage(UINT, WPARAM) method. Do not forget to CHAIN_MSG_MAP
131template <class T> class TaskMarshallerThroughWindowsMessages
132    : public TaskMarshaller {
133 public:
134  TaskMarshallerThroughWindowsMessages() {}
135  virtual void PostTask(const tracked_objects::Location& posted_from,
136                        const base::Closure& task) OVERRIDE {
137    T* this_ptr = static_cast<T*>(this);
138    if (this_ptr->IsWindow()) {
139      this_ptr->AddRef();
140      base::PendingTask* pending_task =
141          new base::PendingTask(posted_from, task);
142      PushTask(pending_task);
143      this_ptr->PostMessage(MSG_EXECUTE_TASK,
144                            reinterpret_cast<WPARAM>(pending_task));
145    } else {
146      DVLOG(1) << "Dropping MSG_EXECUTE_TASK message for destroyed window.";
147    }
148  }
149
150 protected:
151  ~TaskMarshallerThroughWindowsMessages() {
152    DeleteAllPendingTasks();
153  }
154
155  void DeleteAllPendingTasks() {
156    base::AutoLock lock(lock_);
157    DVLOG_IF(1, !pending_tasks_.empty()) << "Destroying "
158                                         << pending_tasks_.size()
159                                         << " pending tasks";
160    while (!pending_tasks_.empty()) {
161      base::PendingTask* task = pending_tasks_.front();
162      pending_tasks_.pop();
163      delete task;
164    }
165  }
166
167  BEGIN_MSG_MAP(PostMessageMarshaller)
168    MESSAGE_HANDLER(MSG_EXECUTE_TASK, ExecuteTask)
169  END_MSG_MAP()
170
171 private:
172  enum { MSG_EXECUTE_TASK = WM_APP + 6 };
173  inline LRESULT ExecuteTask(UINT, WPARAM wparam, LPARAM,
174                             BOOL& handled) {  // NOLINT
175    base::PendingTask* pending_task =
176        reinterpret_cast<base::PendingTask*>(wparam);
177    if (pending_task && PopTask(pending_task)) {
178      pending_task->task.Run();
179      delete pending_task;
180    }
181
182    T* this_ptr = static_cast<T*>(this);
183    this_ptr->Release();
184    return 0;
185  }
186
187  inline void PushTask(base::PendingTask* pending_task) {
188    base::AutoLock lock(lock_);
189    pending_tasks_.push(pending_task);
190  }
191
192  // If |pending_task| is front of the queue, removes the task and returns true,
193  // otherwise we assume this is an already destroyed task (but Window message
194  // had remained in the thread queue).
195  inline bool PopTask(base::PendingTask* pending_task) {
196    base::AutoLock lock(lock_);
197    if (!pending_tasks_.empty() && pending_task == pending_tasks_.front()) {
198      pending_tasks_.pop();
199      return true;
200    }
201
202    return false;
203  }
204
205  base::Lock lock_;
206  std::queue<base::PendingTask*> pending_tasks_;
207};
208
209#endif  // CHROME_FRAME_CHROME_FRAME_DELEGATE_H_
210