bool CefBrowserInfoManager::CanCreateWindow()

in libcef/browser/browser_info_manager.cc [106:207]


bool CefBrowserInfoManager::CanCreateWindow(
    content::RenderFrameHost* opener,
    const GURL& target_url,
    const content::Referrer& referrer,
    const std::string& frame_name,
    WindowOpenDisposition disposition,
    const blink::mojom::WindowFeatures& features,
    bool user_gesture,
    bool opener_suppressed,
    bool* no_javascript_access) {
  CEF_REQUIRE_UIT();

  content::OpenURLParams params(target_url, referrer, disposition,
                                ui::PAGE_TRANSITION_LINK,
                                /*is_renderer_initiated=*/true);
  params.user_gesture = user_gesture;

  CefRefPtr<CefBrowserHostBase> browser;
  if (!MaybeAllowNavigation(opener, params, browser) || !browser) {
    // Cancel the popup.
    return false;
  }

  CefRefPtr<CefClient> client = browser->GetClient();
  bool allow = true;

  std::unique_ptr<CefWindowInfo> window_info(new CefWindowInfo);

#if defined(OS_WIN)
  window_info->SetAsPopup(nullptr, CefString());
#endif

  auto pending_popup = std::make_unique<CefBrowserInfoManager::PendingPopup>();
  pending_popup->step = CefBrowserInfoManager::PendingPopup::CAN_CREATE_WINDOW;
  pending_popup->opener_global_id = opener->GetGlobalId();
  pending_popup->target_url = target_url;
  pending_popup->target_frame_name = frame_name;

  // Start with the current browser's settings.
  pending_popup->client = client;
  pending_popup->settings = browser->settings();

  if (client.get()) {
    CefRefPtr<CefLifeSpanHandler> handler = client->GetLifeSpanHandler();
    if (handler.get()) {
      CefRefPtr<CefFrame> opener_frame = browser->GetFrameForHost(opener);
      DCHECK(opener_frame);

      CefPopupFeatures cef_features;
      TranslatePopupFeatures(features, cef_features);

#if (defined(OS_WIN) || defined(OS_MAC))
      // Default to the size from the popup features.
      if (cef_features.xSet)
        window_info->bounds.x = cef_features.x;
      if (cef_features.ySet)
        window_info->bounds.y = cef_features.y;
      if (cef_features.widthSet)
        window_info->bounds.width = cef_features.width;
      if (cef_features.heightSet)
        window_info->bounds.height = cef_features.height;
#endif

      allow = !handler->OnBeforePopup(
          browser.get(), opener_frame, pending_popup->target_url.spec(),
          pending_popup->target_frame_name,
          static_cast<cef_window_open_disposition_t>(disposition), user_gesture,
          cef_features, *window_info, pending_popup->client,
          pending_popup->settings, pending_popup->extra_info,
          no_javascript_access);
    }
  }

  if (allow) {
    CefBrowserCreateParams create_params;

    if (browser->HasView()) {
      create_params.popup_with_views_hosted_opener = true;
    } else {
      create_params.window_info = std::move(window_info);
    }

    create_params.settings = pending_popup->settings;
    create_params.client = pending_popup->client;
    create_params.extra_info = pending_popup->extra_info;

    pending_popup->platform_delegate =
        CefBrowserPlatformDelegate::Create(create_params);
    CHECK(pending_popup->platform_delegate.get());

    // Between the calls to CanCreateWindow and GetCustomWebContentsView
    // RenderViewHostImpl::CreateNewWindow() will call
    // RenderProcessHostImpl::FilterURL() which, in the case of "javascript:"
    // URIs, rewrites the URL to "about:blank". We need to apply the same filter
    // otherwise GetCustomWebContentsView will fail to retrieve the PopupInfo.
    opener->GetProcess()->FilterURL(false, &pending_popup->target_url);

    PushPendingPopup(std::move(pending_popup));
  }

  return allow;
}