browser_host_impl.cc 120 KB
Newer Older
1 2 3 4 5 6 7 8
// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2011 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.

#include "libcef/browser/browser_host_impl.h"

#include <string>
9
#include <utility>
10

11
#include "libcef/browser/audio_mirror_destination.h"
12
#include "libcef/browser/browser_context_impl.h"
13
#include "libcef/browser/browser_info.h"
14
#include "libcef/browser/browser_info_manager.h"
15 16
#include "libcef/browser/browser_platform_delegate.h"
#include "libcef/browser/browser_util.h"
17
#include "libcef/browser/content_browser_client.h"
18
#include "libcef/browser/context.h"
19 20
#include "libcef/browser/devtools/devtools_frontend.h"
#include "libcef/browser/devtools/devtools_manager_delegate.h"
21
#include "libcef/browser/extensions/browser_extensions_util.h"
22 23 24 25
#include "libcef/browser/extensions/extension_background_host.h"
#include "libcef/browser/extensions/extension_system.h"
#include "libcef/browser/extensions/extension_view_host.h"
#include "libcef/browser/extensions/extension_web_contents_observer.h"
26
#include "libcef/browser/image_impl.h"
27
#include "libcef/browser/media_capture_devices_dispatcher.h"
28
#include "libcef/browser/navigate_params.h"
29
#include "libcef/browser/navigation_entry_impl.h"
30 31
#include "libcef/browser/net/chrome_scheme_handler.h"
#include "libcef/browser/net/scheme_handler.h"
32
#include "libcef/browser/osr/osr_util.h"
33
#include "libcef/browser/printing/print_view_manager.h"
34
#include "libcef/browser/request_context_impl.h"
35 36
#include "libcef/browser/thread_util.h"
#include "libcef/common/cef_messages.h"
37
#include "libcef/common/cef_switches.h"
38
#include "libcef/common/drag_data_impl.h"
39
#include "libcef/common/extensions/extensions_util.h"
40 41 42
#include "libcef/common/main_delegate.h"
#include "libcef/common/process_message_impl.h"
#include "libcef/common/request_impl.h"
43
#include "libcef/common/values_impl.h"
44 45 46

#include "base/bind.h"
#include "base/bind_helpers.h"
47
#include "base/command_line.h"
48 49
#include "chrome/browser/spellchecker/spellcheck_factory.h"
#include "chrome/browser/spellchecker/spellcheck_service.h"
50
#include "chrome/browser/ui/prefs/prefs_tab_helper.h"
51
#include "components/zoom/zoom_controller.h"
52
#include "content/browser/gpu/compositor_util.h"
53
#include "content/browser/media/capture/audio_mirroring_manager.h"
54
#include "content/browser/web_contents/web_contents_impl.h"
55
#include "content/common/widget_messages.h"
56
#include "content/public/browser/desktop_media_id.h"
57
#include "content/public/browser/download_manager.h"
58
#include "content/public/browser/download_request_utils.h"
59
#include "content/public/browser/file_select_listener.h"
60
#include "content/public/browser/host_zoom_map.h"
61
#include "content/public/browser/keyboard_event_processing_result.h"
62
#include "content/public/browser/native_web_keyboard_event.h"
63 64
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
65
#include "content/public/browser/navigation_handle.h"
66 67 68
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
69 70 71
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
72
#include "content/public/browser/render_widget_host.h"
73
#include "content/public/browser/resource_request_info.h"
74
#include "content/public/common/favicon_url.h"
75
#include "extensions/browser/process_manager.h"
76
#include "net/base/net_errors.h"
77
#include "third_party/blink/public/mojom/frame/find_in_page.mojom.h"
78
#include "ui/events/base_event_utils.h"
79

80
#if defined(OS_MACOSX)
81
#include "components/spellcheck/browser/spellcheck_platform.h"
82 83
#endif

84 85
using content::KeyboardEventProcessingResult;

86 87
namespace {

88 89 90 91
const int kUnspecifiedFrameTreeNodeId = -3;
const int kMainFrameTreeNodeId = -2;
const int kUnusedFrameTreeNodeId = -1;

92 93 94
// Associates a CefBrowserHostImpl instance with a WebContents. This object will
// be deleted automatically when the WebContents is destroyed.
class WebContentsUserDataAdapter : public base::SupportsUserData::Data {
95
 public:
96 97
  static void Register(CefBrowserHostImpl* browser) {
    new WebContentsUserDataAdapter(browser);
98 99
  }

100 101 102 103 104 105 106
  static CefBrowserHostImpl* Get(const content::WebContents* web_contents) {
    WebContentsUserDataAdapter* adapter =
        static_cast<WebContentsUserDataAdapter*>(
            web_contents->GetUserData(UserDataKey()));
    if (adapter)
      return adapter->browser_;
    return nullptr;
107 108 109
  }

