2012-04-03 03:34:16 +02:00
|
|
|
// 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.
|
|
|
|
|
2017-05-19 11:06:00 +02:00
|
|
|
#include "libcef/browser/frame_host_impl.h"
|
2019-05-11 00:14:48 +02:00
|
|
|
|
2012-04-03 03:34:16 +02:00
|
|
|
#include "include/cef_request.h"
|
|
|
|
#include "include/cef_stream.h"
|
|
|
|
#include "include/cef_v8.h"
|
2017-05-31 17:33:30 +02:00
|
|
|
#include "include/test/cef_test_helpers.h"
|
2020-09-18 00:24:08 +02:00
|
|
|
#include "libcef/browser/browser_host_base.h"
|
2019-05-24 22:23:43 +02:00
|
|
|
#include "libcef/browser/navigate_params.h"
|
2019-05-11 00:14:48 +02:00
|
|
|
#include "libcef/browser/net_service/browser_urlrequest_impl.h"
|
2017-05-17 11:29:28 +02:00
|
|
|
#include "libcef/common/cef_messages.h"
|
2019-05-24 22:23:43 +02:00
|
|
|
#include "libcef/common/frame_util.h"
|
|
|
|
#include "libcef/common/process_message_impl.h"
|
|
|
|
#include "libcef/common/request_impl.h"
|
2019-05-11 00:14:48 +02:00
|
|
|
#include "libcef/common/task_runner_impl.h"
|
|
|
|
|
2020-12-02 23:31:49 +01:00
|
|
|
#include "components/url_formatter/url_fixer.h"
|
2020-10-08 21:54:42 +02:00
|
|
|
#include "content/browser/renderer_host/frame_tree_node.h"
|
2019-05-11 00:14:48 +02:00
|
|
|
#include "content/public/browser/render_process_host.h"
|
|
|
|
#include "content/public/browser/render_view_host.h"
|
2012-04-03 03:34:16 +02:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
// Implementation of CommandResponseHandler for calling a CefStringVisitor.
|
|
|
|
class StringVisitHandler : public CefResponseManager::Handler {
|
|
|
|
public:
|
|
|
|
explicit StringVisitHandler(CefRefPtr<CefStringVisitor> visitor)
|
2017-05-17 11:29:28 +02:00
|
|
|
: visitor_(visitor) {}
|
2014-11-12 20:25:15 +01:00
|
|
|
void OnResponse(const Cef_Response_Params& params) override {
|
2012-04-03 03:34:16 +02:00
|
|
|
visitor_->Visit(params.response);
|
|
|
|
}
|
2017-05-17 11:29:28 +02:00
|
|
|
|
2012-04-03 03:34:16 +02:00
|
|
|
private:
|
|
|
|
CefRefPtr<CefStringVisitor> visitor_;
|
|
|
|
|
|
|
|
IMPLEMENT_REFCOUNTING(StringVisitHandler);
|
|
|
|
};
|
|
|
|
|
|
|
|
// Implementation of CommandResponseHandler for calling ViewText().
|
|
|
|
class ViewTextHandler : public CefResponseManager::Handler {
|
|
|
|
public:
|
2017-05-17 11:29:28 +02:00
|
|
|
explicit ViewTextHandler(CefRefPtr<CefFrameHostImpl> frame) : frame_(frame) {}
|
2014-11-12 20:25:15 +01:00
|
|
|
void OnResponse(const Cef_Response_Params& params) override {
|
2012-04-03 03:34:16 +02:00
|
|
|
CefRefPtr<CefBrowser> browser = frame_->GetBrowser();
|
|
|
|
if (browser.get()) {
|
2020-09-18 00:24:08 +02:00
|
|
|
static_cast<CefBrowserHostBase*>(browser.get())
|
2017-05-17 11:29:28 +02:00
|
|
|
->ViewText(params.response);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
}
|
2017-05-17 11:29:28 +02:00
|
|
|
|
2012-04-03 03:34:16 +02:00
|
|
|
private:
|
|
|
|
CefRefPtr<CefFrameHostImpl> frame_;
|
|
|
|
|
|
|
|
IMPLEMENT_REFCOUNTING(ViewTextHandler);
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
CefFrameHostImpl::CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,
|
2013-05-31 17:34:53 +02:00
|
|
|
bool is_main_frame,
|
2019-05-24 22:23:43 +02:00
|
|
|
int64_t parent_frame_id)
|
|
|
|
: is_main_frame_(is_main_frame),
|
|
|
|
frame_id_(kInvalidFrameId),
|
|
|
|
browser_info_(browser_info),
|
2014-09-24 17:38:11 +02:00
|
|
|
is_focused_(is_main_frame_), // The main frame always starts focused.
|
2019-05-24 22:23:43 +02:00
|
|
|
parent_frame_id_(parent_frame_id) {
|
|
|
|
#if DCHECK_IS_ON()
|
|
|
|
DCHECK(browser_info_);
|
|
|
|
if (is_main_frame_) {
|
|
|
|
DCHECK_EQ(parent_frame_id_, kInvalidFrameId);
|
|
|
|
} else {
|
|
|
|
DCHECK_GT(parent_frame_id_, 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
CefFrameHostImpl::CefFrameHostImpl(scoped_refptr<CefBrowserInfo> browser_info,
|
|
|
|
content::RenderFrameHost* render_frame_host)
|
|
|
|
: is_main_frame_(render_frame_host->GetParent() == nullptr),
|
|
|
|
frame_id_(MakeFrameId(render_frame_host)),
|
|
|
|
browser_info_(browser_info),
|
|
|
|
is_focused_(is_main_frame_), // The main frame always starts focused.
|
|
|
|
url_(render_frame_host->GetLastCommittedURL().spec()),
|
|
|
|
name_(render_frame_host->GetFrameName()),
|
|
|
|
parent_frame_id_(is_main_frame_
|
2017-05-17 11:29:28 +02:00
|
|
|
? kInvalidFrameId
|
2019-05-24 22:23:43 +02:00
|
|
|
: MakeFrameId(render_frame_host->GetParent())),
|
|
|
|
render_frame_host_(render_frame_host),
|
|
|
|
response_manager_(new CefResponseManager) {
|
|
|
|
DCHECK(browser_info_);
|
|
|
|
}
|
2012-04-03 03:34:16 +02:00
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
CefFrameHostImpl::~CefFrameHostImpl() {}
|
2012-04-03 03:34:16 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
void CefFrameHostImpl::SetRenderFrameHost(content::RenderFrameHost* host) {
|
|
|
|
CEF_REQUIRE_UIT();
|
|
|
|
|
2012-04-03 03:34:16 +02:00
|
|
|
base::AutoLock lock_scope(state_lock_);
|
2019-05-24 22:23:43 +02:00
|
|
|
|
|
|
|
// We should not be detached.
|
|
|
|
CHECK(browser_info_);
|
|
|
|
// We should be the main frame.
|
|
|
|
CHECK(is_main_frame_);
|
|
|
|
|
|
|
|
render_frame_host_ = host;
|
|
|
|
frame_id_ = MakeFrameId(host);
|
|
|
|
url_ = host->GetLastCommittedURL().spec();
|
|
|
|
name_ = host->GetFrameName();
|
|
|
|
|
|
|
|
// Cancel any existing messages.
|
|
|
|
response_manager_.reset(new CefResponseManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CefFrameHostImpl::IsValid() {
|
2020-09-18 00:24:08 +02:00
|
|
|
return !!GetBrowserHostBase();
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::Undo() {
|
2019-05-24 22:23:43 +02:00
|
|
|
SendCommand("Undo", nullptr);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::Redo() {
|
2019-05-24 22:23:43 +02:00
|
|
|
SendCommand("Redo", nullptr);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::Cut() {
|
2019-05-24 22:23:43 +02:00
|
|
|
SendCommand("Cut", nullptr);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::Copy() {
|
2019-05-24 22:23:43 +02:00
|
|
|
SendCommand("Copy", nullptr);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::Paste() {
|
2019-05-24 22:23:43 +02:00
|
|
|
SendCommand("Paste", nullptr);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::Delete() {
|
2019-05-24 22:23:43 +02:00
|
|
|
SendCommand("Delete", nullptr);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::SelectAll() {
|
2019-05-24 22:23:43 +02:00
|
|
|
SendCommand("SelectAll", nullptr);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::ViewSource() {
|
2013-05-31 17:34:53 +02:00
|
|
|
SendCommand("GetSource", new ViewTextHandler(this));
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::GetSource(CefRefPtr<CefStringVisitor> visitor) {
|
2013-05-31 17:34:53 +02:00
|
|
|
SendCommand("GetSource", new StringVisitHandler(visitor));
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::GetText(CefRefPtr<CefStringVisitor> visitor) {
|
2013-05-31 17:34:53 +02:00
|
|
|
SendCommand("GetText", new StringVisitHandler(visitor));
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::LoadRequest(CefRefPtr<CefRequest> request) {
|
2020-02-14 22:58:58 +01:00
|
|
|
CefNavigateParams params(GURL(), kPageTransitionExplicit);
|
2019-05-24 22:23:43 +02:00
|
|
|
static_cast<CefRequestImpl*>(request.get())->Get(params);
|
|
|
|
Navigate(params);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::LoadURL(const CefString& url) {
|
2020-02-14 22:58:58 +01:00
|
|
|
LoadURLWithExtras(url, content::Referrer(), kPageTransitionExplicit,
|
2019-05-24 22:23:43 +02:00
|
|
|
std::string());
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::ExecuteJavaScript(const CefString& jsCode,
|
|
|
|
const CefString& scriptUrl,
|
|
|
|
int startLine) {
|
2012-10-18 00:45:49 +02:00
|
|
|
SendJavaScript(jsCode, scriptUrl, startLine);
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CefFrameHostImpl::IsMain() {
|
|
|
|
return is_main_frame_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CefFrameHostImpl::IsFocused() {
|
|
|
|
base::AutoLock lock_scope(state_lock_);
|
|
|
|
return is_focused_;
|
|
|
|
}
|
|
|
|
|
|
|
|
CefString CefFrameHostImpl::GetName() {
|
|
|
|
base::AutoLock lock_scope(state_lock_);
|
|
|
|
return name_;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64 CefFrameHostImpl::GetIdentifier() {
|
2019-05-24 22:23:43 +02:00
|
|
|
base::AutoLock lock_scope(state_lock_);
|
2012-04-03 03:34:16 +02:00
|
|
|
return frame_id_;
|
|
|
|
}
|
|
|
|
|
|
|
|
CefRefPtr<CefFrame> CefFrameHostImpl::GetParent() {
|
2013-05-31 17:34:53 +02:00
|
|
|
int64 parent_frame_id;
|
|
|
|
|
|
|
|
{
|
|
|
|
base::AutoLock lock_scope(state_lock_);
|
|
|
|
if (is_main_frame_ || parent_frame_id_ == kInvalidFrameId)
|
2019-05-24 22:23:43 +02:00
|
|
|
return nullptr;
|
2013-05-31 17:34:53 +02:00
|
|
|
parent_frame_id = parent_frame_id_;
|
|
|
|
}
|
2012-04-03 03:34:16 +02:00
|
|
|
|
2020-09-18 00:24:08 +02:00
|
|
|
auto browser = GetBrowserHostBase();
|
2019-05-24 22:23:43 +02:00
|
|
|
if (browser)
|
2013-05-31 17:34:53 +02:00
|
|
|
return browser->GetFrame(parent_frame_id);
|
2012-04-03 03:34:16 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
return nullptr;
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CefString CefFrameHostImpl::GetURL() {
|
|
|
|
base::AutoLock lock_scope(state_lock_);
|
|
|
|
return url_;
|
|
|
|
}
|
|
|
|
|
|
|
|
CefRefPtr<CefBrowser> CefFrameHostImpl::GetBrowser() {
|
2020-09-18 00:24:08 +02:00
|
|
|
return GetBrowserHostBase().get();
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CefRefPtr<CefV8Context> CefFrameHostImpl::GetV8Context() {
|
|
|
|
NOTREACHED() << "GetV8Context cannot be called from the browser process";
|
2019-05-24 22:23:43 +02:00
|
|
|
return nullptr;
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
|
|
|
|
2012-04-27 23:19:06 +02:00
|
|
|
void CefFrameHostImpl::VisitDOM(CefRefPtr<CefDOMVisitor> visitor) {
|
|
|
|
NOTREACHED() << "VisitDOM cannot be called from the browser process";
|
|
|
|
}
|
|
|
|
|
2019-05-11 00:14:48 +02:00
|
|
|
CefRefPtr<CefURLRequest> CefFrameHostImpl::CreateURLRequest(
|
|
|
|
CefRefPtr<CefRequest> request,
|
|
|
|
CefRefPtr<CefURLRequestClient> client) {
|
|
|
|
if (!request || !client)
|
2019-05-24 22:23:43 +02:00
|
|
|
return nullptr;
|
2019-05-11 00:14:48 +02:00
|
|
|
|
|
|
|
if (!CefTaskRunnerImpl::GetCurrentTaskRunner()) {
|
|
|
|
NOTREACHED() << "called on invalid thread";
|
2019-05-24 22:23:43 +02:00
|
|
|
return nullptr;
|
2019-05-11 00:14:48 +02:00
|
|
|
}
|
|
|
|
|
2020-09-18 00:24:08 +02:00
|
|
|
auto browser = GetBrowserHostBase();
|
2019-05-11 00:14:48 +02:00
|
|
|
if (!browser)
|
2019-05-24 22:23:43 +02:00
|
|
|
return nullptr;
|
2019-05-11 00:14:48 +02:00
|
|
|
|
|
|
|
auto request_context = browser->request_context();
|
|
|
|
|
2019-07-29 23:27:12 +02:00
|
|
|
CefRefPtr<CefBrowserURLRequest> impl =
|
|
|
|
new CefBrowserURLRequest(this, request, client, request_context);
|
|
|
|
if (impl->Start())
|
|
|
|
return impl.get();
|
2019-05-24 22:23:43 +02:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::SendProcessMessage(
|
|
|
|
CefProcessId target_process,
|
|
|
|
CefRefPtr<CefProcessMessage> message) {
|
|
|
|
DCHECK_EQ(PID_RENDERER, target_process);
|
|
|
|
DCHECK(message.get());
|
|
|
|
|
|
|
|
Cef_Request_Params params;
|
|
|
|
CefProcessMessageImpl* impl =
|
|
|
|
static_cast<CefProcessMessageImpl*>(message.get());
|
|
|
|
if (!impl->CopyTo(params))
|
|
|
|
return;
|
|
|
|
|
|
|
|
DCHECK(!params.name.empty());
|
|
|
|
|
|
|
|
params.user_initiated = true;
|
|
|
|
params.request_id = -1;
|
|
|
|
params.expect_response = false;
|
|
|
|
|
|
|
|
Send(new CefMsg_Request(MSG_ROUTING_NONE, params));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::SetFocused(bool focused) {
|
|
|
|
base::AutoLock lock_scope(state_lock_);
|
|
|
|
is_focused_ = focused;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::RefreshAttributes() {
|
|
|
|
CEF_REQUIRE_UIT();
|
|
|
|
|
|
|
|
base::AutoLock lock_scope(state_lock_);
|
|
|
|
if (!render_frame_host_)
|
|
|
|
return;
|
|
|
|
url_ = render_frame_host_->GetLastCommittedURL().spec();
|
|
|
|
|
|
|
|
// Use the assigned name if it is non-empty. This represents the name property
|
|
|
|
// on the frame DOM element. If the assigned name is empty, revert to the
|
|
|
|
// internal unique name. This matches the logic in render_frame_util::GetName.
|
|
|
|
name_ = render_frame_host_->GetFrameName();
|
|
|
|
if (name_.empty()) {
|
|
|
|
const auto node = content::FrameTreeNode::GloballyFindByID(
|
|
|
|
render_frame_host_->GetFrameTreeNodeId());
|
|
|
|
if (node) {
|
|
|
|
name_ = node->unique_name();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_main_frame_)
|
|
|
|
parent_frame_id_ = MakeFrameId(render_frame_host_->GetParent());
|
|
|
|
}
|
|
|
|
|
2020-12-02 23:31:49 +01:00
|
|
|
void CefFrameHostImpl::NotifyMoveOrResizeStarted() {
|
|
|
|
Send(new CefMsg_MoveOrResizeStarted(MSG_ROUTING_NONE));
|
|
|
|
}
|
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
void CefFrameHostImpl::Navigate(const CefNavigateParams& params) {
|
|
|
|
CefMsg_LoadRequest_Params request;
|
2020-12-02 23:31:49 +01:00
|
|
|
|
|
|
|
// Fix common problems with user-typed text. Among other things, this:
|
|
|
|
// - Converts absolute file paths to "file://" URLs.
|
|
|
|
// - Normalizes "about:" and "chrome:" to "chrome://" URLs.
|
|
|
|
// - Adds the "http://" scheme if none was specified.
|
|
|
|
request.url = url_formatter::FixupURL(params.url.possibly_invalid_spec(),
|
|
|
|
std::string());
|
2019-05-24 22:23:43 +02:00
|
|
|
if (!request.url.is_valid()) {
|
2020-12-02 23:31:49 +01:00
|
|
|
LOG(ERROR) << "Invalid URL: " << params.url.possibly_invalid_spec();
|
2019-05-24 22:23:43 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
request.method = params.method;
|
|
|
|
request.referrer = params.referrer.url;
|
|
|
|
request.referrer_policy =
|
|
|
|
CefRequestImpl::BlinkReferrerPolicyToNetReferrerPolicy(
|
|
|
|
params.referrer.policy);
|
|
|
|
request.site_for_cookies = params.site_for_cookies;
|
|
|
|
request.headers = params.headers;
|
|
|
|
request.load_flags = params.load_flags;
|
|
|
|
request.upload_data = params.upload_data;
|
|
|
|
|
|
|
|
Send(new CefMsg_LoadRequest(MSG_ROUTING_NONE, request));
|
|
|
|
|
2020-09-18 00:24:08 +02:00
|
|
|
auto browser = GetBrowserHostBase();
|
2019-05-24 22:23:43 +02:00
|
|
|
if (browser)
|
|
|
|
browser->OnSetFocus(FOCUS_SOURCE_NAVIGATION);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::LoadURLWithExtras(const std::string& url,
|
|
|
|
const content::Referrer& referrer,
|
|
|
|
ui::PageTransition transition,
|
|
|
|
const std::string& extra_headers) {
|
|
|
|
// Only known frame ids or kMainFrameId are supported.
|
|
|
|
const auto frame_id = GetFrameId();
|
|
|
|
if (frame_id < CefFrameHostImpl::kMainFrameId)
|
|
|
|
return;
|
|
|
|
|
2020-12-02 23:31:49 +01:00
|
|
|
// Any necessary fixup of the URL will occur in
|
|
|
|
// [CefBrowserHostBase|CefFrameHostImpl]::Navigate().
|
2020-09-25 03:40:47 +02:00
|
|
|
GURL gurl(url);
|
2021-02-10 19:30:43 +01:00
|
|
|
if (!url.empty() && !gurl.is_valid() && !gurl.has_scheme()) {
|
|
|
|
std::string fixed_scheme(url::kHttpScheme);
|
|
|
|
fixed_scheme.append(url::kStandardSchemeSeparator);
|
|
|
|
std::string new_url = url;
|
|
|
|
new_url.insert(0, fixed_scheme);
|
|
|
|
gurl = GURL(new_url);
|
|
|
|
}
|
2020-09-25 03:40:47 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
if (frame_id == CefFrameHostImpl::kMainFrameId) {
|
|
|
|
// Load via the browser using NavigationController.
|
2020-09-18 00:24:08 +02:00
|
|
|
auto browser = GetBrowserHostBase();
|
2019-05-24 22:23:43 +02:00
|
|
|
if (browser) {
|
2020-09-25 03:40:47 +02:00
|
|
|
content::OpenURLParams params(
|
|
|
|
gurl, referrer, WindowOpenDisposition::CURRENT_TAB, transition,
|
|
|
|
/*is_renderer_initiated=*/false);
|
|
|
|
params.extra_headers = extra_headers;
|
|
|
|
|
|
|
|
browser->LoadMainFrameURL(params);
|
2019-05-24 22:23:43 +02:00
|
|
|
}
|
|
|
|
} else {
|
2020-09-25 03:40:47 +02:00
|
|
|
CefNavigateParams params(gurl, transition);
|
2019-05-24 22:23:43 +02:00
|
|
|
params.referrer = referrer;
|
|
|
|
params.headers = extra_headers;
|
|
|
|
Navigate(params);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::SendCommand(
|
|
|
|
const std::string& command,
|
|
|
|
CefRefPtr<CefResponseManager::Handler> responseHandler) {
|
|
|
|
DCHECK(!command.empty());
|
|
|
|
|
|
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
|
|
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefFrameHostImpl::SendCommand, this,
|
|
|
|
command, responseHandler));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only known frame ids or kMainFrameId are supported.
|
|
|
|
const auto frame_id = GetFrameId();
|
|
|
|
if (frame_id < CefFrameHostImpl::kMainFrameId)
|
|
|
|
return;
|
|
|
|
|
2020-04-02 23:01:33 +02:00
|
|
|
if (!render_frame_host_ || !response_manager_) {
|
|
|
|
// detached frame has no response_manager_
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
TRACE_EVENT2("cef", "CefFrameHostImpl::SendCommand", "frame_id", frame_id,
|
|
|
|
"needsResponse", responseHandler.get() ? 1 : 0);
|
|
|
|
Cef_Request_Params params;
|
|
|
|
params.name = "execute-command";
|
|
|
|
params.user_initiated = false;
|
|
|
|
|
|
|
|
if (responseHandler.get()) {
|
|
|
|
params.request_id = response_manager_->RegisterHandler(responseHandler);
|
|
|
|
params.expect_response = true;
|
|
|
|
} else {
|
|
|
|
params.request_id = -1;
|
|
|
|
params.expect_response = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
params.arguments.AppendString(command);
|
|
|
|
|
|
|
|
Send(new CefMsg_Request(MSG_ROUTING_NONE, params));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::SendCode(
|
|
|
|
bool is_javascript,
|
|
|
|
const std::string& code,
|
|
|
|
const std::string& script_url,
|
|
|
|
int script_start_line,
|
|
|
|
CefRefPtr<CefResponseManager::Handler> responseHandler) {
|
|
|
|
DCHECK(!code.empty());
|
|
|
|
DCHECK_GE(script_start_line, 0);
|
|
|
|
|
|
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
|
|
CEF_POST_TASK(CEF_UIT, base::BindOnce(&CefFrameHostImpl::SendCode, this,
|
|
|
|
is_javascript, code, script_url,
|
|
|
|
script_start_line, responseHandler));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only known frame ids or kMainFrameId are supported.
|
|
|
|
auto frame_id = GetFrameId();
|
|
|
|
if (frame_id < CefFrameHostImpl::kMainFrameId)
|
|
|
|
return;
|
|
|
|
|
2020-04-02 23:01:33 +02:00
|
|
|
if (!render_frame_host_ || !response_manager_) {
|
|
|
|
// detached frame has no response_manager_
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
TRACE_EVENT2("cef", "CefFrameHostImpl::SendCommand", "frame_id", frame_id,
|
|
|
|
"needsResponse", responseHandler.get() ? 1 : 0);
|
|
|
|
Cef_Request_Params params;
|
|
|
|
params.name = "execute-code";
|
|
|
|
params.user_initiated = false;
|
|
|
|
|
|
|
|
if (responseHandler.get()) {
|
|
|
|
params.request_id = response_manager_->RegisterHandler(responseHandler);
|
|
|
|
params.expect_response = true;
|
|
|
|
} else {
|
|
|
|
params.request_id = -1;
|
|
|
|
params.expect_response = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
params.arguments.AppendBoolean(is_javascript);
|
|
|
|
params.arguments.AppendString(code);
|
|
|
|
params.arguments.AppendString(script_url);
|
|
|
|
params.arguments.AppendInteger(script_start_line);
|
|
|
|
|
|
|
|
Send(new CefMsg_Request(MSG_ROUTING_NONE, params));
|
2019-05-11 00:14:48 +02:00
|
|
|
}
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
void CefFrameHostImpl::SendJavaScript(const std::string& jsCode,
|
|
|
|
const std::string& scriptUrl,
|
|
|
|
int startLine) {
|
2012-10-18 00:45:49 +02:00
|
|
|
if (jsCode.empty())
|
|
|
|
return;
|
2016-10-17 20:14:44 +02:00
|
|
|
if (startLine <= 0) {
|
|
|
|
// A value of 0 is v8::Message::kNoLineNumberInfo in V8. There is code in
|
|
|
|
// V8 that will assert on that value (e.g. V8StackTraceImpl::Frame::Frame
|
|
|
|
// if a JS exception is thrown) so make sure |startLine| > 0.
|
|
|
|
startLine = 1;
|
|
|
|
}
|
2012-10-18 00:45:49 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
SendCode(true, jsCode, scriptUrl, startLine, nullptr);
|
|
|
|
}
|
2013-05-31 17:34:53 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
void CefFrameHostImpl::MaybeSendDidStopLoading() {
|
|
|
|
auto rfh = GetRenderFrameHost();
|
|
|
|
if (!rfh)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// We only want to notify for the highest-level LocalFrame in this frame's
|
|
|
|
// renderer process subtree. If this frame has a parent in the same process
|
|
|
|
// then the notification will be sent via the parent instead.
|
|
|
|
auto rfh_parent = rfh->GetParent();
|
|
|
|
if (rfh_parent && rfh_parent->GetProcess() == rfh->GetProcess()) {
|
|
|
|
return;
|
2012-10-18 00:45:49 +02:00
|
|
|
}
|
2013-05-31 17:34:53 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
Send(new CefMsg_DidStopLoading(MSG_ROUTING_NONE));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CefFrameHostImpl::OnMessageReceived(const IPC::Message& message) {
|
|
|
|
bool handled = true;
|
|
|
|
IPC_BEGIN_MESSAGE_MAP(CefFrameHostImpl, message)
|
|
|
|
IPC_MESSAGE_HANDLER(CefHostMsg_FrameAttached, OnAttached)
|
|
|
|
IPC_MESSAGE_HANDLER(CefHostMsg_DidFinishLoad, OnDidFinishLoad)
|
|
|
|
IPC_MESSAGE_HANDLER(CefHostMsg_UpdateDraggableRegions,
|
|
|
|
OnUpdateDraggableRegions)
|
|
|
|
IPC_MESSAGE_HANDLER(CefHostMsg_Request, OnRequest)
|
|
|
|
IPC_MESSAGE_HANDLER(CefHostMsg_Response, OnResponse)
|
|
|
|
IPC_MESSAGE_HANDLER(CefHostMsg_ResponseAck, OnResponseAck)
|
|
|
|
IPC_MESSAGE_UNHANDLED(handled = false)
|
|
|
|
IPC_END_MESSAGE_MAP()
|
|
|
|
return handled;
|
2012-10-18 00:45:49 +02:00
|
|
|
}
|
|
|
|
|
2017-05-31 17:33:30 +02:00
|
|
|
void CefFrameHostImpl::ExecuteJavaScriptWithUserGestureForTests(
|
|
|
|
const CefString& javascript) {
|
2019-05-11 00:14:48 +02:00
|
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
|
|
CEF_POST_TASK(
|
|
|
|
CEF_UIT,
|
|
|
|
base::BindOnce(
|
|
|
|
&CefFrameHostImpl::ExecuteJavaScriptWithUserGestureForTests, this,
|
|
|
|
javascript));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
content::RenderFrameHost* rfh = GetRenderFrameHost();
|
|
|
|
if (rfh)
|
|
|
|
rfh->ExecuteJavaScriptWithUserGestureForTests(javascript);
|
|
|
|
}
|
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
content::RenderFrameHost* CefFrameHostImpl::GetRenderFrameHost() const {
|
2019-05-11 00:14:48 +02:00
|
|
|
CEF_REQUIRE_UIT();
|
2019-05-24 22:23:43 +02:00
|
|
|
return render_frame_host_;
|
|
|
|
}
|
2019-05-11 00:14:48 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
void CefFrameHostImpl::Detach() {
|
|
|
|
CEF_REQUIRE_UIT();
|
2017-05-31 17:33:30 +02:00
|
|
|
|
|
|
|
{
|
|
|
|
base::AutoLock lock_scope(state_lock_);
|
2019-05-24 22:23:43 +02:00
|
|
|
browser_info_ = nullptr;
|
2017-05-31 17:33:30 +02:00
|
|
|
}
|
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
// In case we never attached, clean up.
|
|
|
|
while (!queued_messages_.empty()) {
|
|
|
|
queued_messages_.pop();
|
|
|
|
}
|
2019-05-11 00:14:48 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
response_manager_.reset();
|
|
|
|
render_frame_host_ = nullptr;
|
|
|
|
}
|
2019-05-11 00:14:48 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
// static
|
|
|
|
int64_t CefFrameHostImpl::MakeFrameId(const content::RenderFrameHost* host) {
|
|
|
|
CEF_REQUIRE_UIT();
|
|
|
|
auto host_nonconst = const_cast<content::RenderFrameHost*>(host);
|
|
|
|
return MakeFrameId(host_nonconst->GetProcess()->GetID(),
|
|
|
|
host_nonconst->GetRoutingID());
|
|
|
|
}
|
2019-05-11 00:14:48 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
// static
|
|
|
|
int64_t CefFrameHostImpl::MakeFrameId(int32_t render_process_id,
|
|
|
|
int32_t render_routing_id) {
|
|
|
|
return frame_util::MakeFrameId(render_process_id, render_routing_id);
|
2017-05-31 17:33:30 +02:00
|
|
|
}
|
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
// kMainFrameId must be -1 to align with renderer expectations.
|
|
|
|
const int64_t CefFrameHostImpl::kMainFrameId = -1;
|
|
|
|
const int64_t CefFrameHostImpl::kFocusedFrameId = -2;
|
|
|
|
const int64_t CefFrameHostImpl::kUnspecifiedFrameId = -3;
|
|
|
|
const int64_t CefFrameHostImpl::kInvalidFrameId = -4;
|
|
|
|
|
2020-02-14 22:58:58 +01:00
|
|
|
// This equates to (TT_EXPLICIT | TT_DIRECT_LOAD_FLAG).
|
|
|
|
const ui::PageTransition CefFrameHostImpl::kPageTransitionExplicit =
|
|
|
|
static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_TYPED |
|
|
|
|
ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
|
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
int64 CefFrameHostImpl::GetFrameId() const {
|
2012-04-03 03:34:16 +02:00
|
|
|
base::AutoLock lock_scope(state_lock_);
|
2019-05-24 22:23:43 +02:00
|
|
|
return is_main_frame_ ? kMainFrameId : frame_id_;
|
2012-04-03 03:34:16 +02:00
|
|
|
}
|
2013-05-31 17:34:53 +02:00
|
|
|
|
2020-09-18 00:24:08 +02:00
|
|
|
CefRefPtr<CefBrowserHostBase> CefFrameHostImpl::GetBrowserHostBase() const {
|
2019-05-24 22:23:43 +02:00
|
|
|
base::AutoLock lock_scope(state_lock_);
|
|
|
|
if (browser_info_)
|
|
|
|
return browser_info_->browser();
|
|
|
|
return nullptr;
|
|
|
|
}
|
2013-05-31 17:34:53 +02:00
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
void CefFrameHostImpl::OnAttached() {
|
|
|
|
if (!is_attached_) {
|
|
|
|
is_attached_ = true;
|
|
|
|
while (!queued_messages_.empty()) {
|
|
|
|
Send(queued_messages_.front().release());
|
|
|
|
queued_messages_.pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::OnDidFinishLoad(const GURL& validated_url,
|
|
|
|
int http_status_code) {
|
2020-09-18 00:24:08 +02:00
|
|
|
auto browser = GetBrowserHostBase();
|
2019-05-24 22:23:43 +02:00
|
|
|
if (browser)
|
|
|
|
browser->OnDidFinishLoad(this, validated_url, http_status_code);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::OnUpdateDraggableRegions(
|
|
|
|
const std::vector<Cef_DraggableRegion_Params>& regions) {
|
2020-09-18 00:24:08 +02:00
|
|
|
auto browser = GetBrowserHostBase();
|
2019-05-24 22:23:43 +02:00
|
|
|
if (!browser)
|
|
|
|
return;
|
|
|
|
|
|
|
|
CefRefPtr<CefDragHandler> handler;
|
|
|
|
auto client = browser->GetClient();
|
|
|
|
if (client)
|
|
|
|
handler = client->GetDragHandler();
|
|
|
|
if (!handler)
|
|
|
|
return;
|
|
|
|
|
|
|
|
std::vector<CefDraggableRegion> draggable_regions;
|
|
|
|
draggable_regions.reserve(regions.size());
|
|
|
|
|
|
|
|
std::vector<Cef_DraggableRegion_Params>::const_iterator it = regions.begin();
|
|
|
|
for (; it != regions.end(); ++it) {
|
|
|
|
const gfx::Rect& rect(it->bounds);
|
|
|
|
const CefRect bounds(rect.x(), rect.y(), rect.width(), rect.height());
|
|
|
|
draggable_regions.push_back(CefDraggableRegion(bounds, it->draggable));
|
|
|
|
}
|
|
|
|
|
|
|
|
handler->OnDraggableRegionsChanged(browser.get(), this, draggable_regions);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::OnRequest(const Cef_Request_Params& params) {
|
|
|
|
CEF_REQUIRE_UIT();
|
|
|
|
|
|
|
|
bool success = false;
|
|
|
|
std::string response;
|
|
|
|
bool expect_response_ack = false;
|
|
|
|
|
|
|
|
if (params.user_initiated) {
|
2020-09-18 00:24:08 +02:00
|
|
|
auto browser = GetBrowserHostBase();
|
|
|
|
if (browser && browser->GetClient()) {
|
2019-05-24 22:23:43 +02:00
|
|
|
// Give the user a chance to handle the request.
|
|
|
|
CefRefPtr<CefProcessMessageImpl> message(new CefProcessMessageImpl(
|
|
|
|
const_cast<Cef_Request_Params*>(¶ms), false, true));
|
2020-09-18 00:24:08 +02:00
|
|
|
success = browser->GetClient()->OnProcessMessageReceived(
|
2019-05-24 22:23:43 +02:00
|
|
|
browser.get(), this, PID_RENDERER, message.get());
|
|
|
|
message->Detach(nullptr);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Invalid request.
|
|
|
|
NOTREACHED();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params.expect_response) {
|
|
|
|
DCHECK_GE(params.request_id, 0);
|
|
|
|
|
|
|
|
// Send a response to the renderer.
|
|
|
|
Cef_Response_Params response_params;
|
|
|
|
response_params.request_id = params.request_id;
|
|
|
|
response_params.success = success;
|
|
|
|
response_params.response = response;
|
|
|
|
response_params.expect_response_ack = expect_response_ack;
|
|
|
|
Send(new CefMsg_Response(MSG_ROUTING_NONE, response_params));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::OnResponse(const Cef_Response_Params& params) {
|
|
|
|
CEF_REQUIRE_UIT();
|
|
|
|
|
|
|
|
response_manager_->RunHandler(params);
|
|
|
|
if (params.expect_response_ack)
|
|
|
|
Send(new CefMsg_ResponseAck(MSG_ROUTING_NONE, params.request_id));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::OnResponseAck(int request_id) {
|
|
|
|
response_manager_->RunAckHandler(request_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CefFrameHostImpl::Send(IPC::Message* message) {
|
|
|
|
if (!CEF_CURRENTLY_ON_UIT()) {
|
|
|
|
CEF_POST_TASK(CEF_UIT,
|
|
|
|
base::BindOnce(base::IgnoreResult(&CefFrameHostImpl::Send),
|
|
|
|
this, message));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!render_frame_host_) {
|
|
|
|
// Either we're a placeholder frame without a renderer representation, or
|
|
|
|
// we've been detached.
|
|
|
|
delete message;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!is_attached_) {
|
|
|
|
// Queue messages until we're notified by the renderer that it's ready to
|
|
|
|
// handle them.
|
|
|
|
queued_messages_.push(base::WrapUnique(message));
|
|
|
|
return;
|
2013-05-31 17:34:53 +02:00
|
|
|
}
|
|
|
|
|
2019-05-24 22:23:43 +02:00
|
|
|
message->set_routing_id(render_frame_host_->GetRoutingID());
|
|
|
|
render_frame_host_->Send(message);
|
2013-05-31 17:34:53 +02:00
|
|
|
}
|
2017-05-31 17:33:30 +02:00
|
|
|
|
|
|
|
void CefExecuteJavaScriptWithUserGestureForTests(CefRefPtr<CefFrame> frame,
|
|
|
|
const CefString& javascript) {
|
|
|
|
CefFrameHostImpl* impl = static_cast<CefFrameHostImpl*>(frame.get());
|
2019-05-11 00:14:48 +02:00
|
|
|
if (impl)
|
|
|
|
impl->ExecuteJavaScriptWithUserGestureForTests(javascript);
|
2017-05-31 17:33:30 +02:00
|
|
|
}
|