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_BROWSER_EXTERNAL_TAB_CONTAINER_WIN_H_
6#define CHROME_BROWSER_EXTERNAL_TAB_CONTAINER_WIN_H_
7#pragma once
8
9#include <map>
10#include <string>
11#include <vector>
12
13#include "base/lazy_instance.h"
14#include "base/memory/scoped_ptr.h"
15#include "chrome/browser/automation/automation_resource_message_filter.h"
16#include "chrome/browser/net/chrome_url_request_context.h"
17#include "chrome/browser/ui/views/frame/browser_bubble_host.h"
18#include "chrome/browser/ui/views/infobars/infobar_container.h"
19#include "chrome/browser/ui/views/unhandled_keyboard_event_handler.h"
20#include "content/browser/tab_contents/tab_contents_delegate.h"
21#include "content/common/navigation_types.h"
22#include "content/common/notification_observer.h"
23#include "content/common/notification_registrar.h"
24#include "views/accelerator.h"
25#include "views/widget/widget_win.h"
26
27class AutomationProvider;
28class Browser;
29class Profile;
30class TabContentsContainer;
31class TabContentsWrapper;
32class RenderViewContextMenuViews;
33struct NavigationInfo;
34
35namespace ui {
36class ViewProp;
37}
38
39// This class serves as the container window for an external tab.
40// An external tab is a Chrome tab that is meant to displayed in an
41// external process. This class provides the FocusManger needed by the
42// TabContents as well as an implementation of TabContentsDelegate.
43class ExternalTabContainer : public TabContentsDelegate,
44                             public NotificationObserver,
45                             public views::WidgetWin,
46                             public base::RefCounted<ExternalTabContainer>,
47                             public views::AcceleratorTarget,
48                             public InfoBarContainer::Delegate,
49                             public BrowserBubbleHost {
50 public:
51  typedef std::map<uintptr_t, scoped_refptr<ExternalTabContainer> > PendingTabs;
52
53  ExternalTabContainer(AutomationProvider* automation,
54      AutomationResourceMessageFilter* filter);
55
56  TabContents* tab_contents() const;
57
58  // Temporary hack so we can send notifications back
59  void SetTabHandle(int handle);
60
61  int tab_handle() const {
62    return tab_handle_;
63  }
64
65  bool Init(Profile* profile,
66            HWND parent,
67            const gfx::Rect& bounds,
68            DWORD style,
69            bool load_requests_via_automation,
70            bool handle_top_level_requests,
71            TabContentsWrapper* existing_tab_contents,
72            const GURL& initial_url,
73            const GURL& referrer,
74            bool infobars_enabled,
75            bool supports_full_tab_mode);
76
77  // Unhook the keystroke listener and notify about the closing TabContents.
78  // This function gets called from three places, which is fine.
79  // 1. OnFinalMessage
80  // 2. In the destructor.
81  // 3. In AutomationProvider::CreateExternalTab
82  void Uninitialize();
83
84  // Used to reinitialize the automation channel and related information
85  // for this container. Typically used when an ExternalTabContainer
86  // instance is created by Chrome and attached to an automation client.
87  bool Reinitialize(AutomationProvider* automation_provider,
88                    AutomationResourceMessageFilter* filter,
89                    gfx::NativeWindow parent_window);
90
91  // This is invoked when the external host reflects back to us a keyboard
92  // message it did not process
93  void ProcessUnhandledAccelerator(const MSG& msg);
94
95  // See TabContents::FocusThroughTabTraversal.  Called from AutomationProvider.
96  void FocusThroughTabTraversal(bool reverse, bool restore_focus_to_view);
97
98  // A helper method that tests whether the given window is an
99  // ExternalTabContainer window
100  static bool IsExternalTabContainer(HWND window);
101
102  // A helper function that returns a pointer to the ExternalTabContainer
103  // instance associated with a native view.  Returns NULL if the window
104  // is not an ExternalTabContainer.
105  static ExternalTabContainer* GetExternalContainerFromNativeWindow(
106      gfx::NativeView native_window);
107
108  // A helper method that retrieves the ExternalTabContainer object that
109  // hosts the given tab window.
110  static ExternalTabContainer* GetContainerForTab(HWND tab_window);
111
112  // Overridden from TabContentsDelegate:
113  virtual void OpenURLFromTab(TabContents* source,
114                              const GURL& url,
115                              const GURL& referrer,
116                              WindowOpenDisposition disposition,
117                              PageTransition::Type transition);
118  virtual void NavigationStateChanged(const TabContents* source,
119                                      unsigned changed_flags);
120  virtual void AddNewContents(TabContents* source,
121                              TabContents* new_contents,
122                              WindowOpenDisposition disposition,
123                              const gfx::Rect& initial_pos,
124                              bool user_gesture);
125  virtual void ActivateContents(TabContents* contents);
126  virtual void DeactivateContents(TabContents* contents);
127  virtual void LoadingStateChanged(TabContents* source);
128  virtual void CloseContents(TabContents* source);
129  virtual void MoveContents(TabContents* source, const gfx::Rect& pos);
130  virtual bool IsPopup(const TabContents* source) const;
131  virtual void UpdateTargetURL(TabContents* source, const GURL& url);
132  virtual void ContentsZoomChange(bool zoom_in);
133  virtual void ForwardMessageToExternalHost(const std::string& message,
134                                            const std::string& origin,
135                                            const std::string& target);
136  virtual bool IsExternalTabContainer() const;
137  virtual gfx::NativeWindow GetFrameNativeWindow();
138
139  virtual bool PreHandleKeyboardEvent(const NativeWebKeyboardEvent& event,
140                                      bool* is_keyboard_shortcut);
141  virtual void HandleKeyboardEvent(const NativeWebKeyboardEvent& event);
142
143  virtual bool TakeFocus(bool reverse);
144
145  virtual bool CanDownload(int request_id);
146
147  virtual bool OnGoToEntryOffset(int offset);
148
149  virtual void ShowPageInfo(Profile* profile,
150                            const GURL& url,
151                            const NavigationEntry::SSLStatus& ssl,
152                            bool show_history);
153
154  // Handles the context menu display operation. This allows external
155  // hosts to customize the menu.
156  virtual bool HandleContextMenu(const ContextMenuParams& params);
157
158  // Executes the context menu command identified by the command
159  // parameter.
160  virtual bool ExecuteContextMenuCommand(int command);
161
162  // Show a dialog with HTML content. |delegate| contains a pointer to the
163  // delegate who knows how to display the dialog (which file URL and JSON
164  // string input to use during initialization). |parent_window| is the window
165  // that should be parent of the dialog, or NULL for the default.
166  virtual void ShowHtmlDialog(HtmlDialogUIDelegate* delegate,
167                              gfx::NativeWindow parent_window);
168
169  virtual void BeforeUnloadFired(TabContents* tab,
170                                 bool proceed,
171                                 bool* proceed_to_fire_unload);
172
173  void ShowRepostFormWarningDialog(TabContents* tab_contents);
174
175  // Overriden from TabContentsDelegate::AutomationResourceRoutingDelegate
176  virtual void RegisterRenderViewHost(RenderViewHost* render_view_host);
177  virtual void UnregisterRenderViewHost(RenderViewHost* render_view_host);
178
179  // Overridden from NotificationObserver:
180  virtual void Observe(NotificationType type,
181                       const NotificationSource& source,
182                       const NotificationDetails& details);
183
184  // Returns the ExternalTabContainer instance associated with the cookie
185  // passed in. It also erases the corresponding reference from the map.
186  // Returns NULL if we fail to find the cookie in the map.
187  static scoped_refptr<ExternalTabContainer> RemovePendingTab(uintptr_t cookie);
188
189  // Overridden from views::WidgetWin:
190  virtual views::Window* GetWindow();
191
192  // Handles the specified |accelerator| being pressed.
193  bool AcceleratorPressed(const views::Accelerator& accelerator);
194
195  bool pending() const {
196    return pending_;
197  }
198
199  void set_pending(bool pending) {
200    pending_ = pending;
201  }
202
203  void set_is_popup_window(bool is_popup_window) {
204    is_popup_window_ = is_popup_window;
205  }
206
207  // InfoBarContainer::Delegate overrides
208  virtual SkColor GetInfoBarSeparatorColor() const OVERRIDE;
209  virtual void InfoBarContainerStateChanged(bool is_animating) OVERRIDE;
210  virtual bool DrawInfoBarArrows(int* x) const OVERRIDE;
211
212  virtual void TabContentsCreated(TabContents* new_contents);
213
214  virtual bool infobars_enabled();
215
216  void RunUnloadHandlers(IPC::Message* reply_message);
217
218 protected:
219  ~ExternalTabContainer();
220  // Overridden from views::WidgetWin:
221  virtual LRESULT OnCreate(LPCREATESTRUCT create_struct);
222  virtual void OnDestroy();
223  virtual void OnFinalMessage(HWND window);
224
225  bool InitNavigationInfo(NavigationInfo* nav_info,
226                          NavigationType::Type nav_type,
227                          int relative_offset);
228  void Navigate(const GURL& url, const GURL& referrer);
229
230  friend class base::RefCounted<ExternalTabContainer>;
231
232  // Helper resource automation registration method, allowing registration of
233  // pending RenderViewHosts.
234  void RegisterRenderViewHostForAutomation(RenderViewHost* render_view_host,
235                                           bool pending_view);
236
237  // Top level navigations received for a tab while it is waiting for an ack
238  // from the external host go here. Scenario is a window.open executes on a
239  // page in ChromeFrame. A new TabContents is created and the current
240  // ExternalTabContainer is notified via AddNewContents. At this point we
241  // send off an attach tab request to the host browser. Before the host
242  // browser sends over the ack, we receive a top level URL navigation for the
243  // new tab, which needs to be routed over the correct automation channel.
244  // We receive the automation channel only when the external host acks the
245  // attach tab request.
246  struct PendingTopLevelNavigation {
247    GURL url;
248    GURL referrer;
249    WindowOpenDisposition disposition;
250    PageTransition::Type transition;
251  };
252
253  // Helper function for processing keystokes coming back from the renderer
254  // process.
255  bool ProcessUnhandledKeyStroke(HWND window, UINT message, WPARAM wparam,
256                                 LPARAM lparam);
257
258  void LoadAccelerators();
259
260  // Sends over pending Open URL requests to the external host.
261  void ServicePendingOpenURLRequests();
262
263  // Scheduled as a task in ExternalTabContainer::Reinitialize
264  void OnReinitialize();
265
266  // Creates and initializes the view hierarchy for this ExternalTabContainer.
267  void SetupExternalTabView();
268
269  scoped_ptr<TabContentsWrapper> tab_contents_;
270  scoped_refptr<AutomationProvider> automation_;
271
272  NotificationRegistrar registrar_;
273
274  // A view to handle focus cycling
275  TabContentsContainer* tab_contents_container_;
276
277  int tab_handle_;
278  // A failed navigation like a 404 is followed in chrome with a success
279  // navigation for the 404 page. We need to ignore the next navigation
280  // to avoid confusing the clients of the external tab. This member variable
281  // is set when we need to ignore the next load notification.
282  bool ignore_next_load_notification_;
283
284  scoped_ptr<RenderViewContextMenuViews> external_context_menu_;
285
286  // A message filter to load resources via automation
287  scoped_refptr<AutomationResourceMessageFilter>
288      automation_resource_message_filter_;
289
290  // If all the url requests for this tab are to be loaded via automation.
291  bool load_requests_via_automation_;
292
293  // whether top level URL requests are to be handled by the automation client.
294  bool handle_top_level_requests_;
295
296  // Scoped browser object for this ExternalTabContainer instance.
297  scoped_ptr<Browser> browser_;
298
299  // Contains ExternalTabContainers that have not been connected to as yet.
300  static base::LazyInstance<PendingTabs> pending_tabs_;
301
302  // Allows us to run tasks on the ExternalTabContainer instance which are
303  // bound by its lifetime.
304  ScopedRunnableMethodFactory<ExternalTabContainer> external_method_factory_;
305
306  // The URL request context to be used for this tab. Can be NULL.
307  scoped_refptr<ChromeURLRequestContextGetter> request_context_;
308
309  UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
310
311  // A mapping between accelerators and commands.
312  std::map<views::Accelerator, int> accelerator_table_;
313
314  // Contains the list of URL requests which are pending waiting for an ack
315  // from the external host.
316  std::vector<PendingTopLevelNavigation> pending_open_url_requests_;
317
318  // Set to true if the ExternalTabContainer instance is waiting for an ack
319  // from the host.
320  bool pending_;
321
322  // Set to true if the ExternalTabContainer if infobars should be enabled.
323  bool infobars_enabled_;
324
325  views::FocusManager* focus_manager_;
326
327  views::View* external_tab_view_;
328
329  IPC::Message* unload_reply_message_;
330
331  // set to true if the host needs to get notified of all top level navigations
332  // in this page. This typically applies to hosts which would render the new
333  // page without chrome frame.
334  bool route_all_top_level_navigations_;
335
336  scoped_ptr<ui::ViewProp> prop_;
337
338  // if this tab is a popup
339  bool is_popup_window_;
340
341  DISALLOW_COPY_AND_ASSIGN(ExternalTabContainer);
342};
343
344// This class is instantiated for handling requests to open popups for external
345// tabs hosted in browsers which need to be notified about all top level
346// navigations. An instance of this class is created for handling window.open
347// or link navigations with target blank, etc.
348class TemporaryPopupExternalTabContainer : public ExternalTabContainer {
349 public:
350  TemporaryPopupExternalTabContainer(AutomationProvider* automation,
351      AutomationResourceMessageFilter* filter);
352  virtual ~TemporaryPopupExternalTabContainer();
353
354  virtual bool OnGoToEntryOffset(int offset) {
355    NOTREACHED();
356    return false;
357  }
358
359  virtual bool ProcessUnhandledKeyStroke(HWND window, UINT message,
360                                         WPARAM wparam, LPARAM lparam) {
361    NOTREACHED();
362    return false;
363  }
364
365  virtual void Observe(NotificationType type, const NotificationSource& source,
366                       const NotificationDetails& details) {}
367
368  virtual void OpenURLFromTab(TabContents* source, const GURL& url,
369                              const GURL& referrer,
370                              WindowOpenDisposition disposition,
371                              PageTransition::Type transition);
372
373  virtual void NavigationStateChanged(const TabContents* source,
374                                      unsigned changed_flags) {
375    NOTREACHED();
376  }
377
378  virtual void CloseContents(TabContents* source) {
379    NOTREACHED();
380  }
381
382  virtual void UpdateTargetURL(TabContents* source, const GURL& url) {
383    NOTREACHED();
384  }
385
386  void ForwardMessageToExternalHost(const std::string& message,
387                                    const std::string& origin,
388                                    const std::string& target) {
389    NOTREACHED();
390  }
391
392  virtual bool TakeFocus(bool reverse) {
393    NOTREACHED();
394    return false;
395  }
396
397  virtual bool HandleContextMenu(const ContextMenuParams& params) {
398    NOTREACHED();
399    return false;
400  }
401
402  virtual void BeforeUnloadFired(TabContents* tab, bool proceed,
403                                 bool* proceed_to_fire_unload) {
404    NOTREACHED();
405  }
406};
407
408#endif  // CHROME_BROWSER_EXTERNAL_TAB_CONTAINER_WIN_H_
409