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