 private:
110
  WebContentsUserDataAdapter(CefBrowserHostImpl* browser) : browser_(browser) {
111
    browser->web_contents()->SetUserData(UserDataKey(), base::WrapUnique(this));
112 113
  }

114 115 116 117 118 119
  static void* UserDataKey() {
    // We just need a unique constant. Use the address of a static that
    // COMDAT folding won't touch in an optimizing linker.
    static int data_key = 0;
    return reinterpret_cast<void*>(&data_key);
  }
120

121
  CefBrowserHostImpl* browser_;  // Not owned.
122 123
};

124 125 126 127 128
class CreateBrowserHelper {
 public:
  CreateBrowserHelper(const CefWindowInfo& windowInfo,
                      CefRefPtr<CefClient> client,
                      const CefString& url,
129 130
                      const CefBrowserSettings& settings,
                      CefRefPtr<CefRequestContext> request_context)
131 132 133 134 135
      : window_info_(windowInfo),
        client_(client),
        url_(url),
        settings_(settings),
        request_context_(request_context) {}
136 137 138 139 140

  CefWindowInfo window_info_;
  CefRefPtr<CefClient> client_;
  CefString url_;
  CefBrowserSettings settings_;
141
  CefRefPtr<CefRequestContext> request_context_;
142 143 144 145
};

void CreateBrowserWithHelper(CreateBrowserHelper* helper) {
  CefBrowserHost::CreateBrowserSync(helper->window_info_, helper->client_,
146 147
                                    helper->url_, helper->settings_,
                                    helper->request_context_);
148 149 150
  delete helper;
}

151 152 153 154 155
class ShowDevToolsHelper {
 public:
  ShowDevToolsHelper(CefRefPtr<CefBrowserHostImpl> browser,
                     const CefWindowInfo& windowInfo,
                     CefRefPtr<CefClient> client,
156 157
                     const CefBrowserSettings& settings,
                     const CefPoint& inspect_element_at)
158 159 160 161 162
      : browser_(browser),
        window_info_(windowInfo),
        client_(client),
        settings_(settings),
        inspect_element_at_(inspect_element_at) {}
163 164 165 166 167

  CefRefPtr<CefBrowserHostImpl> browser_;
  CefWindowInfo window_info_;
  CefRefPtr<CefClient> client_;
  CefBrowserSettings settings_;
168
  CefPoint inspect_element_at_;
169 170 171 172
};

void ShowDevToolsWithHelper(ShowDevToolsHelper* helper) {
  helper->browser_->ShowDevTools(helper->window_info_, helper->client_,
173 174
                                 helper->settings_,
                                 helper->inspect_element_at_);
175 176 177
  delete helper;
}

178 179 180 181 182 183 184 185 186
// Callback from CefBrowserHostImpl::DownloadImage.
void OnDownloadImage(uint32 max_image_size,
                     CefRefPtr<CefDownloadImageCallback> callback,
                     int id,
                     int http_status_code,
                     const GURL& image_url,
                     const std::vector<SkBitmap>& bitmaps,
                     const std::vector<gfx::Size>& sizes) {
  CEF_REQUIRE_UIT();
187

188
  CefRefPtr<CefImageImpl> image_impl;
189

190 191 192 193 194 195 196
  if (!bitmaps.empty()) {
    image_impl = new CefImageImpl();
    image_impl->AddBitmaps(max_image_size, bitmaps);
  }

  callback->OnDownloadImageFinished(image_url.spec(), http_status_code,
                                    image_impl.get());
197 198
}

199 200 201 202 203 204
}  // namespace

// CefBrowserHost static methods.
// -----------------------------------------------------------------------------

