mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-01-22 15:29:56 +01:00
e411b513be
See the new cef_frame_handler.h for complete usage documentation. This change includes the following related enhancements: - The newly added CefBrowser::IsValid method will return false (in the browser process) after CefLifeSpanHandler::OnBeforeClose is called. - CefBrowser::GetMainFrame will return a valid object (in the browser process) until after CefLifeSpanHandler::OnBeforeClose is called. - The main frame object will change during cross-origin navigation or re-navigation after renderer process termination. During that time, GetMainFrame will return the new/pending frame (in the browser process) and any messages that arrive for the new/pending frame will be correctly attributed in OnProcessMessageReceived. - Commands to be executed in the renderer process that may fail during early frame initialization (ExecuteJavaScript, LoadRequest, etc.) will now be queued until after the JavaScript context for the frame has been created. - Logging has been added for any commands that are dropped because they arrived after frame detachment.
404 lines
12 KiB
C++
404 lines
12 KiB
C++
// 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/renderer/browser_impl.h"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "libcef/common/app_manager.h"
|
|
#include "libcef/renderer/blink_glue.h"
|
|
#include "libcef/renderer/render_frame_util.h"
|
|
#include "libcef/renderer/render_manager.h"
|
|
#include "libcef/renderer/thread_util.h"
|
|
|
|
#include "base/strings/string_util.h"
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "content/public/renderer/document_state.h"
|
|
#include "content/public/renderer/render_frame.h"
|
|
#include "content/public/renderer/render_view.h"
|
|
#include "content/renderer/navigation_state.h"
|
|
#include "third_party/blink/public/platform/web_string.h"
|
|
#include "third_party/blink/public/platform/web_url_error.h"
|
|
#include "third_party/blink/public/platform/web_url_response.h"
|
|
#include "third_party/blink/public/web/web_document.h"
|
|
#include "third_party/blink/public/web/web_frame.h"
|
|
#include "third_party/blink/public/web/web_frame_content_dumper.h"
|
|
#include "third_party/blink/public/web/web_local_frame.h"
|
|
#include "third_party/blink/public/web/web_security_policy.h"
|
|
#include "third_party/blink/public/web/web_view.h"
|
|
|
|
// CefBrowserImpl static methods.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// static
|
|
CefRefPtr<CefBrowserImpl> CefBrowserImpl::GetBrowserForView(
|
|
content::RenderView* view) {
|
|
return CefRenderManager::Get()->GetBrowserForView(view);
|
|
}
|
|
|
|
// static
|
|
CefRefPtr<CefBrowserImpl> CefBrowserImpl::GetBrowserForMainFrame(
|
|
blink::WebFrame* frame) {
|
|
return CefRenderManager::Get()->GetBrowserForMainFrame(frame);
|
|
}
|
|
|
|
// CefBrowser methods.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
bool CefBrowserImpl::IsValid() {
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
return !!GetWebView();
|
|
}
|
|
|
|
CefRefPtr<CefBrowserHost> CefBrowserImpl::GetHost() {
|
|
NOTREACHED() << "GetHost cannot be called from the render process";
|
|
return nullptr;
|
|
}
|
|
|
|
bool CefBrowserImpl::CanGoBack() {
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
|
|
return blink_glue::CanGoBack(GetWebView());
|
|
}
|
|
|
|
void CefBrowserImpl::GoBack() {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
blink_glue::GoBack(GetWebView());
|
|
}
|
|
|
|
bool CefBrowserImpl::CanGoForward() {
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
|
|
return blink_glue::CanGoForward(GetWebView());
|
|
}
|
|
|
|
void CefBrowserImpl::GoForward() {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
blink_glue::GoForward(GetWebView());
|
|
}
|
|
|
|
bool CefBrowserImpl::IsLoading() {
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
|
|
if (GetWebView()) {
|
|
blink::WebFrame* main_frame = GetWebView()->MainFrame();
|
|
if (main_frame)
|
|
return main_frame->ToWebLocalFrame()->IsLoading();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CefBrowserImpl::Reload() {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
if (GetWebView()) {
|
|
blink::WebFrame* main_frame = GetWebView()->MainFrame();
|
|
if (main_frame && main_frame->IsWebLocalFrame()) {
|
|
main_frame->ToWebLocalFrame()->StartReload(
|
|
blink::WebFrameLoadType::kReload);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CefBrowserImpl::ReloadIgnoreCache() {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
if (GetWebView()) {
|
|
blink::WebFrame* main_frame = GetWebView()->MainFrame();
|
|
if (main_frame && main_frame->IsWebLocalFrame()) {
|
|
main_frame->ToWebLocalFrame()->StartReload(
|
|
blink::WebFrameLoadType::kReloadBypassingCache);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CefBrowserImpl::StopLoad() {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
if (GetWebView()) {
|
|
blink::WebFrame* main_frame = GetWebView()->MainFrame();
|
|
if (main_frame && main_frame->IsWebLocalFrame()) {
|
|
main_frame->ToWebLocalFrame()->DeprecatedStopLoading();
|
|
}
|
|
}
|
|
}
|
|
|
|
int CefBrowserImpl::GetIdentifier() {
|
|
CEF_REQUIRE_RT_RETURN(0);
|
|
|
|
return browser_id();
|
|
}
|
|
|
|
bool CefBrowserImpl::IsSame(CefRefPtr<CefBrowser> that) {
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
|
|
CefBrowserImpl* impl = static_cast<CefBrowserImpl*>(that.get());
|
|
return (impl == this);
|
|
}
|
|
|
|
bool CefBrowserImpl::IsPopup() {
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
|
|
return is_popup();
|
|
}
|
|
|
|
bool CefBrowserImpl::HasDocument() {
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
|
|
if (GetWebView()) {
|
|
blink::WebFrame* main_frame = GetWebView()->MainFrame();
|
|
if (main_frame && main_frame->IsWebLocalFrame()) {
|
|
return !main_frame->ToWebLocalFrame()->GetDocument().IsNull();
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefBrowserImpl::GetMainFrame() {
|
|
CEF_REQUIRE_RT_RETURN(nullptr);
|
|
|
|
if (GetWebView()) {
|
|
blink::WebFrame* main_frame = GetWebView()->MainFrame();
|
|
if (main_frame && main_frame->IsWebLocalFrame()) {
|
|
return GetWebFrameImpl(main_frame->ToWebLocalFrame()).get();
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefBrowserImpl::GetFocusedFrame() {
|
|
CEF_REQUIRE_RT_RETURN(nullptr);
|
|
|
|
if (GetWebView() && GetWebView()->FocusedFrame()) {
|
|
return GetWebFrameImpl(GetWebView()->FocusedFrame()).get();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefBrowserImpl::GetFrame(int64 identifier) {
|
|
CEF_REQUIRE_RT_RETURN(nullptr);
|
|
|
|
return GetWebFrameImpl(identifier).get();
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefBrowserImpl::GetFrame(const CefString& name) {
|
|
CEF_REQUIRE_RT_RETURN(nullptr);
|
|
|
|
blink::WebView* web_view = GetWebView();
|
|
if (web_view) {
|
|
const blink::WebString& frame_name =
|
|
blink::WebString::FromUTF16(name.ToString16());
|
|
// Search by assigned frame name (Frame::name).
|
|
blink::WebFrame* frame = web_view->MainFrame();
|
|
if (frame && frame->IsWebLocalFrame())
|
|
frame = frame->ToWebLocalFrame()->FindFrameByName(frame_name);
|
|
if (!frame) {
|
|
// Search by unique frame name (Frame::uniqueName).
|
|
const std::string& searchname = name;
|
|
for (blink::WebFrame* cur_frame = web_view->MainFrame(); cur_frame;
|
|
cur_frame = cur_frame->TraverseNext()) {
|
|
if (cur_frame->IsWebLocalFrame() &&
|
|
render_frame_util::GetName(cur_frame->ToWebLocalFrame()) ==
|
|
searchname) {
|
|
frame = cur_frame;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (frame && frame->IsWebLocalFrame())
|
|
return GetWebFrameImpl(frame->ToWebLocalFrame()).get();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
size_t CefBrowserImpl::GetFrameCount() {
|
|
CEF_REQUIRE_RT_RETURN(0);
|
|
|
|
int count = 0;
|
|
|
|
if (GetWebView()) {
|
|
for (blink::WebFrame* frame = GetWebView()->MainFrame(); frame;
|
|
frame = frame->TraverseNext()) {
|
|
count++;
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
void CefBrowserImpl::GetFrameIdentifiers(std::vector<int64>& identifiers) {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
if (identifiers.size() > 0)
|
|
identifiers.clear();
|
|
|
|
if (GetWebView()) {
|
|
for (blink::WebFrame* frame = GetWebView()->MainFrame(); frame;
|
|
frame = frame->TraverseNext()) {
|
|
if (frame->IsWebLocalFrame())
|
|
identifiers.push_back(
|
|
render_frame_util::GetIdentifier(frame->ToWebLocalFrame()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void CefBrowserImpl::GetFrameNames(std::vector<CefString>& names) {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
if (names.size() > 0)
|
|
names.clear();
|
|
|
|
if (GetWebView()) {
|
|
for (blink::WebFrame* frame = GetWebView()->MainFrame(); frame;
|
|
frame = frame->TraverseNext()) {
|
|
if (frame->IsWebLocalFrame())
|
|
names.push_back(render_frame_util::GetName(frame->ToWebLocalFrame()));
|
|
}
|
|
}
|
|
}
|
|
|
|
// CefBrowserImpl public methods.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
CefBrowserImpl::CefBrowserImpl(content::RenderView* render_view,
|
|
int browser_id,
|
|
bool is_popup,
|
|
bool is_windowless)
|
|
: blink::WebViewObserver(render_view->GetWebView()),
|
|
browser_id_(browser_id),
|
|
is_popup_(is_popup),
|
|
is_windowless_(is_windowless) {}
|
|
|
|
CefBrowserImpl::~CefBrowserImpl() {}
|
|
|
|
CefRefPtr<CefFrameImpl> CefBrowserImpl::GetWebFrameImpl(
|
|
blink::WebLocalFrame* frame) {
|
|
DCHECK(frame);
|
|
int64_t frame_id = render_frame_util::GetIdentifier(frame);
|
|
|
|
// Frames are re-used between page loads. Only add the frame to the map once.
|
|
FrameMap::const_iterator it = frames_.find(frame_id);
|
|
if (it != frames_.end())
|
|
return it->second;
|
|
|
|
CefRefPtr<CefFrameImpl> framePtr(new CefFrameImpl(this, frame, frame_id));
|
|
frames_.insert(std::make_pair(frame_id, framePtr));
|
|
|
|
return framePtr;
|
|
}
|
|
|
|
CefRefPtr<CefFrameImpl> CefBrowserImpl::GetWebFrameImpl(int64_t frame_id) {
|
|
if (frame_id == blink_glue::kInvalidFrameId) {
|
|
if (GetWebView()) {
|
|
blink::WebFrame* main_frame = GetWebView()->MainFrame();
|
|
if (main_frame && main_frame->IsWebLocalFrame()) {
|
|
return GetWebFrameImpl(main_frame->ToWebLocalFrame());
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Check if we already know about the frame.
|
|
FrameMap::const_iterator it = frames_.find(frame_id);
|
|
if (it != frames_.end())
|
|
return it->second;
|
|
|
|
if (GetWebView()) {
|
|
// Check if the frame exists but we don't know about it yet.
|
|
for (blink::WebFrame* frame = GetWebView()->MainFrame(); frame;
|
|
frame = frame->TraverseNext()) {
|
|
if (frame->IsWebLocalFrame() &&
|
|
render_frame_util::GetIdentifier(frame->ToWebLocalFrame()) ==
|
|
frame_id) {
|
|
return GetWebFrameImpl(frame->ToWebLocalFrame());
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void CefBrowserImpl::AddFrameObject(int64_t frame_id,
|
|
CefTrackNode* tracked_object) {
|
|
CefRefPtr<CefTrackManager> manager;
|
|
|
|
if (!frame_objects_.empty()) {
|
|
FrameObjectMap::const_iterator it = frame_objects_.find(frame_id);
|
|
if (it != frame_objects_.end())
|
|
manager = it->second;
|
|
}
|
|
|
|
if (!manager.get()) {
|
|
manager = new CefTrackManager();
|
|
frame_objects_.insert(std::make_pair(frame_id, manager));
|
|
}
|
|
|
|
manager->Add(tracked_object);
|
|
}
|
|
|
|
// RenderViewObserver methods.
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void CefBrowserImpl::OnDestruct() {
|
|
// Notify that the browser window has been destroyed.
|
|
CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
|
|
if (app.get()) {
|
|
CefRefPtr<CefRenderProcessHandler> handler = app->GetRenderProcessHandler();
|
|
if (handler.get())
|
|
handler->OnBrowserDestroyed(this);
|
|
}
|
|
|
|
CefRenderManager::Get()->OnBrowserDestroyed(this);
|
|
}
|
|
|
|
void CefBrowserImpl::FrameDetached(int64_t frame_id) {
|
|
if (!frames_.empty()) {
|
|
// Remove the frame from the map.
|
|
FrameMap::iterator it = frames_.find(frame_id);
|
|
if (it != frames_.end()) {
|
|
frames_.erase(it);
|
|
}
|
|
}
|
|
|
|
if (!frame_objects_.empty()) {
|
|
// Remove any tracked objects associated with the frame.
|
|
FrameObjectMap::iterator it = frame_objects_.find(frame_id);
|
|
if (it != frame_objects_.end())
|
|
frame_objects_.erase(it);
|
|
}
|
|
}
|
|
|
|
void CefBrowserImpl::OnLoadingStateChange(bool isLoading) {
|
|
CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
|
|
if (app.get()) {
|
|
CefRefPtr<CefRenderProcessHandler> handler = app->GetRenderProcessHandler();
|
|
if (handler.get()) {
|
|
CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
|
|
if (load_handler.get()) {
|
|
blink::WebView* web_view = GetWebView();
|
|
const bool canGoBack = blink_glue::CanGoBack(web_view);
|
|
const bool canGoForward = blink_glue::CanGoForward(web_view);
|
|
|
|
// Don't call OnLoadingStateChange multiple times with the same status.
|
|
// This can occur in cases where there are multiple highest-level
|
|
// LocalFrames in-process for the same browser.
|
|
if (last_loading_state_ &&
|
|
last_loading_state_->IsMatch(isLoading, canGoBack, canGoForward)) {
|
|
return;
|
|
}
|
|
|
|
load_handler->OnLoadingStateChange(this, isLoading, canGoBack,
|
|
canGoForward);
|
|
last_loading_state_.reset(
|
|
new LoadingState(isLoading, canGoBack, canGoForward));
|
|
}
|
|
}
|
|
}
|
|
}
|