mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-01-22 15:29:56 +01:00
b3a8da9b25
This is the first pass in removing direct dependencies on the Alloy runtime from code that can potentially be shared between runtimes. CefBrowserHost and CefRequestContext APIs (including CefCookieManager, CefURLRequest, etc.) are not yet implemented for the Chrome runtime. Assert early if these API methods are called while the Chrome runtime is enabled.
527 lines
15 KiB
C++
527 lines
15 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.
|
|
|
|
#include "libcef/renderer/frame_impl.h"
|
|
|
|
#include "base/compiler_specific.h"
|
|
|
|
// Enable deprecation warnings on Windows. See http://crbug.com/585142.
|
|
#if defined(OS_WIN)
|
|
#if defined(__clang__)
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic error "-Wdeprecated-declarations"
|
|
#else
|
|
#pragma warning(push)
|
|
#pragma warning(default : 4996)
|
|
#endif
|
|
#endif
|
|
|
|
#include "libcef/common/app_manager.h"
|
|
#include "libcef/common/cef_messages.h"
|
|
#include "libcef/common/net/http_header_utils.h"
|
|
#include "libcef/common/process_message_impl.h"
|
|
#include "libcef/common/request_impl.h"
|
|
#include "libcef/common/response_manager.h"
|
|
#include "libcef/renderer/blink_glue.h"
|
|
#include "libcef/renderer/browser_impl.h"
|
|
#include "libcef/renderer/dom_document_impl.h"
|
|
#include "libcef/renderer/render_frame_util.h"
|
|
#include "libcef/renderer/render_urlrequest_impl.h"
|
|
#include "libcef/renderer/thread_util.h"
|
|
#include "libcef/renderer/v8_impl.h"
|
|
|
|
#include "base/strings/utf_string_conversions.h"
|
|
#include "content/public/renderer/render_view.h"
|
|
#include "content/renderer/render_frame_impl.h"
|
|
#include "third_party/blink/public/platform/web_data.h"
|
|
#include "third_party/blink/public/platform/web_string.h"
|
|
#include "third_party/blink/public/platform/web_url.h"
|
|
#include "third_party/blink/public/web/blink.h"
|
|
#include "third_party/blink/public/web/web_document.h"
|
|
#include "third_party/blink/public/web/web_document_loader.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_navigation_control.h"
|
|
#include "third_party/blink/public/web/web_script_source.h"
|
|
#include "third_party/blink/public/web/web_view.h"
|
|
|
|
CefFrameImpl::CefFrameImpl(CefBrowserImpl* browser,
|
|
blink::WebLocalFrame* frame,
|
|
int64_t frame_id)
|
|
: browser_(browser),
|
|
frame_(frame),
|
|
frame_id_(frame_id),
|
|
response_manager_(new CefResponseManager) {}
|
|
|
|
CefFrameImpl::~CefFrameImpl() {}
|
|
|
|
bool CefFrameImpl::IsValid() {
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
|
|
return (frame_ != nullptr);
|
|
}
|
|
|
|
void CefFrameImpl::Undo() {
|
|
ExecuteCommand("Undo");
|
|
}
|
|
|
|
void CefFrameImpl::Redo() {
|
|
ExecuteCommand("Redo");
|
|
}
|
|
|
|
void CefFrameImpl::Cut() {
|
|
ExecuteCommand("Cut");
|
|
}
|
|
|
|
void CefFrameImpl::Copy() {
|
|
ExecuteCommand("Copy");
|
|
}
|
|
|
|
void CefFrameImpl::Paste() {
|
|
ExecuteCommand("Paste");
|
|
}
|
|
|
|
void CefFrameImpl::Delete() {
|
|
ExecuteCommand("Delete");
|
|
}
|
|
|
|
void CefFrameImpl::SelectAll() {
|
|
ExecuteCommand("SelectAll");
|
|
}
|
|
|
|
void CefFrameImpl::ViewSource() {
|
|
NOTREACHED() << "ViewSource cannot be called from the renderer process";
|
|
}
|
|
|
|
void CefFrameImpl::GetSource(CefRefPtr<CefStringVisitor> visitor) {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
if (frame_) {
|
|
const CefString& content =
|
|
std::string(blink::WebFrameContentDumper::DumpAsMarkup(frame_).Utf8());
|
|
visitor->Visit(content);
|
|
}
|
|
}
|
|
|
|
void CefFrameImpl::GetText(CefRefPtr<CefStringVisitor> visitor) {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
if (frame_) {
|
|
const CefString& content = blink_glue::DumpDocumentText(frame_);
|
|
visitor->Visit(content);
|
|
}
|
|
}
|
|
|
|
void CefFrameImpl::LoadRequest(CefRefPtr<CefRequest> request) {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
if (!frame_)
|
|
return;
|
|
|
|
CefMsg_LoadRequest_Params params;
|
|
params.url = GURL(std::string(request->GetURL()));
|
|
params.method = request->GetMethod();
|
|
params.site_for_cookies = net::SiteForCookies::FromUrl(
|
|
GURL(request->GetFirstPartyForCookies().ToString()));
|
|
|
|
CefRequest::HeaderMap headerMap;
|
|
request->GetHeaderMap(headerMap);
|
|
if (!headerMap.empty())
|
|
params.headers = HttpHeaderUtils::GenerateHeaders(headerMap);
|
|
|
|
CefRefPtr<CefPostData> postData = request->GetPostData();
|
|
if (postData.get()) {
|
|
CefPostDataImpl* impl = static_cast<CefPostDataImpl*>(postData.get());
|
|
params.upload_data = new net::UploadData();
|
|
impl->Get(*params.upload_data.get());
|
|
}
|
|
|
|
params.load_flags = request->GetFlags();
|
|
|
|
OnLoadRequest(params);
|
|
}
|
|
|
|
void CefFrameImpl::LoadURL(const CefString& url) {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
if (!frame_)
|
|
return;
|
|
|
|
CefMsg_LoadRequest_Params params;
|
|
params.url = GURL(url.ToString());
|
|
params.method = "GET";
|
|
|
|
OnLoadRequest(params);
|
|
}
|
|
|
|
void CefFrameImpl::ExecuteJavaScript(const CefString& jsCode,
|
|
const CefString& scriptUrl,
|
|
int startLine) {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
if (jsCode.empty())
|
|
return;
|
|
if (startLine < 1)
|
|
startLine = 1;
|
|
|
|
if (frame_) {
|
|
GURL gurl = GURL(scriptUrl.ToString());
|
|
frame_->ExecuteScript(blink::WebScriptSource(
|
|
blink::WebString::FromUTF16(jsCode.ToString16()), gurl, startLine));
|
|
}
|
|
}
|
|
|
|
bool CefFrameImpl::IsMain() {
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
|
|
if (frame_)
|
|
return (frame_->Parent() == nullptr);
|
|
return false;
|
|
}
|
|
|
|
bool CefFrameImpl::IsFocused() {
|
|
CEF_REQUIRE_RT_RETURN(false);
|
|
|
|
if (frame_ && frame_->View())
|
|
return (frame_->View()->FocusedFrame() == frame_);
|
|
return false;
|
|
}
|
|
|
|
CefString CefFrameImpl::GetName() {
|
|
CefString name;
|
|
CEF_REQUIRE_RT_RETURN(name);
|
|
|
|
if (frame_)
|
|
name = render_frame_util::GetName(frame_);
|
|
return name;
|
|
}
|
|
|
|
int64 CefFrameImpl::GetIdentifier() {
|
|
CEF_REQUIRE_RT_RETURN(0);
|
|
|
|
return frame_id_;
|
|
}
|
|
|
|
CefRefPtr<CefFrame> CefFrameImpl::GetParent() {
|
|
CEF_REQUIRE_RT_RETURN(nullptr);
|
|
|
|
if (frame_) {
|
|
blink::WebFrame* parent = frame_->Parent();
|
|
if (parent && parent->IsWebLocalFrame())
|
|
return browser_->GetWebFrameImpl(parent->ToWebLocalFrame()).get();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
CefString CefFrameImpl::GetURL() {
|
|
CefString url;
|
|
CEF_REQUIRE_RT_RETURN(url);
|
|
|
|
if (frame_) {
|
|
GURL gurl = frame_->GetDocument().Url();
|
|
url = gurl.spec();
|
|
}
|
|
return url;
|
|
}
|
|
|
|
CefRefPtr<CefBrowser> CefFrameImpl::GetBrowser() {
|
|
CEF_REQUIRE_RT_RETURN(nullptr);
|
|
|
|
return browser_;
|
|
}
|
|
|
|
CefRefPtr<CefV8Context> CefFrameImpl::GetV8Context() {
|
|
CEF_REQUIRE_RT_RETURN(nullptr);
|
|
|
|
if (frame_) {
|
|
v8::Isolate* isolate = blink::MainThreadIsolate();
|
|
v8::HandleScope handle_scope(isolate);
|
|
return new CefV8ContextImpl(isolate, frame_->MainWorldScriptContext());
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
void CefFrameImpl::VisitDOM(CefRefPtr<CefDOMVisitor> visitor) {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
|
|
if (!frame_)
|
|
return;
|
|
|
|
// Create a CefDOMDocumentImpl object that is valid only for the scope of this
|
|
// method.
|
|
CefRefPtr<CefDOMDocumentImpl> documentImpl;
|
|
const blink::WebDocument& document = frame_->GetDocument();
|
|
if (!document.IsNull())
|
|
documentImpl = new CefDOMDocumentImpl(browser_, frame_);
|
|
|
|
visitor->Visit(documentImpl.get());
|
|
|
|
if (documentImpl.get())
|
|
documentImpl->Detach();
|
|
}
|
|
|
|
CefRefPtr<CefURLRequest> CefFrameImpl::CreateURLRequest(
|
|
CefRefPtr<CefRequest> request,
|
|
CefRefPtr<CefURLRequestClient> client) {
|
|
CEF_REQUIRE_RT_RETURN(nullptr);
|
|
|
|
if (!request || !client || !frame_)
|
|
return nullptr;
|
|
|
|
CefRefPtr<CefRenderURLRequest> impl =
|
|
new CefRenderURLRequest(this, request, client);
|
|
if (impl->Start())
|
|
return impl.get();
|
|
return nullptr;
|
|
}
|
|
|
|
void CefFrameImpl::SendProcessMessage(CefProcessId target_process,
|
|
CefRefPtr<CefProcessMessage> message) {
|
|
Cef_Request_Params params;
|
|
CefProcessMessageImpl* impl =
|
|
static_cast<CefProcessMessageImpl*>(message.get());
|
|
if (impl->CopyTo(params)) {
|
|
SendProcessMessage(target_process, params.name, ¶ms.arguments, true);
|
|
}
|
|
}
|
|
|
|
blink::WebURLLoaderFactory* CefFrameImpl::GetURLLoaderFactory() {
|
|
CEF_REQUIRE_RT();
|
|
if (!url_loader_factory_ && frame_) {
|
|
auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
|
|
if (render_frame) {
|
|
url_loader_factory_ = render_frame->CreateURLLoaderFactory();
|
|
}
|
|
}
|
|
return url_loader_factory_.get();
|
|
}
|
|
|
|
void CefFrameImpl::OnAttached() {
|
|
Send(new CefHostMsg_FrameAttached(MSG_ROUTING_NONE));
|
|
}
|
|
|
|
bool CefFrameImpl::OnMessageReceived(const IPC::Message& message) {
|
|
bool handled = true;
|
|
IPC_BEGIN_MESSAGE_MAP(CefFrameImpl, message)
|
|
IPC_MESSAGE_HANDLER(CefMsg_Request, OnRequest)
|
|
IPC_MESSAGE_HANDLER(CefMsg_Response, OnResponse)
|
|
IPC_MESSAGE_HANDLER(CefMsg_ResponseAck, OnResponseAck)
|
|
IPC_MESSAGE_HANDLER(CefMsg_LoadRequest, OnLoadRequest)
|
|
IPC_MESSAGE_HANDLER(CefMsg_DidStopLoading, OnDidStopLoading)
|
|
IPC_MESSAGE_UNHANDLED(handled = false)
|
|
IPC_END_MESSAGE_MAP()
|
|
return handled;
|
|
}
|
|
|
|
void CefFrameImpl::OnDidFinishLoad() {
|
|
// Ignore notifications from the embedded frame hosting a mime-type plugin.
|
|
// We'll eventually receive a notification from the owner frame.
|
|
if (blink_glue::HasPluginFrameOwner(frame_))
|
|
return;
|
|
|
|
blink::WebDocumentLoader* dl = frame_->GetDocumentLoader();
|
|
const int http_status_code = dl->GetResponse().HttpStatusCode();
|
|
Send(new CefHostMsg_DidFinishLoad(MSG_ROUTING_NONE, dl->GetUrl(),
|
|
http_status_code));
|
|
|
|
CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
|
|
if (app) {
|
|
CefRefPtr<CefRenderProcessHandler> handler = app->GetRenderProcessHandler();
|
|
if (handler) {
|
|
CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
|
|
if (load_handler) {
|
|
load_handler->OnLoadEnd(browser_, this, http_status_code);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CefFrameImpl::OnDraggableRegionsChanged() {
|
|
blink::WebVector<blink::WebDraggableRegion> webregions =
|
|
frame_->GetDocument().DraggableRegions();
|
|
std::vector<Cef_DraggableRegion_Params> regions;
|
|
for (size_t i = 0; i < webregions.size(); ++i) {
|
|
Cef_DraggableRegion_Params region;
|
|
auto render_frame = content::RenderFrameImpl::FromWebFrame(frame_);
|
|
render_frame->ConvertViewportToWindow(&webregions[i].bounds);
|
|
region.bounds = webregions[i].bounds;
|
|
region.draggable = webregions[i].draggable;
|
|
regions.push_back(region);
|
|
}
|
|
Send(new CefHostMsg_UpdateDraggableRegions(MSG_ROUTING_NONE, regions));
|
|
}
|
|
|
|
void CefFrameImpl::OnDetached() {
|
|
// The browser may hold the last reference to |this|. Take a reference here to
|
|
// keep |this| alive until after this method returns.
|
|
CefRefPtr<CefFrameImpl> self = this;
|
|
|
|
browser_->FrameDetached(frame_id_);
|
|
|
|
browser_ = nullptr;
|
|
frame_ = nullptr;
|
|
url_loader_factory_.reset();
|
|
response_manager_.reset();
|
|
}
|
|
|
|
void CefFrameImpl::ExecuteCommand(const std::string& command) {
|
|
CEF_REQUIRE_RT_RETURN_VOID();
|
|
if (frame_)
|
|
frame_->ExecuteCommand(blink::WebString::FromUTF8(command));
|
|
}
|
|
|
|
void CefFrameImpl::SendProcessMessage(CefProcessId target_process,
|
|
const std::string& name,
|
|
base::ListValue* arguments,
|
|
bool user_initiated) {
|
|
DCHECK_EQ(PID_BROWSER, target_process);
|
|
DCHECK(!name.empty());
|
|
|
|
if (!frame_)
|
|
return;
|
|
|
|
Cef_Request_Params params;
|
|
params.name = name;
|
|
if (arguments)
|
|
params.arguments.Swap(arguments);
|
|
params.user_initiated = user_initiated;
|
|
params.request_id = -1;
|
|
params.expect_response = false;
|
|
|
|
Send(new CefHostMsg_Request(MSG_ROUTING_NONE, params));
|
|
}
|
|
|
|
void CefFrameImpl::Send(IPC::Message* message) {
|
|
if (!frame_) {
|
|
delete message;
|
|
return;
|
|
}
|
|
|
|
auto render_frame = content::RenderFrame::FromWebFrame(frame_);
|
|
message->set_routing_id(render_frame->GetRoutingID());
|
|
render_frame->Send(message);
|
|
}
|
|
|
|
void CefFrameImpl::OnRequest(const Cef_Request_Params& params) {
|
|
DCHECK(browser_);
|
|
DCHECK(frame_);
|
|
|
|
bool success = false;
|
|
std::string response;
|
|
bool expect_response_ack = false;
|
|
|
|
TRACE_EVENT2("cef", "CefBrowserImpl::OnRequest", "request_id",
|
|
params.request_id, "expect_response",
|
|
params.expect_response ? 1 : 0);
|
|
|
|
if (params.user_initiated) {
|
|
// Give the user a chance to handle the request.
|
|
CefRefPtr<CefApp> app = CefAppManager::Get()->GetApplication();
|
|
if (app.get()) {
|
|
CefRefPtr<CefRenderProcessHandler> handler =
|
|
app->GetRenderProcessHandler();
|
|
if (handler.get()) {
|
|
CefRefPtr<CefProcessMessageImpl> message(new CefProcessMessageImpl(
|
|
const_cast<Cef_Request_Params*>(¶ms), false, true));
|
|
success = handler->OnProcessMessageReceived(browser_, this, PID_BROWSER,
|
|
message.get());
|
|
message->Detach(nullptr);
|
|
}
|
|
}
|
|
} else if (params.name == "execute-code") {
|
|
// Execute code.
|
|
DCHECK_EQ(params.arguments.GetSize(), (size_t)4);
|
|
|
|
bool is_javascript = false;
|
|
std::string code, script_url;
|
|
int script_start_line = 0;
|
|
|
|
params.arguments.GetBoolean(0, &is_javascript);
|
|
params.arguments.GetString(1, &code);
|
|
DCHECK(!code.empty());
|
|
params.arguments.GetString(2, &script_url);
|
|
params.arguments.GetInteger(3, &script_start_line);
|
|
DCHECK_GE(script_start_line, 0);
|
|
|
|
if (is_javascript) {
|
|
frame_->ExecuteScript(
|
|
blink::WebScriptSource(blink::WebString::FromUTF8(code),
|
|
GURL(script_url), script_start_line));
|
|
success = true;
|
|
} else {
|
|
// TODO(cef): implement support for CSS code.
|
|
NOTIMPLEMENTED();
|
|
}
|
|
} else if (params.name == "execute-command") {
|
|
// Execute command.
|
|
DCHECK_EQ(params.arguments.GetSize(), (size_t)1);
|
|
|
|
std::string command;
|
|
|
|
params.arguments.GetString(0, &command);
|
|
DCHECK(!command.empty());
|
|
|
|
if (base::LowerCaseEqualsASCII(command, "getsource")) {
|
|
response = blink::WebFrameContentDumper::DumpAsMarkup(frame_).Utf8();
|
|
success = true;
|
|
} else if (base::LowerCaseEqualsASCII(command, "gettext")) {
|
|
response = blink_glue::DumpDocumentText(frame_);
|
|
success = true;
|
|
} else if (frame_->ExecuteCommand(blink::WebString::FromUTF8(command))) {
|
|
success = true;
|
|
}
|
|
} else {
|
|
// Invalid request.
|
|
NOTREACHED();
|
|
}
|
|
|
|
if (params.expect_response) {
|
|
DCHECK_GE(params.request_id, 0);
|
|
|
|
// Send a response to the browser.
|
|
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 CefHostMsg_Response(MSG_ROUTING_NONE, response_params));
|
|
}
|
|
}
|
|
|
|
void CefFrameImpl::OnResponse(const Cef_Response_Params& params) {
|
|
response_manager_->RunHandler(params);
|
|
if (params.expect_response_ack)
|
|
Send(new CefHostMsg_ResponseAck(MSG_ROUTING_NONE, params.request_id));
|
|
}
|
|
|
|
void CefFrameImpl::OnResponseAck(int request_id) {
|
|
response_manager_->RunAckHandler(request_id);
|
|
}
|
|
|
|
void CefFrameImpl::OnDidStopLoading() {
|
|
// We should only receive this notification for the highest-level LocalFrame
|
|
// in this frame's in-process subtree. If there are multiple of these for the
|
|
// same browser then the other occurrences will be discarded in
|
|
// OnLoadingStateChange.
|
|
browser_->OnLoadingStateChange(false);
|
|
}
|
|
|
|
void CefFrameImpl::OnLoadRequest(const CefMsg_LoadRequest_Params& params) {
|
|
DCHECK(frame_);
|
|
|
|
blink::WebURLRequest request;
|
|
CefRequestImpl::Get(params, request);
|
|
|
|
frame_->StartNavigation(request);
|
|
}
|
|
|
|
// Enable deprecation warnings on Windows. See http://crbug.com/585142.
|
|
#if defined(OS_WIN)
|
|
#if defined(__clang__)
|
|
#pragma GCC diagnostic pop
|
|
#else
|
|
#pragma warning(pop)
|
|
#endif
|
|
#endif
|