cef/libcef/browser/browser_info.h
Marshall Greenblatt dca0435d2f chrome: Add support for Alloy style browsers and windows (see #3681)
Split the Alloy runtime into bootstrap and style components. Support
creation of Alloy style browsers and windows with the Chrome runtime.
Chrome runtime (`--enable-chrome-runtime`) + Alloy style
(`--use-alloy-style`) supports Views (`--use-views`), native parent
(`--use-native`) and windowless rendering
(`--off-screen-rendering-enabled`).

Print preview is supported in all cases except with windowless rendering
on all platforms and native parent on MacOS. It is disabled by default
with Alloy style for legacy compatibility. Where supported it can be
enabled or disabled globally using `--[enable|disable]-print-preview` or
configured on a per-RequestContext basis using the
`printing.print_preview_disabled` preference. It also behaves as
expected when triggered via the PDF viewer print button.

Chrome runtime + Alloy style behavior differs from Alloy runtime in the
following significant ways:

- Supports Chrome error pages by default.
- DevTools popups are Chrome style only (cannot be windowless).
- The Alloy extension API will not supported.

Chrome runtime + Alloy style passes all expected Alloy ceftests except
the following:

- `DisplayTest.AutoResize` (Alloy extension API not supported)
- `DownloadTest.*` (Download API not yet supported)
- `ExtensionTest.*` (Alloy extension API not supported)

This change also adds Chrome runtime support for
CefContextMenuHandler::RunContextMenu (see #3293).

This change also explicitly blocks (and doesn't retry) FrameAttached
requests from PDF viewer and print preview excluded frames (see #3664).

Known issues specific to Chrome runtime + Alloy style:
- DevTools popup with windowless rendering doesn't load successfully.
  Use windowed rendering or remote debugging as a workaround.
- Chrome style Window with Alloy style BrowserView (`--use-alloy-style
  --use-chrome-style-window`) does not show Chrome theme changes.

To test:
- Run `ceftests --enable-chrome-runtime --use-alloy-style
       [--use-chrome-style-window] [--use-views|--use-native]
       --gtest_filter=...`
- Run `cefclient --enable-chrome-runtime --use-alloy-style
       [--use-chrome-style-window]
       [--use-views|--use-native|--off-screen-rendering-enabled]`
- Run `cefsimple --enable-chrome-runtime --use-alloy-style [--use-views]`
2024-04-22 14:57:37 -04:00

274 lines
11 KiB
C++

// Copyright (c) 2012 The Chromium Embedded Framework 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 CEF_LIBCEF_BROWSER_BROWSER_INFO_H_
#define CEF_LIBCEF_BROWSER_BROWSER_INFO_H_
#pragma once
#include <queue>
#include <set>
#include <unordered_map>
#include "include/internal/cef_ptr.h"
#include "libcef/common/values_impl.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/functional/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/synchronization/lock.h"
#include "base/values.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/render_frame_host.h"
class CefBrowserHostBase;
class CefFrameHandler;
class CefFrameHostImpl;
// CefBrowserInfo is used to associate a browser ID and render view/process
// IDs with a particular CefBrowserHostBase. Render view/process IDs may change
// during the lifetime of a single CefBrowserHostBase.
//
// CefBrowserInfo objects are managed by CefBrowserInfoManager and should not be
// created directly.
class CefBrowserInfo : public base::RefCountedThreadSafe<CefBrowserInfo> {
public:
CefBrowserInfo(int browser_id,
bool is_popup,
bool is_windowless,
bool print_preview_enabled,
CefRefPtr<CefDictionaryValue> extra_info);
CefBrowserInfo(const CefBrowserInfo&) = delete;
CefBrowserInfo& operator=(const CefBrowserInfo&) = delete;
int browser_id() const { return browser_id_; }
bool is_popup() const { return is_popup_; }
bool is_windowless() const { return is_windowless_; }
bool print_preview_enabled() const { return print_preview_enabled_; }
CefRefPtr<CefDictionaryValue> extra_info() const { return extra_info_; }
// May return NULL if the browser has not yet been created or if the browser
// has been destroyed.
CefRefPtr<CefBrowserHostBase> browser() const;
// Set or clear the browser. Called from CefBrowserHostBase InitializeBrowser
// (to set) and DestroyBrowser (to clear).
void SetBrowser(CefRefPtr<CefBrowserHostBase> browser);
// Called after OnBeforeClose and before SetBrowser(nullptr). This will cause
// browser() and GetMainFrame() to return nullptr as expected by
// CefFrameHandler callbacks. Note that this differs from calling
// SetBrowser(nullptr) because the WebContents has not yet been destroyed and
// further frame-related callbacks are expected.
void SetClosing();
// Ensure that a frame record exists for |host|. Called for the main frame
// when the RenderView is created, or for a sub-frame when the associated
// RenderFrame is created in the renderer process.
// Called from CefBrowserContentsDelegate::RenderFrameCreated (is_guest_view =
// false) or CefMimeHandlerViewGuestDelegate::OnGuestAttached (is_guest_view =
// true).
void MaybeCreateFrame(content::RenderFrameHost* host, bool is_guest_view);
// Used to track state changes such as entering/exiting the BackForwardCache.
// Called from CefBrowserContentsDelegate::RenderFrameHostStateChanged.
void FrameHostStateChanged(
content::RenderFrameHost* host,
content::RenderFrameHost::LifecycleState old_state,
content::RenderFrameHost::LifecycleState new_state);
// Remove the frame record for |host|. Called for the main frame when the
// RenderView is destroyed, or for a sub-frame when the associated RenderFrame
// is destroyed in the renderer process.
// Called from CefBrowserContentsDelegate::RenderFrameDeleted or
// CefMimeHandlerViewGuestDelegate::OnGuestDetached.
void RemoveFrame(content::RenderFrameHost* host);
// Returns the main frame object. This object will remain valid until the
// browser is destroyed even though the indentifier may change with cross-
// origin navigations. Furthermore, calling LoadURL on this object will always
// behave as expected because the call is routed through the browser's
// NavigationController.
CefRefPtr<CefFrameHostImpl> GetMainFrame();
// Creates a temporary sub-frame object for situations during navigation or
// resource loading where a RFH does not yet exist. If |parent_frame_id|
// is invalid the current main frame will be specified as the parent.
// Temporary frame objects are not tracked but will be implicitly detached
// on browser destruction.
CefRefPtr<CefFrameHostImpl> CreateTempSubFrame(
const content::GlobalRenderFrameHostId& parent_global_id);
// Returns the frame object matching the specified host or nullptr if no match
// is found. Nullptr will also be returned if a guest view match is found
// because we don't create frame objects for guest views. If |is_guest_view|
// is non-nullptr it will be set to true in this case. Must be called on the
// UI thread.
CefRefPtr<CefFrameHostImpl> GetFrameForHost(
const content::RenderFrameHost* host,
bool* is_guest_view = nullptr,
bool prefer_speculative = false) const;
// Returns the frame object matching the specified ID/token or nullptr if no
// match is found. Nullptr will also be returned if a guest view match is
// found because we don't create frame objects for guest views. If
// |is_guest_view| is non-nullptr it will be set to true in this case. Safe to
// call from any thread.
CefRefPtr<CefFrameHostImpl> GetFrameForGlobalId(
const content::GlobalRenderFrameHostId& global_id,
bool* is_guest_view = nullptr,
bool prefer_speculative = false) const;
CefRefPtr<CefFrameHostImpl> GetFrameForGlobalToken(
const content::GlobalRenderFrameHostToken& global_token,
bool* is_guest_view = nullptr,
bool prefer_speculative = false) const;
// Returns all non-speculative frame objects that currently exist. Guest views
// will be excluded because they don't have a frame object. Safe to call from
// any thread.
using FrameHostList = std::set<CefRefPtr<CefFrameHostImpl>>;
FrameHostList GetAllFrames() const;
class NavigationLock final : public base::RefCounted<NavigationLock> {
private:
friend class CefBrowserInfo;
friend class base::RefCounted<NavigationLock>;
// All usage is via friend declaration. NOLINTNEXTLINE
NavigationLock();
// All usage is via friend declaration. NOLINTNEXTLINE
~NavigationLock();
base::OnceClosure pending_action_;
base::WeakPtrFactory<NavigationLock> weak_ptr_factory_;
};
// Block navigation actions on NavigationLock life span. Must be called on the
// UI thread.
scoped_refptr<NavigationLock> CreateNavigationLock();
// Returns true if navigation actions are currently blocked. If this method
// returns true the most recent |pending_action| will be executed on the UI
// thread once the navigation lock is released. Must be called on the UI
// thread.
bool IsNavigationLocked(base::OnceClosure pending_action);
using FrameNotifyOnceAction =
base::OnceCallback<void(CefRefPtr<CefFrameHandler>)>;
// Specifies a CefFrameHandler notification action whose execution may need
// to be blocked on release of a potentially held NotificationStateLock. If no
// CefFrameHandler exists then the action will be discarded without executing.
// If the NotificationStateLock is not currently held then the action will be
// executed immediately.
void MaybeExecuteFrameNotification(FrameNotifyOnceAction pending_action);
void MaybeNotifyDraggableRegionsChanged(
CefRefPtr<CefBrowserHostBase> browser,
CefRefPtr<CefFrameHostImpl> frame,
std::vector<CefDraggableRegion> draggable_regions);
private:
friend class base::RefCountedThreadSafe<CefBrowserInfo>;
virtual ~CefBrowserInfo();
struct FrameInfo {
~FrameInfo();
inline bool IsCurrentMainFrame() const {
return frame_ && is_main_frame_ && !is_speculative_ && !is_in_bfcache_;
}
content::RenderFrameHost* host_;
content::GlobalRenderFrameHostId global_id_;
bool is_guest_view_;
bool is_main_frame_;
bool is_speculative_;
bool is_in_bfcache_ = false;
CefRefPtr<CefFrameHostImpl> frame_;
};
void SetMainFrame(CefRefPtr<CefBrowserHostBase> browser,
CefRefPtr<CefFrameHostImpl> frame);
void MaybeNotifyFrameCreated(CefRefPtr<CefFrameHostImpl> frame);
void MaybeNotifyFrameDetached(CefRefPtr<CefBrowserHostBase> browser,
CefRefPtr<CefFrameHostImpl> frame);
void MaybeNotifyMainFrameChanged(CefRefPtr<CefBrowserHostBase> browser,
CefRefPtr<CefFrameHostImpl> old_frame,
CefRefPtr<CefFrameHostImpl> new_frame);
void RemoveAllFrames(CefRefPtr<CefBrowserHostBase> old_browser);
const int browser_id_;
const bool is_popup_;
const bool is_windowless_;
const bool print_preview_enabled_;
CefRefPtr<CefDictionaryValue> extra_info_;
// Navigation will be blocked while |navigation_lock_| exists.
// Only accessed on the UI thread.
base::WeakPtr<NavigationLock> navigation_lock_;
// Used instead of |base::AutoLock(lock_)| in situations that might generate
// CefFrameHandler notifications. Any notifications passed to
// MaybeExecuteFrameNotification() will be queued until the lock is released,
// and then executed in order. Only accessed on the UI thread.
class NotificationStateLock final {
public:
explicit NotificationStateLock(CefBrowserInfo* browser_info);
~NotificationStateLock();
protected:
friend class CefBrowserInfo;
CefBrowserInfo* const browser_info_;
CefRefPtr<CefFrameHandler> frame_handler_;
std::unique_ptr<base::AutoLock> browser_info_lock_scope_;
std::queue<FrameNotifyOnceAction> queue_;
};
mutable base::Lock notification_lock_;
// These members must be protected by |notification_lock_|.
NotificationStateLock* notification_state_lock_ = nullptr;
CefRefPtr<CefFrameHandler> frame_handler_;
mutable base::Lock lock_;
// The below members must be protected by |lock_|.
CefRefPtr<CefBrowserHostBase> browser_;
// Owner of FrameInfo structs.
using FrameInfoSet =
std::set<std::unique_ptr<FrameInfo>, base::UniquePtrComparator>;
FrameInfoSet frame_info_set_;
// Map a global ID to one frame. These IDs are guaranteed to uniquely
// identify a RFH for its complete lifespan. See documentation on
// RenderFrameHost::GetFrameTreeNodeId() for background.
using FrameIDMap = std::unordered_map<content::GlobalRenderFrameHostId,
FrameInfo*,
content::GlobalRenderFrameHostIdHasher>;
FrameIDMap frame_id_map_;
// Map of global token to global ID.
using FrameTokenToIdMap = std::map<content::GlobalRenderFrameHostToken,
content::GlobalRenderFrameHostId>;
FrameTokenToIdMap frame_token_to_id_map_;
// The current main frame.
CefRefPtr<CefFrameHostImpl> main_frame_;
// True if the browser is currently closing.
bool is_closing_ = false;
// Only accessed on the UI thread.
std::vector<CefDraggableRegion> draggable_regions_;
};
#endif // CEF_LIBCEF_BROWSER_BROWSER_INFO_H_