// static
205 206 207 208 209 210
bool CefBrowserHost::CreateBrowser(
    const CefWindowInfo& windowInfo,
    CefRefPtr<CefClient> client,
    const CefString& url,
    const CefBrowserSettings& settings,
    CefRefPtr<CefRequestContext> request_context) {
211 212 213 214 215 216 217 218 219 220 221 222
  // Verify that the context is in a valid state.
  if (!CONTEXT_STATE_VALID()) {
    NOTREACHED() << "context not valid";
    return false;
  }

  // Verify that the settings structure is a valid size.
  if (settings.size != sizeof(cef_browser_settings_t)) {
    NOTREACHED() << "invalid CefBrowserSettings structure size";
    return false;
  }

223
  // Verify windowless rendering requirements.
224 225 226 227
  if (windowInfo.windowless_rendering_enabled &&
      !client->GetRenderHandler().get()) {
    NOTREACHED() << "CefRenderHandler implementation is required";
    return false;
228 229
  }

230 231 232 233 234 235 236
  if (windowInfo.windowless_rendering_enabled &&
      !CefContext::Get()->settings().windowless_rendering_enabled) {
    LOG(ERROR) << "Creating a windowless browser without setting "
                  "CefSettings.windowless_rendering_enabled may result in "
                  "reduced performance or runtime errors.";
  }

237
  // Create the browser on the UI thread.
238 239
  CreateBrowserHelper* helper = new CreateBrowserHelper(
      windowInfo, client, url, settings, request_context);
240
  CEF_POST_TASK(CEF_UIT, base::BindOnce(CreateBrowserWithHelper, helper));
241 242 243 244 245 246 247 248 249

  return true;
}

// static
CefRefPtr<CefBrowser> CefBrowserHost::CreateBrowserSync(
    const CefWindowInfo& windowInfo,
    CefRefPtr<CefClient> client,
    const CefString& url,
250 251
    const CefBrowserSettings& settings,
    CefRefPtr<CefRequestContext> request_context) {
252 253 254
  // Verify that the context is in a valid state.
  if (!CONTEXT_STATE_VALID()) {
    NOTREACHED() << "context not valid";
255
    return nullptr;
256 257 258 259 260
  }

  // Verify that the settings structure is a valid size.
  if (settings.size != sizeof(cef_browser_settings_t)) {
    NOTREACHED() << "invalid CefBrowserSettings structure size";
261
    return nullptr;
262 263 264 265 266
  }

  // Verify that this method is being called on the UI thread.
  if (!CEF_CURRENTLY_ON_UIT()) {
    NOTREACHED() << "called on invalid thread";
267 268 269 270 271 272 273 274
    return nullptr;
  }

  // Verify windowless rendering requirements.
  if (windowInfo.windowless_rendering_enabled &&
      !client->GetRenderHandler().get()) {
    NOTREACHED() << "CefRenderHandler implementation is required";
    return nullptr;
275 276
  }

277 278 279
  CefBrowserHostImpl::CreateParams create_params;
  create_params.window_info.reset(new CefWindowInfo(windowInfo));
  create_params.client = client;
280
  create_params.url = GURL(url.ToString());
281
  if (!url.empty() && !create_params.url.is_valid() &&
282 283 284 285
      !create_params.url.has_scheme()) {
    std::string new_url = std::string("http://") + url.ToString();
    create_params.url = GURL(new_url);
  }
286 287 288
  create_params.settings = settings;
  create_params.request_context = request_context;

289
  CefRefPtr<CefBrowserHostImpl> browser =
290
      CefBrowserHostImpl::Create(create_params);
291 292 293 294 295 296 297 298
  return browser.get();
}

// CefBrowserHostImpl static methods.
// -----------------------------------------------------------------------------

