• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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_PLUGIN_H_
6 #define CHROME_FRAME_CHROME_FRAME_PLUGIN_H_
7 
8 #include <string>
9 #include <vector>
10 
11 #include "base/memory/ref_counted.h"
12 #include "base/win/win_util.h"
13 #include "chrome_frame/chrome_frame_automation.h"
14 #include "chrome/common/chrome_paths.h"
15 #include "chrome/common/chrome_paths_internal.h"
16 #include "chrome_frame/simple_resource_loader.h"
17 #include "chrome_frame/navigation_constraints.h"
18 #include "chrome_frame/utils.h"
19 #include "grit/chromium_strings.h"
20 
21 #define IDC_ABOUT_CHROME_FRAME 40018
22 
23 // Helper so that this file doesn't include the messages header.
24 void ChromeFramePluginGetParamsCoordinates(
25     const MiniContextMenuParams& params,
26     int* x,
27     int* y);
28 
29 // A class to implement common functionality for all types of
30 // plugins: ActiveX and ActiveDoc
31 template <typename T>
32 class ChromeFramePlugin
33     : public ChromeFrameDelegateImpl,
34       public NavigationConstraintsImpl  {
35  public:
ChromeFramePlugin()36   ChromeFramePlugin() : ignore_setfocus_(false){
37   }
~ChromeFramePlugin()38   ~ChromeFramePlugin() {
39     Uninitialize();
40   }
41 
42 BEGIN_MSG_MAP(T)
MESSAGE_HANDLER(WM_SETFOCUS,OnSetFocus)43   MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
44   MESSAGE_HANDLER(WM_SIZE, OnSize)
45   MESSAGE_HANDLER(WM_PARENTNOTIFY, OnParentNotify)
46 END_MSG_MAP()
47 
48   bool Initialize() {
49     DVLOG(1) << __FUNCTION__;
50     DCHECK(!automation_client_.get());
51     automation_client_ = CreateAutomationClient();
52     if (!automation_client_.get()) {
53       NOTREACHED() << "new ChromeFrameAutomationClient";
54       return false;
55     }
56 
57     return true;
58   }
59 
Uninitialize()60   void Uninitialize() {
61     DVLOG(1) << __FUNCTION__;
62     if (IsValid()) {
63       automation_client_->Uninitialize();
64       automation_client_ = NULL;
65     }
66   }
67 
InitializeAutomation(const std::wstring & profile_name,bool incognito,bool is_widget_mode,const GURL & url,const GURL & referrer,bool route_all_top_level_navigations)68   bool InitializeAutomation(const std::wstring& profile_name,
69                             bool incognito, bool is_widget_mode,
70                             const GURL& url, const GURL& referrer,
71                             bool route_all_top_level_navigations) {
72     DCHECK(IsValid());
73     DCHECK(launch_params_ == NULL);
74     // We don't want to do incognito when privileged, since we're
75     // running in browser chrome or some other privileged context.
76     bool incognito_mode = !is_privileged() && incognito;
77     base::FilePath profile_path;
78     GetProfilePath(profile_name, &profile_path);
79     // The profile name could change based on the browser version. For e.g. for
80     // IE6/7 the profile is created in a different folder whose last component
81     // is Google Chrome Frame.
82     base::FilePath actual_profile_name = profile_path.BaseName();
83     launch_params_ = new ChromeFrameLaunchParams(url, referrer, profile_path,
84         actual_profile_name.value(), SimpleResourceLoader::GetLanguage(),
85         incognito_mode, is_widget_mode, route_all_top_level_navigations);
86     return automation_client_->Initialize(this, launch_params_);
87   }
88 
89   // ChromeFrameDelegate implementation
GetWindow()90   virtual WindowType GetWindow() const {
91     return (static_cast<const T*>(this))->m_hWnd;
92   }
93 
GetBounds(RECT * bounds)94   virtual void GetBounds(RECT* bounds) {
95     if (bounds) {
96       if (::IsWindow(GetWindow())) {
97         (static_cast<T*>(this))->GetClientRect(bounds);
98       }
99     }
100   }
GetDocumentUrl()101   virtual std::string GetDocumentUrl() {
102     return document_url_;
103   }
OnAutomationServerReady()104   virtual void OnAutomationServerReady() {
105   }
106 
IsValid()107   virtual bool IsValid() const {
108     return automation_client_.get() != NULL;
109   }
110 
OnHostMoved()111   virtual void OnHostMoved() {
112     if (IsValid())
113       automation_client_->OnChromeFrameHostMoved();
114   }
115 
116  protected:
OnNavigationFailed(int error_code,const GURL & gurl)117   virtual void OnNavigationFailed(int error_code, const GURL& gurl) {
118     OnLoadFailed(error_code, gurl.spec());
119   }
120 
OnHandleContextMenu(const ContextMenuModel & menu_model,int align_flags,const MiniContextMenuParams & params)121   virtual void OnHandleContextMenu(const ContextMenuModel& menu_model,
122                                    int align_flags,
123                                    const MiniContextMenuParams& params) {
124     if (!automation_client_.get()) {
125       NOTREACHED();
126       return;
127     }
128 
129     HMENU menu = BuildContextMenu(menu_model);
130     if (!menu)
131       return;
132 
133     T* self = static_cast<T*>(this);
134     if (self->PreProcessContextMenu(menu)) {
135       // In order for the context menu to handle keyboard input, give the
136       // ActiveX window focus.
137       ignore_setfocus_ = true;
138       SetFocus(GetWindow());
139       ignore_setfocus_ = false;
140       UINT flags = align_flags | TPM_LEFTBUTTON | TPM_RETURNCMD | TPM_RECURSE;
141       int x, y;
142       ChromeFramePluginGetParamsCoordinates(params, &x, &y);
143       UINT selected = TrackPopupMenuEx(menu, flags, x, y, GetWindow(), NULL);
144       // Menu is over now give focus back to chrome
145       GiveFocusToChrome(false);
146       if (IsValid() && selected != 0 &&
147           !self->HandleContextMenuCommand(selected, params)) {
148         automation_client_->SendContextMenuCommandToChromeFrame(selected);
149       }
150     }
151 
152     DestroyMenu(menu);
153   }
154 
OnSetFocus(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)155   LRESULT OnSetFocus(UINT message, WPARAM wparam, LPARAM lparam,
156                      BOOL& handled) {  // NO_LINT
157     if (!ignore_setfocus_ && IsValid()) {
158       // Pass false to |restore_focus_view|, because we do not want Chrome
159       // to focus the first focusable element in the current view, only the
160       // view itself.
161       GiveFocusToChrome(false);
162     }
163     return 0;
164   }
165 
OnSize(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)166   LRESULT OnSize(UINT message, WPARAM wparam, LPARAM lparam,
167                  BOOL& handled) {  // NO_LINT
168     handled = FALSE;
169     // When we get resized, we need to resize the external tab window too.
170     if (IsValid())
171       automation_client_->Resize(LOWORD(lparam), HIWORD(lparam),
172                                  SWP_NOACTIVATE | SWP_NOZORDER);
173     return 0;
174   }
175 
OnParentNotify(UINT message,WPARAM wparam,LPARAM lparam,BOOL & handled)176   LRESULT OnParentNotify(UINT message, WPARAM wparam, LPARAM lparam,
177                          BOOL& handled) {  // NO_LINT
178     switch (LOWORD(wparam)) {
179       case WM_LBUTTONDOWN:
180       case WM_MBUTTONDOWN:
181       case WM_RBUTTONDOWN:
182       case WM_XBUTTONDOWN: {
183         // If we got activated via mouse click on the external tab,
184         // we need to update the state of this thread and tell the
185         // browser that we now have the focus.
186         HWND focus = ::GetFocus();
187         HWND plugin_window = GetWindow();
188 
189         // The Chrome-Frame instance may have launched a popup which currently
190         // has focus.  Because experimental extension popups are top-level
191         // windows, we have to check that the focus has shifted to a window
192         // that does not share the same GA_ROOTOWNER as the plugin.
193         if (focus != plugin_window &&
194             ::GetAncestor(plugin_window, GA_ROOTOWNER) !=
195                 ::GetAncestor(focus, GA_ROOTOWNER)) {
196           ignore_setfocus_ = true;
197           SetFocus(plugin_window);
198           ignore_setfocus_ = false;
199         }
200         break;
201       }
202     }
203 
204     return 0;
205   }
206 
207   // Return true if context menu should be displayed. The menu could be
208   // modified as well (enable/disable commands, add/remove items).
209   // Override in most-derived class if needed.
PreProcessContextMenu(HMENU menu)210   bool PreProcessContextMenu(HMENU menu) {
211     // Add an "About" item.
212     AppendMenu(menu, MF_STRING, IDC_ABOUT_CHROME_FRAME,
213                SimpleResourceLoader::Get(IDS_CHROME_FRAME_MENU_ABOUT).c_str());
214     return true;
215   }
216 
217   // Return true if menu command is processed, otherwise the command will be
218   // passed to Chrome for execution. Override in most-derived class if needed.
HandleContextMenuCommand(UINT cmd,const MiniContextMenuParams & params)219   bool HandleContextMenuCommand(UINT cmd,
220                                 const MiniContextMenuParams& params) {
221     return false;
222   }
223 
224   // Allow overriding the type of automation client used, for unit tests.
CreateAutomationClient()225   virtual ChromeFrameAutomationClient* CreateAutomationClient() {
226     return new ChromeFrameAutomationClient;
227   }
228 
GiveFocusToChrome(bool restore_focus_to_view)229   void GiveFocusToChrome(bool restore_focus_to_view) {
230     if (IsValid()) {
231       TabProxy* tab = automation_client_->tab();
232       HWND chrome_window = automation_client_->tab_window();
233       if (tab && ::IsWindow(chrome_window)) {
234         DVLOG(1) << "Setting initial focus";
235         tab->SetInitialFocus(base::win::IsShiftPressed(), restore_focus_to_view);
236       }
237     }
238   }
239 
GetProfilePath(const std::wstring & profile_name,base::FilePath * profile_path)240   virtual void GetProfilePath(const std::wstring& profile_name,
241                               base::FilePath* profile_path) {
242     return GetChromeFrameProfilePath(profile_name, profile_path);
243   }
244 
245  protected:
246   // Our gateway to chrome land
247   scoped_refptr<ChromeFrameAutomationClient> automation_client_;
248 
249   // How we launched Chrome.
250   scoped_refptr<ChromeFrameLaunchParams> launch_params_;
251 
252   // Url of the containing document.
253   std::string document_url_;
254 
255   // We set this flag when we're taking the focus ourselves
256   // and notifying the host browser that we're doing so.
257   // When the flag is not set, we transfer the focus to chrome.
258   bool ignore_setfocus_;
259 };
260 
261 #endif  // CHROME_FRAME_CHROME_FRAME_PLUGIN_H_
262