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