// static
CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::Create(
299
    CreateParams& create_params) {
300
  std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate =
301 302 303 304
      CefBrowserPlatformDelegate::Create(create_params);
  CHECK(platform_delegate);

  const bool is_devtools_popup = !!create_params.devtools_opener;
305

306
  scoped_refptr<CefBrowserInfo> info =
307
      CefBrowserInfoManager::GetInstance()->CreateBrowserInfo(
308
          is_devtools_popup, platform_delegate->IsWindowless());
309 310 311

  // Get or create the request context and browser context.
  CefRefPtr<CefRequestContextImpl> request_context_impl =
312
      CefRequestContextImpl::GetOrCreateForRequestContext(
313 314
          create_params.request_context);
  DCHECK(request_context_impl);
315
  CefBrowserContext* browser_context =
316 317 318
      request_context_impl->GetBrowserContext();
  DCHECK(browser_context);

319 320 321 322 323
  // A StoragePartitionImplMap must already exist for the BrowserContext. See
  // additional comments in CefBrowserContextImpl::Initialize().
  DCHECK(browser_context->GetUserData(
      content::BrowserContext::GetStoragePartitionMapUserDataKey()));

324 325 326 327 328
  if (!create_params.request_context) {
    // Using the global request context.
    create_params.request_context = request_context_impl.get();
  }

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
  CefRefPtr<CefExtension> cef_extension;
  scoped_refptr<content::SiteInstance> site_instance;
  if (extensions::ExtensionsEnabled() && !create_params.url.is_empty()) {
    if (!create_params.extension) {
      // We might be loading an extension app view where the extension URL is
      // provided by the client.
      create_params.extension =
          extensions::GetExtensionForUrl(browser_context, create_params.url);
    }
    if (create_params.extension) {
      cef_extension = browser_context->extension_system()->GetExtension(
          create_params.extension->id());
      DCHECK(cef_extension);

      if (create_params.extension_host_type == extensions::VIEW_TYPE_INVALID) {
        // Default to dialog behavior.
        create_params.extension_host_type =
            extensions::VIEW_TYPE_EXTENSION_DIALOG;
      }

      // Extension resources will fail to load if we don't use a SiteInstance
      // associated with the extension.
      // (CefContentBrowserClient::SiteInstanceGotProcess won't find the
      // extension to register with InfoMap, and AllowExtensionResourceLoad in
      // ExtensionProtocolHandler::MaybeCreateJob will return false resulting in
      // ERR_BLOCKED_BY_CLIENT).
      site_instance = extensions::ProcessManager::Get(browser_context)
                          ->GetSiteInstanceForURL(create_params.url);
      DCHECK(site_instance);
    }
  }

  content::WebContents::CreateParams wc_create_params(browser_context,
                                                      site_instance);
363 364 365 366

  if (platform_delegate->IsWindowless()) {
    // Create the OSR view for the WebContents.
    platform_delegate->CreateViewForWebContents(
367
        &wc_create_params.view, &wc_create_params.delegate_view);
368 369
  }

370
  std::unique_ptr<content::WebContents> web_contents =
371 372
      content::WebContents::Create(wc_create_params);
  DCHECK(web_contents);
373

374 375 376
  CefRefPtr<CefBrowserHostImpl> browser = CreateInternal(
      create_params.settings, create_params.client, web_contents.release(),
      true, info, create_params.devtools_opener, is_devtools_popup,
377 378 379 380 381 382 383
      create_params.request_context, std::move(platform_delegate),
      cef_extension);
  if (!browser)
    return nullptr;

  if (create_params.extension) {
    browser->CreateExtensionHost(create_params.extension, browser_context,
384
                                 browser->web_contents(), create_params.url,
385 386 387
                                 create_params.extension_host_type);
  } else if (!create_params.url.is_empty()) {
    browser->LoadURL(CefFrameHostImpl::kMainFrameId, create_params.url.spec(),
388 389
                     content::Referrer(), ui::PAGE_TRANSITION_TYPED,
                     std::string());
390
  }
391

392 393 394 395
  return browser.get();
}

// static
396
CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::CreateInternal(
397 398
    const CefBrowserSettings& settings,
    CefRefPtr<CefClient> client,
399
    content::WebContents* web_contents,
400
    bool own_web_contents,
401
    scoped_refptr<CefBrowserInfo> browser_info,
402
    CefRefPtr<CefBrowserHostImpl> opener,
403
    bool is_devtools_popup,
404
    CefRefPtr<CefRequestContext> request_context,
405 406
    std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
    CefRefPtr<CefExtension> extension) {
407
  CEF_REQUIRE_UIT();
408 409 410 411
  DCHECK(web_contents);
  DCHECK(browser_info);
  DCHECK(request_context);
  DCHECK(platform_delegate);
412 413

  // If |opener| is non-NULL it must be a popup window.
414
  DCHECK(!opener.get() || browser_info->is_popup());
415

416
  if (opener) {
417 418 419 420 421
    if (!opener->platform_delegate_) {
      // The opener window is being destroyed. Cancel the popup.
      return nullptr;
    }

422 423 424 425 426
    // Give the opener browser's platform delegate an opportunity to modify the
    // new browser's platform delegate.
    opener->platform_delegate_->PopupWebContentsCreated(
        settings, client, web_contents, platform_delegate.get(),
        is_devtools_popup);
427 428
  }

429 430
  platform_delegate->WebContentsCreated(web_contents);

431 432
  CefRefPtr<CefBrowserHostImpl> browser = new CefBrowserHostImpl(
      settings, client, web_contents, browser_info, opener, request_context,
433
      std::move(platform_delegate), extension);
434 435
  if (own_web_contents)
    browser->set_owned_web_contents(web_contents);
436 437
  if (!browser->CreateHostWindow())
    return nullptr;
438

439 440 441 442 443
  // Notify that the browser has been created. These must be delivered in the
  // expected order.

  // 1. Notify the browser's LifeSpanHandler. This must always be the first
  // notification for the browser.
444 445 446 447 448 449
  if (client.get()) {
    CefRefPtr<CefLifeSpanHandler> handler = client->GetLifeSpanHandler();
    if (handler.get())
      handler->OnAfterCreated(browser.get());
  }

450 451 452 453
  // 2. Notify the platform delegate. With Views this will result in a call to
  // CefBrowserViewDelegate::OnBrowserCreated().
  browser->platform_delegate_->NotifyBrowserCreated();

454
  if (opener && opener->platform_delegate_) {
455 456 457 458 459 460
    // 3. Notify the opener browser's platform delegate. With Views this will
    // result in a call to CefBrowserViewDelegate::OnPopupBrowserViewCreated().
    opener->platform_delegate_->PopupBrowserCreated(browser.get(),
                                                    is_devtools_popup);
  }

461 462 463 464 465 466 467 468
  return browser;
}

