mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02:00
chrome: Update expectations with same-site BFCache enabled (fixes issue #3301)
With same-site BFCache enabled every navigation can now potentially be served via the BFCache. To support this internally a new top-level RenderFrame object may be created for each new navigation. As a result, OnBrowserCreated may now be called multiple times with the same browser ID in a given renderer process (a behavior previously only seen with cross-site navigations and different renderer processes). BFCache navigations do not trigger the same Chromium notifications as a normal load. To avoid breaking CEF API usage expectations we now synthetically generate the load-related callbacks that would otherwise be missing (OnLoadingStateChange with isLoading=true, OnLoadStart, OnLoadEnd). The |httpStatusCode| argument to OnLoadEnd will be 0 in this case. To test: - Run `FrameHandlerTest.*:MessageRouterTest.*:NavigationTest.*` - Run `NavigationTest.LoadSameOriginLoadURL` for OnBrowserCreated behavior. - Run `NavigationTest.History` for load-related callback behavior.
This commit is contained in:
@@ -22,6 +22,8 @@
|
||||
#include "third_party/blink/renderer/core/dom/element.h"
|
||||
#include "third_party/blink/renderer/core/dom/node.h"
|
||||
#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
|
||||
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
|
||||
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_state_observer.h"
|
||||
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
|
||||
#include "third_party/blink/renderer/core/frame/frame_owner.h"
|
||||
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
|
||||
@@ -220,6 +222,43 @@ bool IsScriptForbidden() {
|
||||
return blink::ScriptForbiddenScope::IsScriptForbidden();
|
||||
}
|
||||
|
||||
std::unique_ptr<CefObserverRegistration>
|
||||
RegisterExecutionContextLifecycleStateObserver(
|
||||
v8::Local<v8::Context> context,
|
||||
CefExecutionContextLifecycleStateObserver* observer) {
|
||||
class Observer : public blink::GarbageCollected<Observer>,
|
||||
public blink::ExecutionContextLifecycleStateObserver {
|
||||
public:
|
||||
Observer(blink::ExecutionContext* execution_context,
|
||||
CefExecutionContextLifecycleStateObserver* observer)
|
||||
: blink::ExecutionContextLifecycleStateObserver(execution_context),
|
||||
observer_(observer) {
|
||||
UpdateStateIfNeeded();
|
||||
}
|
||||
|
||||
void ContextLifecycleStateChanged(
|
||||
blink::mojom::blink::FrameLifecycleState state) override {
|
||||
observer_->ContextLifecycleStateChanged(state);
|
||||
}
|
||||
|
||||
void ContextDestroyed() override {}
|
||||
|
||||
private:
|
||||
CefExecutionContextLifecycleStateObserver* observer_;
|
||||
};
|
||||
|
||||
class Registration : public CefObserverRegistration {
|
||||
public:
|
||||
Registration(blink::Persistent<Observer> observer) : observer_(observer) {}
|
||||
|
||||
private:
|
||||
blink::Persistent<Observer> observer_;
|
||||
};
|
||||
|
||||
return std::make_unique<Registration>(blink::MakeGarbageCollected<Observer>(
|
||||
blink::ExecutionContext::From(context), observer));
|
||||
}
|
||||
|
||||
void RegisterURLSchemeAsSupportingFetchAPI(const blink::WebString& scheme) {
|
||||
blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI(scheme);
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "include/internal/cef_types.h"
|
||||
|
||||
#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink-forward.h"
|
||||
#include "third_party/blink/public/platform/web_common.h"
|
||||
#include "v8/include/v8.h"
|
||||
|
||||
@@ -72,6 +73,32 @@ BLINK_EXPORT v8::Local<v8::Value> ExecuteV8ScriptAndReturnValue(
|
||||
|
||||
BLINK_EXPORT bool IsScriptForbidden();
|
||||
|
||||
class BLINK_EXPORT CefObserverRegistration {
|
||||
public:
|
||||
CefObserverRegistration() = default;
|
||||
|
||||
CefObserverRegistration(const CefObserverRegistration&) = delete;
|
||||
CefObserverRegistration& operator=(const CefObserverRegistration&) = delete;
|
||||
|
||||
virtual ~CefObserverRegistration() = default;
|
||||
};
|
||||
|
||||
class BLINK_EXPORT CefExecutionContextLifecycleStateObserver {
|
||||
public:
|
||||
virtual void ContextLifecycleStateChanged(
|
||||
blink::mojom::blink::FrameLifecycleState state) {}
|
||||
|
||||
protected:
|
||||
virtual ~CefExecutionContextLifecycleStateObserver() = default;
|
||||
};
|
||||
|
||||
// Register an ExecutionContextLifecycleStateObserver. Remains registered until
|
||||
// the returned object is destroyed.
|
||||
BLINK_EXPORT std::unique_ptr<CefObserverRegistration>
|
||||
RegisterExecutionContextLifecycleStateObserver(
|
||||
v8::Local<v8::Context> context,
|
||||
CefExecutionContextLifecycleStateObserver* observer);
|
||||
|
||||
BLINK_EXPORT void RegisterURLSchemeAsSupportingFetchAPI(
|
||||
const blink::WebString& scheme);
|
||||
|
||||
|
@@ -393,6 +393,19 @@ void CefBrowserImpl::OnLoadingStateChange(bool isLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (was_in_bfcache_) {
|
||||
// Send the expected callbacks when exiting the BFCache.
|
||||
DCHECK(!isLoading);
|
||||
load_handler->OnLoadingStateChange(this, /*isLoading=*/true,
|
||||
canGoBack, canGoForward);
|
||||
|
||||
auto main_frame = GetMainFrame();
|
||||
load_handler->OnLoadStart(this, main_frame, TT_EXPLICIT);
|
||||
load_handler->OnLoadEnd(this, main_frame, 0);
|
||||
|
||||
was_in_bfcache_ = false;
|
||||
}
|
||||
|
||||
load_handler->OnLoadingStateChange(this, isLoading, canGoBack,
|
||||
canGoForward);
|
||||
last_loading_state_.reset(
|
||||
@@ -401,3 +414,10 @@ void CefBrowserImpl::OnLoadingStateChange(bool isLoading) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CefBrowserImpl::OnEnterBFCache() {
|
||||
// Reset loading state so that notifications will be resent if/when exiting
|
||||
// BFCache.
|
||||
was_in_bfcache_ = true;
|
||||
last_loading_state_.reset();
|
||||
}
|
||||
|
@@ -92,6 +92,7 @@ class CefBrowserImpl : public CefBrowser, public blink::WebViewObserver {
|
||||
void FrameDetached(int64_t frame_id);
|
||||
|
||||
void OnLoadingStateChange(bool isLoading);
|
||||
void OnEnterBFCache();
|
||||
|
||||
private:
|
||||
// ID of the browser that this RenderView is associated with. During loading
|
||||
@@ -105,6 +106,9 @@ class CefBrowserImpl : public CefBrowser, public blink::WebViewObserver {
|
||||
using FrameMap = std::map<int64, CefRefPtr<CefFrameImpl>>;
|
||||
FrameMap frames_;
|
||||
|
||||
// True if the browser was in the BFCache.
|
||||
bool was_in_bfcache_ = false;
|
||||
|
||||
// Map of unique frame ids to CefTrackManager objects that need to be cleaned
|
||||
// up when the frame is deleted.
|
||||
using FrameObjectMap = std::map<int64, CefRefPtr<CefTrackManager>>;
|
||||
|
@@ -35,6 +35,7 @@
|
||||
#include "content/public/renderer/render_view.h"
|
||||
#include "content/renderer/render_frame_impl.h"
|
||||
#include "third_party/blink/public/mojom/frame/frame.mojom-blink.h"
|
||||
#include "third_party/blink/public/mojom/frame/lifecycle.mojom-blink.h"
|
||||
#include "third_party/blink/public/platform/web_back_forward_cache_loader_helper.h"
|
||||
#include "third_party/blink/public/platform/web_data.h"
|
||||
#include "third_party/blink/public/platform/web_string.h"
|
||||
@@ -390,7 +391,7 @@ void CefFrameImpl::OnDraggableRegionsChanged() {
|
||||
std::move(regions_arg)));
|
||||
}
|
||||
|
||||
void CefFrameImpl::OnContextCreated() {
|
||||
void CefFrameImpl::OnContextCreated(v8::Local<v8::Context> context) {
|
||||
context_created_ = true;
|
||||
|
||||
CHECK(frame_);
|
||||
@@ -399,6 +400,13 @@ void CefFrameImpl::OnContextCreated() {
|
||||
std::move(action.second).Run(frame_);
|
||||
queued_context_actions_.pop();
|
||||
}
|
||||
|
||||
execution_context_lifecycle_state_observer_ =
|
||||
blink_glue::RegisterExecutionContextLifecycleStateObserver(context, this);
|
||||
}
|
||||
|
||||
void CefFrameImpl::OnContextReleased() {
|
||||
execution_context_lifecycle_state_observer_.reset();
|
||||
}
|
||||
|
||||
void CefFrameImpl::OnDetached() {
|
||||
@@ -684,6 +692,14 @@ void CefFrameImpl::MoveOrResizeStarted() {
|
||||
}
|
||||
}
|
||||
|
||||
void CefFrameImpl::ContextLifecycleStateChanged(
|
||||
blink::mojom::blink::FrameLifecycleState state) {
|
||||
if (state == blink::mojom::FrameLifecycleState::kFrozen && IsMain() &&
|
||||
blink_glue::IsInBackForwardCache(frame_)) {
|
||||
browser_->OnEnterBFCache();
|
||||
}
|
||||
}
|
||||
|
||||
// Enable deprecation warnings on Windows. See http://crbug.com/585142.
|
||||
#if BUILDFLAG(IS_WIN)
|
||||
#if defined(__clang__)
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "include/cef_frame.h"
|
||||
#include "include/cef_v8.h"
|
||||
#include "libcef/renderer/blink_glue.h"
|
||||
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/timer/timer.h"
|
||||
@@ -37,7 +38,10 @@ class CefBrowserImpl;
|
||||
// Implementation of CefFrame. CefFrameImpl objects are owned by the
|
||||
// CefBrowerImpl and will be detached when the browser is notified that the
|
||||
// associated renderer WebFrame will close.
|
||||
class CefFrameImpl : public CefFrame, public cef::mojom::RenderFrame {
|
||||
class CefFrameImpl
|
||||
: public CefFrame,
|
||||
public cef::mojom::RenderFrame,
|
||||
public blink_glue::CefExecutionContextLifecycleStateObserver {
|
||||
public:
|
||||
CefFrameImpl(CefBrowserImpl* browser,
|
||||
blink::WebLocalFrame* frame,
|
||||
@@ -90,7 +94,8 @@ class CefFrameImpl : public CefFrame, public cef::mojom::RenderFrame {
|
||||
void OnWasShown();
|
||||
void OnDidFinishLoad();
|
||||
void OnDraggableRegionsChanged();
|
||||
void OnContextCreated();
|
||||
void OnContextCreated(v8::Local<v8::Context> context);
|
||||
void OnContextReleased();
|
||||
void OnDetached();
|
||||
|
||||
blink::WebLocalFrame* web_frame() const { return frame_; }
|
||||
@@ -139,6 +144,10 @@ class CefFrameImpl : public CefFrame, public cef::mojom::RenderFrame {
|
||||
void DidStopLoading() override;
|
||||
void MoveOrResizeStarted() override;
|
||||
|
||||
// blink_glue::CefExecutionContextLifecycleStateObserver methods:
|
||||
void ContextLifecycleStateChanged(
|
||||
blink::mojom::blink::FrameLifecycleState state) override;
|
||||
|
||||
CefBrowserImpl* browser_;
|
||||
blink::WebLocalFrame* frame_;
|
||||
const int64 frame_id_;
|
||||
@@ -168,6 +177,9 @@ class CefFrameImpl : public CefFrame, public cef::mojom::RenderFrame {
|
||||
|
||||
mojo::Remote<cef::mojom::BrowserFrame> browser_frame_;
|
||||
|
||||
std::unique_ptr<blink_glue::CefObserverRegistration>
|
||||
execution_context_lifecycle_state_observer_;
|
||||
|
||||
base::WeakPtrFactory<CefFrameImpl> weak_ptr_factory_{this};
|
||||
|
||||
IMPLEMENT_REFCOUNTING(CefFrameImpl);
|
||||
|
@@ -148,7 +148,7 @@ void CefRenderFrameObserver::DidCreateScriptContext(
|
||||
}
|
||||
|
||||
// Do this last, in case the client callback modified the window object.
|
||||
framePtr->OnContextCreated();
|
||||
framePtr->OnContextCreated(context);
|
||||
}
|
||||
|
||||
void CefRenderFrameObserver::WillReleaseScriptContext(
|
||||
@@ -157,31 +157,32 @@ void CefRenderFrameObserver::WillReleaseScriptContext(
|
||||
blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
|
||||
CefRefPtr<CefBrowserImpl> browserPtr =
|
||||
CefBrowserImpl::GetBrowserForMainFrame(frame->Top());
|
||||
if (browserPtr) {
|
||||
CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
|
||||
if (application) {
|
||||
CefRefPtr<CefRenderProcessHandler> handler =
|
||||
application->GetRenderProcessHandler();
|
||||
if (handler) {
|
||||
CefRefPtr<CefFrameImpl> framePtr = browserPtr->GetWebFrameImpl(frame);
|
||||
if (!browserPtr)
|
||||
return;
|
||||
|
||||
v8::Isolate* isolate = blink::MainThreadIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
CefRefPtr<CefRenderProcessHandler> handler;
|
||||
CefRefPtr<CefApp> application = CefAppManager::Get()->GetApplication();
|
||||
if (application)
|
||||
handler = application->GetRenderProcessHandler();
|
||||
|
||||
// The released context should not be used for script execution.
|
||||
// Depending on how the context is released this may or may not already
|
||||
// be set.
|
||||
blink_glue::CefScriptForbiddenScope forbidScript;
|
||||
CefRefPtr<CefFrameImpl> framePtr = browserPtr->GetWebFrameImpl(frame);
|
||||
|
||||
CefRefPtr<CefV8Context> contextPtr(
|
||||
new CefV8ContextImpl(isolate, context));
|
||||
if (handler) {
|
||||
v8::Isolate* isolate = blink::MainThreadIsolate();
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
|
||||
handler->OnContextReleased(browserPtr.get(), framePtr.get(),
|
||||
contextPtr);
|
||||
}
|
||||
}
|
||||
// The released context should not be used for script execution.
|
||||
// Depending on how the context is released this may or may not already
|
||||
// be set.
|
||||
blink_glue::CefScriptForbiddenScope forbidScript;
|
||||
|
||||
CefRefPtr<CefV8Context> contextPtr(new CefV8ContextImpl(isolate, context));
|
||||
|
||||
handler->OnContextReleased(browserPtr.get(), framePtr.get(), contextPtr);
|
||||
}
|
||||
|
||||
framePtr->OnContextReleased();
|
||||
|
||||
CefV8ReleaseContext(context);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user