Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / devtools / devtools_window.h
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_BROWSER_DEVTOOLS_DEVTOOLS_WINDOW_H_
6 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_WINDOW_H_
7
8 #include "chrome/browser/devtools/devtools_contents_resizing_strategy.h"
9 #include "chrome/browser/devtools/devtools_toggle_action.h"
10 #include "chrome/browser/devtools/devtools_ui_bindings.h"
11 #include "content/public/browser/web_contents_delegate.h"
12
13 class Browser;
14 class BrowserWindow;
15 class DevToolsControllerTest;
16 class DevToolsEventForwarder;
17
18 namespace content {
19 class DevToolsAgentHost;
20 struct NativeWebKeyboardEvent;
21 class RenderViewHost;
22 }
23
24 namespace user_prefs {
25 class PrefRegistrySyncable;
26 }
27
28 class DevToolsWindow : public DevToolsUIBindings::Delegate,
29                        public content::WebContentsDelegate {
30  public:
31   static const char kDevToolsApp[];
32
33   virtual ~DevToolsWindow();
34
35   static std::string GetDevToolsWindowPlacementPrefKey();
36   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
37
38   // Return the DevToolsWindow for the given RenderViewHost if one exists,
39   // otherwise NULL.
40   static DevToolsWindow* GetInstanceForInspectedRenderViewHost(
41       content::RenderViewHost* inspected_rvh);
42
43   // Return the DevToolsWindow for the given WebContents if one exists,
44   // otherwise NULL.
45   static DevToolsWindow* GetInstanceForInspectedWebContents(
46       content::WebContents* inspected_web_contents);
47
48   // Return the DevToolsWindow for the given WebContents if one exists and is
49   // docked, otherwise NULL. This method will return only fully initialized
50   // window ready to be presented in UI.
51   // For immediately-ready-to-use but maybe not yet fully initialized DevTools
52   // use |GetInstanceForInspectedRenderViewHost| instead.
53   static DevToolsWindow* GetDockedInstanceForInspectedTab(
54       content::WebContents* inspected_tab);
55
56   static bool IsDevToolsWindow(content::RenderViewHost* window_rvh);
57
58   // Open or reveal DevTools window, and perform the specified action.
59   static DevToolsWindow* OpenDevToolsWindow(
60       content::RenderViewHost* inspected_rvh,
61       const DevToolsToggleAction& action);
62
63   // Open or reveal DevTools window, with no special action.
64   static DevToolsWindow* OpenDevToolsWindow(
65       content::RenderViewHost* inspected_rvh);
66
67   static DevToolsWindow* OpenDevToolsWindowForTest(
68       content::RenderViewHost* inspected_rvh, bool is_docked);
69   static DevToolsWindow* OpenDevToolsWindowForTest(
70       Browser* browser, bool is_docked);
71
72   // Perform specified action for current WebContents inside a |browser|.
73   // This may close currently open DevTools window.
74   static DevToolsWindow* ToggleDevToolsWindow(
75       Browser* browser,
76       const DevToolsToggleAction& action);
77
78   // External frontend is always undocked.
79   static void OpenExternalFrontend(
80       Profile* profile,
81       const std::string& frontend_uri,
82       content::DevToolsAgentHost* agent_host);
83
84   // Worker frontend is always undocked.
85   static DevToolsWindow* OpenDevToolsWindowForWorker(
86       Profile* profile,
87       content::DevToolsAgentHost* worker_agent);
88
89   static void InspectElement(
90       content::RenderViewHost* inspected_rvh, int x, int y);
91
92   content::WebContents* web_contents() { return web_contents_; }
93
94   Browser* browser() { return browser_; }  // For tests.
95
96   // Inspected WebContents is placed over DevTools WebContents in docked mode.
97   // The following method returns the resizing strategy of inspected
98   // WebContents relative to DevTools WebContents.
99   const DevToolsContentsResizingStrategy& GetContentsResizingStrategy() const;
100
101   // Minimum size of the docked DevTools WebContents. This includes
102   // the overlaying inspected WebContents size.
103   gfx::Size GetMinimumSize() const;
104
105   // Sets closure to be called after load is done. If already loaded, calls
106   // closure immediately.
107   void SetLoadCompletedCallback(const base::Closure& closure);
108
109   // Forwards an unhandled keyboard event to the DevTools frontend.
110   bool ForwardKeyboardEvent(const content::NativeWebKeyboardEvent& event);
111
112   // BeforeUnload interception ////////////////////////////////////////////////
113
114   // In order to preserve any edits the user may have made in devtools, the
115   // beforeunload event of the inspected page is hooked - devtools gets the
116   // first shot at handling beforeunload and presents a dialog to the user. If
117   // the user accepts the dialog then the script is given a chance to handle
118   // it. This way 2 dialogs may be displayed: one from the devtools asking the
119   // user to confirm that they're ok with their devtools edits going away and
120   // another from the webpage as the result of its beforeunload handler.
121   // The following set of methods handle beforeunload event flow through
122   // devtools window. When the |contents| with devtools opened on them are
123   // getting closed, the following sequence of calls takes place:
124   // 1. |DevToolsWindow::InterceptPageBeforeUnload| is called and indicates
125   //    whether devtools intercept the beforeunload event.
126   //    If InterceptPageBeforeUnload() returns true then the following steps
127   //    will take place; otherwise only step 4 will be reached and none of the
128   //    corresponding functions in steps 2 & 3 will get called.
129   // 2. |DevToolsWindow::InterceptPageBeforeUnload| fires beforeunload event
130   //    for devtools frontend, which will asynchronously call
131   //    |WebContentsDelegate::BeforeUnloadFired| method.
132   //    In case of docked devtools window, devtools are set as a delegate for
133   //    its frontend, so method |DevToolsWindow::BeforeUnloadFired| will be
134   //    called directly.
135   //    If devtools window is undocked it's not set as the delegate so the call
136   //    to BeforeUnloadFired is proxied through HandleBeforeUnload() rather
137   //    than getting called directly.
138   // 3a. If |DevToolsWindow::BeforeUnloadFired| is called with |proceed|=false
139   //     it calls throught to the content's BeforeUnloadFired(), which from the
140   //     WebContents perspective looks the same as the |content|'s own
141   //     beforeunload dialog having had it's 'stay on this page' button clicked.
142   // 3b. If |proceed| = true, then it fires beforeunload event on |contents|
143   //     and everything proceeds as it normally would without the Devtools
144   //     interception.
145   // 4. If the user cancels the dialog put up by either the WebContents or
146   //    devtools frontend, then |contents|'s |BeforeUnloadFired| callback is
147   //    called with the proceed argument set to false, this causes
148   //    |DevToolsWindow::OnPageCloseCancelled| to be called.
149
150   // Devtools window in undocked state is not set as a delegate of
151   // its frontend. Instead, an instance of browser is set as the delegate, and
152   // thus beforeunload event callback from devtools frontend is not delivered
153   // to the instance of devtools window, which is solely responsible for
154   // managing custom beforeunload event flow.
155   // This is a helper method to route callback from
156   // |Browser::BeforeUnloadFired| back to |DevToolsWindow::BeforeUnloadFired|.
157   // * |proceed| - true if the user clicked 'ok' in the beforeunload dialog,
158   //   false otherwise.
159   // * |proceed_to_fire_unload| - output parameter, whether we should continue
160   //   to fire the unload event or stop things here.
161   // Returns true if devtools window is in a state of intercepting beforeunload
162   // event and if it will manage unload process on its own.
163   static bool HandleBeforeUnload(content::WebContents* contents,
164                                  bool proceed,
165                                  bool* proceed_to_fire_unload);
166
167   // Returns true if this contents beforeunload event was intercepted by
168   // devtools and false otherwise. If the event was intercepted, caller should
169   // not fire beforeunlaod event on |contents| itself as devtools window will
170   // take care of it, otherwise caller should continue handling the event as
171   // usual.
172   static bool InterceptPageBeforeUnload(content::WebContents* contents);
173
174   // Returns true if devtools browser has already fired its beforeunload event
175   // as a result of beforeunload event interception.
176   static bool HasFiredBeforeUnloadEventForDevToolsBrowser(Browser* browser);
177
178   // Returns true if devtools window would like to hook beforeunload event
179   // of this |contents|.
180   static bool NeedsToInterceptBeforeUnload(content::WebContents* contents);
181
182   // Notify devtools window that closing of |contents| was cancelled
183   // by user.
184   static void OnPageCloseCanceled(content::WebContents* contents);
185
186  private:
187   friend class DevToolsControllerTest;
188   friend class DevToolsSanityTest;
189   friend class BrowserWindowControllerTest;
190
191   // DevTools initialization typically follows this way:
192   // - Toggle/Open: client call;
193   // - Create;
194   // - ScheduleShow: setup window to be functional, but not yet show;
195   // - DocumentOnLoadCompletedInMainFrame: frontend loaded;
196   // - SetIsDocked: frontend decided on docking state;
197   // - OnLoadCompleted: ready to present frontend;
198   // - Show: actually placing frontend WebContents to a Browser or docked place;
199   // - DoAction: perform action passed in Toggle/Open.
200   enum LoadState {
201     kNotLoaded,
202     kOnLoadFired, // Implies SetIsDocked was not yet called.
203     kIsDockedSet, // Implies DocumentOnLoadCompleted was not yet called.
204     kLoadCompleted
205   };
206
207   DevToolsWindow(Profile* profile,
208                  const GURL& frontend_url,
209                  content::RenderViewHost* inspected_rvh,
210                  bool can_dock);
211
212   static DevToolsWindow* Create(Profile* profile,
213                                 const GURL& frontend_url,
214                                 content::RenderViewHost* inspected_rvh,
215                                 bool shared_worker_frontend,
216                                 bool external_frontend,
217                                 bool can_dock);
218   static GURL GetDevToolsURL(Profile* profile,
219                              const GURL& base_url,
220                              bool shared_worker_frontend,
221                              bool external_frontend,
222                              bool can_dock);
223   static DevToolsWindow* FindDevToolsWindow(content::DevToolsAgentHost*);
224   static DevToolsWindow* AsDevToolsWindow(content::RenderViewHost*);
225   static DevToolsWindow* CreateDevToolsWindowForWorker(Profile* profile);
226   static bool FindInspectedBrowserAndTabIndex(
227       content::WebContents* inspected_web_contents, Browser**, int* tab);
228   static DevToolsWindow* ToggleDevToolsWindow(
229       content::RenderViewHost* inspected_rvh,
230       bool force_open,
231       const DevToolsToggleAction& action);
232
233   // content::WebContentsDelegate:
234   virtual content::WebContents* OpenURLFromTab(
235       content::WebContents* source,
236       const content::OpenURLParams& params) OVERRIDE;
237   virtual void ActivateContents(content::WebContents* contents) OVERRIDE;
238   virtual void AddNewContents(content::WebContents* source,
239                               content::WebContents* new_contents,
240                               WindowOpenDisposition disposition,
241                               const gfx::Rect& initial_pos,
242                               bool user_gesture,
243                               bool* was_blocked) OVERRIDE;
244   virtual void CloseContents(content::WebContents* source) OVERRIDE;
245   virtual void ContentsZoomChange(bool zoom_in) OVERRIDE;
246   virtual void BeforeUnloadFired(content::WebContents* tab,
247                                  bool proceed,
248                                  bool* proceed_to_fire_unload) OVERRIDE;
249   virtual bool PreHandleKeyboardEvent(
250       content::WebContents* source,
251       const content::NativeWebKeyboardEvent& event,
252       bool* is_keyboard_shortcut) OVERRIDE;
253   virtual void HandleKeyboardEvent(
254       content::WebContents* source,
255       const content::NativeWebKeyboardEvent& event) OVERRIDE;
256   virtual content::JavaScriptDialogManager*
257       GetJavaScriptDialogManager() OVERRIDE;
258   virtual content::ColorChooser* OpenColorChooser(
259       content::WebContents* web_contents,
260       SkColor color,
261       const std::vector<content::ColorSuggestion>& suggestions) OVERRIDE;
262   virtual void RunFileChooser(
263       content::WebContents* web_contents,
264       const content::FileChooserParams& params) OVERRIDE;
265   virtual void WebContentsFocused(content::WebContents* contents) OVERRIDE;
266   virtual bool PreHandleGestureEvent(
267       content::WebContents* source,
268       const blink::WebGestureEvent& event) OVERRIDE;
269
270   // content::DevToolsUIBindings::Delegate overrides
271   virtual void ActivateWindow() OVERRIDE;
272   virtual void CloseWindow() OVERRIDE;
273   virtual void SetContentsInsets(
274       int left, int top, int right, int bottom) OVERRIDE;
275   virtual void SetContentsResizingStrategy(
276       const gfx::Insets& insets, const gfx::Size& min_size) OVERRIDE;
277   virtual void InspectElementCompleted() OVERRIDE;
278   virtual void MoveWindow(int x, int y) OVERRIDE;
279   virtual void SetIsDocked(bool is_docked) OVERRIDE;
280   virtual void OpenInNewTab(const std::string& url) OVERRIDE;
281   virtual void SetWhitelistedShortcuts(const std::string& message) OVERRIDE;
282   virtual void InspectedContentsClosing() OVERRIDE;
283   virtual void OnLoadCompleted() OVERRIDE;
284   virtual InfoBarService* GetInfoBarService() OVERRIDE;
285   virtual void RenderProcessGone() OVERRIDE;
286
287   void CreateDevToolsBrowser();
288   BrowserWindow* GetInspectedBrowserWindow();
289   void ScheduleShow(const DevToolsToggleAction& action);
290   void Show(const DevToolsToggleAction& action);
291   void DoAction(const DevToolsToggleAction& action);
292   void LoadCompleted();
293   void SetIsDockedAndShowImmediatelyForTest(bool is_docked);
294   void UpdateBrowserToolbar();
295   content::WebContents* GetInspectedWebContents();
296
297   class InspectedWebContentsObserver;
298   scoped_ptr<InspectedWebContentsObserver> inspected_contents_observer_;
299
300   Profile* profile_;
301   content::WebContents* web_contents_;
302   DevToolsUIBindings* bindings_;
303   Browser* browser_;
304   bool is_docked_;
305   const bool can_dock_;
306   LoadState load_state_;
307   DevToolsToggleAction action_on_load_;
308   bool ignore_set_is_docked_;
309   DevToolsContentsResizingStrategy contents_resizing_strategy_;
310   // True if we're in the process of handling a beforeunload event originating
311   // from the inspected webcontents, see InterceptPageBeforeUnload for details.
312   bool intercepted_page_beforeunload_;
313   base::Closure load_completed_callback_;
314
315   base::TimeTicks inspect_element_start_time_;
316   scoped_ptr<DevToolsEventForwarder> event_forwarder_;
317
318   friend class DevToolsEventForwarder;
319   DISALLOW_COPY_AND_ASSIGN(DevToolsWindow);
320 };
321
322 #endif  // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_WINDOW_H_