// static
CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForHost(
    const content::RenderViewHost* host) {
  DCHECK(host);
  CEF_REQUIRE_UIT();
469 470
  content::WebContents* web_contents = content::WebContents::FromRenderViewHost(
      const_cast<content::RenderViewHost*>(host));
471
  if (web_contents)
472
    return GetBrowserForContents(web_contents);
473
  return nullptr;
474 475 476 477 478 479 480 481 482 483
}

// static
CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForHost(
    const content::RenderFrameHost* host) {
  DCHECK(host);
  CEF_REQUIRE_UIT();
  content::WebContents* web_contents =
      content::WebContents::FromRenderFrameHost(
          const_cast<content::RenderFrameHost*>(host));
484
  if (web_contents)
485
    return GetBrowserForContents(web_contents);
486
  return nullptr;
487 488 489 490
}

// static
CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForContents(
491
    const content::WebContents* contents) {
492
  DCHECK(contents);
493 494
  CEF_REQUIRE_UIT();
  return WebContentsUserDataAdapter::Get(contents);
495 496 497 498
}

// static
CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForRequest(
499
    const net::URLRequest* request) {
500 501
  DCHECK(request);
  CEF_REQUIRE_IOT();
502 503 504 505 506

  // When navigating the main frame a new (pre-commit) URLRequest will be
  // created before the RenderFrameHost. Consequently we can't rely on
  // ResourceRequestInfo::GetRenderFrameForRequest returning a valid frame
  // ID. See https://crbug.com/776884 for background.
507
  int render_process_id = -1;
508
  int render_frame_id = MSG_ROUTING_NONE;
509 510 511 512
  if (content::ResourceRequestInfo::GetRenderFrameForRequest(
          request, &render_process_id, &render_frame_id) &&
      render_process_id >= 0 && render_frame_id >= 0) {
    return GetBrowserForFrame(render_process_id, render_frame_id);
513
  }
514

515
  content::ResourceRequestInfo* request_info =
516 517 518 519 520
      content::ResourceRequestInfo::ForRequest(request);
  if (request_info)
    return GetBrowserForFrameTreeNode(request_info->GetFrameTreeNodeId());

  return nullptr;
521 522 523
}

// static
524 525 526 527 528 529 530 531 532 533 534 535
CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForFrameTreeNode(
    int frame_tree_node_id) {
  // Use the thread-safe approach.
  scoped_refptr<CefBrowserInfo> info =
      CefBrowserInfoManager::GetInstance()->GetBrowserInfoForFrameTreeNode(
          frame_tree_node_id);
  if (info.get()) {
    CefRefPtr<CefBrowserHostImpl> browser = info->browser();
    if (!browser.get()) {
      LOG(WARNING) << "Found browser id " << info->browser_id()
                   << " but no browser object matching frame tree node id "
                   << frame_tree_node_id;
536
    }
537
    return browser;
538
  }
539 540

  return nullptr;
541 542 543 544
}

// static
CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::GetBrowserForFrame(
545 546
    int render_process_id,
    int render_routing_id) {
547
  if (render_process_id == -1 || render_routing_id == MSG_ROUTING_NONE)
548
    return nullptr;
549 550 551 552 553 554

  if (CEF_CURRENTLY_ON_UIT()) {
    // Use the non-thread-safe but potentially faster approach.
    content::RenderFrameHost* render_frame_host =
        content::RenderFrameHost::FromID(render_process_id, render_routing_id);
    if (!render_frame_host)
555
      return nullptr;
556 557 558
    return GetBrowserForHost(render_frame_host);
  } else {
    // Use the thread-safe approach.
559
    bool is_guest_view = false;
560
    scoped_refptr<CefBrowserInfo> info =
561
        CefBrowserInfoManager::GetInstance()->GetBrowserInfoForFrame(
562 563
            render_process_id, render_routing_id, &is_guest_view);
    if (info.get() && !is_guest_view) {
564
      CefRefPtr<CefBrowserHostImpl> browser = info->browser();
565
      if (!browser.get()) {
566 567 568 569
        LOG(WARNING) << "Found browser id " << info->browser_id()
                     << " but no browser object matching frame process id "
                     << render_process_id << " and routing id "
                     << render_routing_id;
570
      }
571
      return browser;
572
    }
573
    return nullptr;
574 575 576
  }
}

577
// CefBrowserHostImpl methods.
578 579
// -----------------------------------------------------------------------------

580 581
// WebContentsObserver that will be notified when the frontend WebContents is
// destroyed so that the inspected browser can clear its DevTools references.
582 583
class CefBrowserHostImpl::DevToolsWebContentsObserver
    : public content::WebContentsObserver {
584 585 586
 public:
  DevToolsWebContentsObserver(CefBrowserHostImpl* browser,
                              content::WebContents* frontend_web_contents)
587
      : WebContentsObserver(frontend_web_contents), browser_(browser) {}
588 589

  // WebContentsObserver methods:
590
  void WebContentsDestroyed() override {
591 592 593 594 595 596 597 598 599
    browser_->OnDevToolsWebContentsDestroyed();
  }

 private:
  CefBrowserHostImpl* browser_;

  DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
};

600
CefBrowserHostImpl::~CefBrowserHostImpl() {}
601

602 603 604 605
CefRefPtr<CefBrowser> CefBrowserHostImpl::GetBrowser() {
  return this;
}

606
void CefBrowserHostImpl::CloseBrowser(bool force_close) {
607
  if (CEF_CURRENTLY_ON_UIT()) {
608 609
    // Exit early if a close attempt is already pending and this method is
    // called again from somewhere other than WindowDestroyed().
610 611
    if (destruction_state_ >= DESTRUCTION_STATE_PENDING &&
        (IsWindowless() || !window_destroyed_)) {
612 613 614
      if (force_close && destruction_state_ == DESTRUCTION_STATE_PENDING) {
        // Upgrade the destruction state.
        destruction_state_ = DESTRUCTION_STATE_ACCEPTED;
615
      }
616 617 618 619
      return;
    }

    if (destruction_state_ < DESTRUCTION_STATE_ACCEPTED) {
620 621
      destruction_state_ = (force_close ? DESTRUCTION_STATE_ACCEPTED
                                        : DESTRUCTION_STATE_PENDING);
622 623 624 625 626 627
    }

    content::WebContents* contents = web_contents();
    if (contents && contents->NeedToFireBeforeUnload()) {
      // Will result in a call to BeforeUnloadFired() and, if the close isn't
      // canceled, CloseContents().
628
      contents->DispatchBeforeUnload(false /* auto_cancel */);
629
    } else {
630
      CloseContents(contents);
631
    }
632
  } else {
633 634
    CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostImpl::CloseBrowser,
                                          this, force_close));
635 636 637
  }
}

638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
bool CefBrowserHostImpl::TryCloseBrowser() {
  if (!CEF_CURRENTLY_ON_UIT()) {
    NOTREACHED() << "called on invalid thread";
    return false;
  }

  // Protect against multiple requests to close while the close is pending.
  if (destruction_state_ <= DESTRUCTION_STATE_PENDING) {
    if (destruction_state_ == DESTRUCTION_STATE_NONE) {
      // Request that the browser close.
      CloseBrowser(false);
    }

    // Cancel the close.
    return false;
  }

  // Allow the close.
  return true;
}

659
void CefBrowserHostImpl::SetFocus(bool focus) {
660 661
  if (!CEF_CURRENTLY_ON_UIT()) {
    CEF_POST_TASK(CEF_UIT,
662
                  base::BindOnce(&CefBrowserHostImpl::SetFocus, this, focus));
663
    return;
664
  }
665 666 667

  if (focus)
    OnSetFocus(FOCUS_SOURCE_SYSTEM);
668
  else if (platform_delegate_)
669
    platform_delegate_->SendFocusEvent(false);
670
}
671 672

CefWindowHandle CefBrowserHostImpl::GetWindowHandle() {
673 674 675 676 677 678 679
  if (IsViewsHosted() && CEF_CURRENTLY_ON_UIT()) {
    // Always return the most up-to-date window handle for a views-hosted
    // browser since it may change if the view is re-parented.
    if (platform_delegate_)
      return platform_delegate_->GetHostWindowHandle();
  }
  return host_window_handle_;
680 681 682 683 684 685
}

CefWindowHandle CefBrowserHostImpl::GetOpenerWindowHandle() {
  return opener_;
}

686 687 688 689
bool CefBrowserHostImpl::HasView() {
  return IsViewsHosted();
}

690 691 692 693
CefRefPtr<CefClient> CefBrowserHostImpl::GetClient() {
  return client_;
}

694 695 696 697
CefRefPtr<CefRequestContext> CefBrowserHostImpl::GetRequestContext() {
  return request_context_;
}

698 699 700 701 702 703 704
double CefBrowserHostImpl::GetZoomLevel() {
  // Verify that this method is being called on the UI thread.
  if (!CEF_CURRENTLY_ON_UIT()) {
    NOTREACHED() << "called on invalid thread";
    return 0;
  }

705 706
  if (web_contents())
    return content::HostZoomMap::GetZoomLevel(web_contents());
707 708 709 710 711 712

  return 0;
}

void CefBrowserHostImpl::SetZoomLevel(double zoomLevel) {
  if (CEF_CURRENTLY_ON_UIT()) {
713 714
    if (web_contents())
      content::HostZoomMap::SetZoomLevel(web_contents(), zoomLevel);
715
  } else {
716 717
    CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostImpl::SetZoomLevel,
                                          this, zoomLevel));
718 719 720
  }
}

721
void CefBrowserHostImpl::RunFileDialog(
722 723 724 725 726 727
    FileDialogMode mode,
    const CefString& title,
    const CefString& default_file_path,
    const std::vector<CefString>& accept_filters,
    int selected_accept_filter,
    CefRefPtr<CefRunFileDialogCallback> callback) {
728 729
  if (!CEF_CURRENTLY_ON_UIT()) {
    CEF_POST_TASK(CEF_UIT,
730 731 732
                  base::BindOnce(&CefBrowserHostImpl::RunFileDialog, this, mode,
                                 title, default_file_path, accept_filters,
                                 selected_accept_filter, callback));
733 734
    return;
  }
735

736 737 738 739
  EnsureFileDialogManager();
  file_dialog_manager_->RunFileDialog(mode, title, default_file_path,
                                      accept_filters, selected_accept_filter,
                                      callback);
740 741
}

742 743
void CefBrowserHostImpl::StartDownload(const CefString& url) {
  if (!CEF_CURRENTLY_ON_UIT()) {
744 745
    CEF_POST_TASK(
        CEF_UIT, base::BindOnce(&CefBrowserHostImpl::StartDownload, this, url));
746 747 748 749 750 751 752 753 754 755
    return;
  }

  GURL gurl = GURL(url.ToString());
  if (gurl.is_empty() || !gurl.is_valid())
    return;

  if (!web_contents())
    return;

756
  CefBrowserContext* context =
757
      static_cast<CefBrowserContext*>(web_contents()->GetBrowserContext());
758
  if (!context)
759 760
    return;

761
  content::DownloadManager* manager =
762
      content::BrowserContext::GetDownloadManager(context);
763 764 765
  if (!manager)
    return;

766 767
  std::unique_ptr<download::DownloadUrlParameters> params(
      content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
768
          web_contents(), gurl, NO_TRAFFIC_ANNOTATION_YET));
769
  manager->DownloadUrl(std::move(params));
770 771
}

772 773 774 775 776 777 778
void CefBrowserHostImpl::DownloadImage(
    const CefString& image_url,
    bool is_favicon,
    uint32 max_image_size,
    bool bypass_cache,
    CefRefPtr<CefDownloadImageCallback> callback) {
  if (!CEF_CURRENTLY_ON_UIT()) {
779 780 781 782
    CEF_POST_TASK(
        CEF_UIT,
        base::BindOnce(&CefBrowserHostImpl::DownloadImage, this, image_url,
                       is_favicon, max_image_size, bypass_cache, callback));
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
    return;
  }

  if (!callback)
    return;

  GURL gurl = GURL(image_url.ToString());
  if (gurl.is_empty() || !gurl.is_valid())
    return;

  if (!web_contents())
    return;

  web_contents()->DownloadImage(
      gurl, is_favicon, max_image_size * gfx::ImageSkia::GetMaxSupportedScale(),
798
      bypass_cache, base::BindOnce(OnDownloadImage, max_image_size, callback));
799 800
}

801 802
void CefBrowserHostImpl::Print() {
  if (CEF_CURRENTLY_ON_UIT()) {
803 804
    content::WebContents* actionable_contents = GetActionableWebContents();
    if (!actionable_contents)
805
      return;
806 807
    printing::CefPrintViewManager::FromWebContents(actionable_contents)
        ->PrintNow(actionable_contents->GetRenderViewHost()->GetMainFrame());
808
  } else {
809
    CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostImpl::Print, this));
810 811 812
  }
}

813 814 815 816
void CefBrowserHostImpl::PrintToPDF(const CefString& path,
                                    const CefPdfPrintSettings& settings,
                                    CefRefPtr<CefPdfPrintCallback> callback) {
  if (CEF_CURRENTLY_ON_UIT()) {
817 818
    content::WebContents* actionable_contents = GetActionableWebContents();
    if (!actionable_contents)
819 820
      return;

821
    printing::CefPrintViewManager::PdfPrintCallback pdf_callback;
822 823 824 825
    if (callback.get()) {
      pdf_callback = base::Bind(&CefPdfPrintCallback::OnPdfPrintFinished,
                                callback.get(), path);
    }
826 827 828
    printing::CefPrintViewManager::FromWebContents(actionable_contents)
        ->PrintToPDF(actionable_contents->GetMainFrame(), base::FilePath(path),
                     settings, pdf_callback);
829
  } else {
830 831
    CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostImpl::PrintToPDF, this,
                                          path, settings, callback));
832 833 834
  }
}

835 836 837 838 839
void CefBrowserHostImpl::Find(int identifier,
                              const CefString& searchText,
                              bool forward,
                              bool matchCase,
                              bool findNext) {
840
  if (CEF_CURRENTLY_ON_UIT()) {
841
    if (!web_contents())
842 843
      return;

844 845 846 847 848 849 850 851
    // Every find request must have a unique ID and these IDs must strictly
    // increase so that newer requests always have greater IDs than older
    // requests.
    if (identifier <= find_request_id_counter_)
      identifier = ++find_request_id_counter_;
    else
      find_request_id_counter_ = identifier;

852 853 854 855 856
    auto options = blink::mojom::FindOptions::New();
    options->forward = forward;
    options->match_case = matchCase;
    options->find_next = findNext;
    web_contents()->Find(identifier, searchText, std::move(options));
857 858
  } else {
    CEF_POST_TASK(CEF_UIT,
859 860
                  base::BindOnce(&CefBrowserHostImpl::Find, this, identifier,
                                 searchText, forward, matchCase, findNext));
861 862 863 864 865
  }
}

void CefBrowserHostImpl::StopFinding(bool clearSelection) {
  if (CEF_CURRENTLY_ON_UIT()) {
866
    if (!web_contents())
867 868
      return;

869 870 871
    content::StopFindAction action =
        clearSelection ? content::STOP_FIND_ACTION_CLEAR_SELECTION
                       : content::STOP_FIND_ACTION_KEEP_SELECTION;
872
    web_contents()->StopFinding(action);
873
  } else {
874 875
    CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefBrowserHostImpl::StopFinding,
                                          this, clearSelection));
876 877 878
  }
}

879 880 881 882
void CefBrowserHostImpl::ShowDevTools(const CefWindowInfo& windowInfo,
                                      CefRefPtr<CefClient> client,
                                      const CefBrowserSettings& settings,
                                      const CefPoint& inspect_element_at) {
883
  if (CEF_CURRENTLY_ON_UIT()) {
884
    if (!web_contents())
885 886 887
      return;

    if (devtools_frontend_) {
888 889 890 891
      if (!inspect_element_at.IsEmpty()) {
        devtools_frontend_->InspectElementAt(inspect_element_at.x,
                                             inspect_element_at.y);
      }
892 893 894 895 896
      devtools_frontend_->Focus();
      return;
    }

    devtools_frontend_ = CefDevToolsFrontend::Show(
897
        this, windowInfo, client, settings, inspect_element_at);
898 899 900
    devtools_observer_.reset(new DevToolsWebContentsObserver(
        this, devtools_frontend_->frontend_browser()->web_contents()));
  } else {
901 902
    ShowDevToolsHelper* helper = new ShowDevToolsHelper(
        this, windowInfo, client, settings, inspect_element_at);
903
    CEF_POST_TASK(CEF_UIT, base::BindOnce(ShowDevToolsWithHelper, helper));
904 905 906 907 908 909 910 911 912 913
  }
}

void CefBrowserHostImpl::CloseDevTools() {
  if (CEF_CURRENTLY_ON_UIT()) {
    if (!devtools_frontend_)
      return;
    devtools_frontend_->Close();
  } else {
    CEF_POST_TASK(CEF_UIT,
914
                  base::BindOnce(&CefBrowserHostImpl::CloseDevTools, this));
915 916 917
  }
}

918 919 920 921 922 923 924 925 926
bool CefBrowserHostImpl::HasDevTools() {
  if (!CEF_CURRENTLY_ON_UIT()) {
    NOTREACHED() << "called on invalid thread";
    return false;
  }

  return (devtools_frontend_ != nullptr);
}

927 928 929 930 931 932