Create 2272 release branch for CEF3.

git-svn-id: https://chromiumembedded.googlecode.com/svn/branches/2272@1993 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt
2015-01-24 03:26:25 +00:00
parent 0d6bfeb4dd
commit dc47bc006a
1045 changed files with 190843 additions and 0 deletions

View File

@@ -0,0 +1,818 @@
// 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/cef_messages.h"
#include "libcef/common/content_client.h"
#include "libcef/common/process_message_impl.h"
#include "libcef/common/response_manager.h"
#include "libcef/renderer/content_renderer_client.h"
#include "libcef/renderer/dom_document_impl.h"
#include "libcef/renderer/thread_util.h"
#include "libcef/renderer/webkit_glue.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/renderer/document_state.h"
#include "content/public/renderer/navigation_state.h"
#include "content/public/renderer/render_view.h"
#include "content/renderer/render_view_impl.h"
#include "net/http/http_util.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
#include "third_party/WebKit/public/web/WebDataSource.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebScriptSource.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
#include "third_party/WebKit/public/web/WebView.h"
using blink::WebFrame;
using blink::WebScriptSource;
using blink::WebString;
using blink::WebURL;
using blink::WebView;
namespace {
blink::WebString FilePathStringToWebString(
const base::FilePath::StringType& str) {
#if defined(OS_POSIX)
return base::WideToUTF16(base::SysNativeMBToWide(str));
#elif defined(OS_WIN)
return base::WideToUTF16(str);
#endif
}
} // namespace
// CefBrowserImpl static methods.
// -----------------------------------------------------------------------------
// static
CefRefPtr<CefBrowserImpl> CefBrowserImpl::GetBrowserForView(
content::RenderView* view) {
return CefContentRendererClient::Get()->GetBrowserForView(view);
}
// static
CefRefPtr<CefBrowserImpl> CefBrowserImpl::GetBrowserForMainFrame(
blink::WebFrame* frame) {
return CefContentRendererClient::Get()->GetBrowserForMainFrame(frame);
}
// CefBrowser methods.
// -----------------------------------------------------------------------------
CefRefPtr<CefBrowserHost> CefBrowserImpl::GetHost() {
NOTREACHED() << "GetHost cannot be called from the render process";
return NULL;
}
bool CefBrowserImpl::CanGoBack() {
CEF_REQUIRE_RT_RETURN(false);
return webkit_glue::CanGoBack(render_view()->GetWebView());
}
void CefBrowserImpl::GoBack() {
CEF_REQUIRE_RT_RETURN_VOID();
webkit_glue::GoBack(render_view()->GetWebView());
}
bool CefBrowserImpl::CanGoForward() {
CEF_REQUIRE_RT_RETURN(false);
return webkit_glue::CanGoForward(render_view()->GetWebView());
}
void CefBrowserImpl::GoForward() {
CEF_REQUIRE_RT_RETURN_VOID();
webkit_glue::GoForward(render_view()->GetWebView());
}
bool CefBrowserImpl::IsLoading() {
CEF_REQUIRE_RT_RETURN(false);
if (render_view()->GetWebView()) {
blink::WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
if (main_frame)
return main_frame->toWebLocalFrame()->isLoading();
}
return false;
}
void CefBrowserImpl::Reload() {
CEF_REQUIRE_RT_RETURN_VOID();
if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame())
render_view()->GetWebView()->mainFrame()->reload(false);
}
void CefBrowserImpl::ReloadIgnoreCache() {
CEF_REQUIRE_RT_RETURN_VOID();
if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame())
render_view()->GetWebView()->mainFrame()->reload(true);
}
void CefBrowserImpl::StopLoad() {
CEF_REQUIRE_RT_RETURN_VOID();
if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame())
render_view()->GetWebView()->mainFrame()->stopLoading();
}
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 (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame())
return !render_view()->GetWebView()->mainFrame()->document().isNull();
return false;
}
CefRefPtr<CefFrame> CefBrowserImpl::GetMainFrame() {
CEF_REQUIRE_RT_RETURN(NULL);
if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame())
return GetWebFrameImpl(render_view()->GetWebView()->mainFrame()).get();
return NULL;
}
CefRefPtr<CefFrame> CefBrowserImpl::GetFocusedFrame() {
CEF_REQUIRE_RT_RETURN(NULL);
if (render_view()->GetWebView() &&
render_view()->GetWebView()->focusedFrame()) {
return GetWebFrameImpl(render_view()->GetWebView()->focusedFrame()).get();
}
return NULL;
}
CefRefPtr<CefFrame> CefBrowserImpl::GetFrame(int64 identifier) {
CEF_REQUIRE_RT_RETURN(NULL);
return GetWebFrameImpl(identifier).get();
}
CefRefPtr<CefFrame> CefBrowserImpl::GetFrame(const CefString& name) {
CEF_REQUIRE_RT_RETURN(NULL);
blink::WebView* web_view = render_view()->GetWebView();
if (web_view) {
const blink::WebString& frame_name = name.ToString16();
// Search by assigned frame name (Frame::name).
WebFrame* frame = web_view->findFrameByName(frame_name,
web_view->mainFrame());
if (!frame) {
// Search by unique frame name (Frame::uniqueName).
frame = webkit_glue::FindFrameByUniqueName(frame_name,
web_view->mainFrame());
}
if (frame)
return GetWebFrameImpl(frame).get();
}
return NULL;
}
size_t CefBrowserImpl::GetFrameCount() {
CEF_REQUIRE_RT_RETURN(0);
int count = 0;
if (render_view()->GetWebView()) {
WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
if (main_frame) {
WebFrame* cur = main_frame;
do {
count++;
cur = cur->traverseNext(true);
} while (cur != main_frame);
}
}
return count;
}
void CefBrowserImpl::GetFrameIdentifiers(std::vector<int64>& identifiers) {
CEF_REQUIRE_RT_RETURN_VOID();
if (identifiers.size() > 0)
identifiers.clear();
if (render_view()->GetWebView()) {
WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
if (main_frame) {
WebFrame* cur = main_frame;
do {
identifiers.push_back(webkit_glue::GetIdentifier(cur));
cur = cur->traverseNext(true);
} while (cur != main_frame);
}
}
}
void CefBrowserImpl::GetFrameNames(std::vector<CefString>& names) {
CEF_REQUIRE_RT_RETURN_VOID();
if (names.size() > 0)
names.clear();
if (render_view()->GetWebView()) {
WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
if (main_frame) {
WebFrame* cur = main_frame;
do {
names.push_back(CefString(cur->uniqueName().utf8()));
cur = cur->traverseNext(true);
} while (cur != main_frame);
}
}
}
bool CefBrowserImpl::SendProcessMessage(CefProcessId target_process,
CefRefPtr<CefProcessMessage> message) {
Cef_Request_Params params;
CefProcessMessageImpl* impl =
static_cast<CefProcessMessageImpl*>(message.get());
if (impl->CopyTo(params)) {
return SendProcessMessage(target_process, params.name, &params.arguments,
true);
}
return false;
}
// CefBrowserImpl public methods.
// -----------------------------------------------------------------------------
CefBrowserImpl::CefBrowserImpl(content::RenderView* render_view,
int browser_id,
bool is_popup,
bool is_windowless)
: content::RenderViewObserver(render_view),
browser_id_(browser_id),
is_popup_(is_popup),
is_windowless_(is_windowless) {
response_manager_.reset(new CefResponseManager);
}
CefBrowserImpl::~CefBrowserImpl() {
}
void CefBrowserImpl::LoadRequest(const CefMsg_LoadRequest_Params& params) {
CefRefPtr<CefFrameImpl> framePtr = GetWebFrameImpl(params.frame_id);
if (!framePtr.get())
return;
WebFrame* web_frame = framePtr->web_frame();
blink::WebURLRequest request(params.url);
// DidCreateDataSource checks for this value.
request.setRequestorID(-1);
if (!params.method.empty())
request.setHTTPMethod(base::ASCIIToUTF16(params.method));
if (params.referrer.is_valid()) {
WebString referrer = blink::WebSecurityPolicy::generateReferrerHeader(
static_cast<blink::WebReferrerPolicy>(params.referrer_policy),
params.url,
WebString::fromUTF8(params.referrer.spec()));
if (!referrer.isEmpty())
request.setHTTPHeaderField(WebString::fromUTF8("Referer"), referrer);
}
if (params.first_party_for_cookies.is_valid())
request.setFirstPartyForCookies(params.first_party_for_cookies);
if (!params.headers.empty()) {
for (net::HttpUtil::HeadersIterator i(params.headers.begin(),
params.headers.end(), "\n");
i.GetNext(); ) {
request.addHTTPHeaderField(WebString::fromUTF8(i.name()),
WebString::fromUTF8(i.values()));
}
}
if (params.upload_data.get()) {
base::string16 method = request.httpMethod();
if (method == base::ASCIIToUTF16("GET") ||
method == base::ASCIIToUTF16("HEAD")) {
request.setHTTPMethod(base::ASCIIToUTF16("POST"));
}
if (request.httpHeaderField(
base::ASCIIToUTF16("Content-Type")).length() == 0) {
request.setHTTPHeaderField(
base::ASCIIToUTF16("Content-Type"),
base::ASCIIToUTF16("application/x-www-form-urlencoded"));
}
blink::WebHTTPBody body;
body.initialize();
const ScopedVector<net::UploadElement>& elements =
params.upload_data->elements();
ScopedVector<net::UploadElement>::const_iterator it =
elements.begin();
for (; it != elements.end(); ++it) {
const net::UploadElement& element = **it;
if (element.type() == net::UploadElement::TYPE_BYTES) {
blink::WebData data;
data.assign(element.bytes(), element.bytes_length());
body.appendData(data);
} else if (element.type() == net::UploadElement::TYPE_FILE) {
body.appendFile(FilePathStringToWebString(element.file_path().value()));
} else {
NOTREACHED();
}
}
request.setHTTPBody(body);
}
web_frame->loadRequest(request);
}
bool CefBrowserImpl::SendProcessMessage(CefProcessId target_process,
const std::string& name,
base::ListValue* arguments,
bool user_initiated) {
DCHECK_EQ(PID_BROWSER, target_process);
DCHECK(!name.empty());
Cef_Request_Params params;
params.name = name;
if (arguments)
params.arguments.Swap(arguments);
params.frame_id = -1;
params.user_initiated = user_initiated;
params.request_id = -1;
params.expect_response = false;
return Send(new CefHostMsg_Request(routing_id(), params));
}
CefRefPtr<CefFrameImpl> CefBrowserImpl::GetWebFrameImpl(
blink::WebFrame* frame) {
DCHECK(frame);
int64 frame_id = webkit_glue::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));
frames_.insert(std::make_pair(frame_id, framePtr));
int64 parent_id = frame->parent() == NULL ?
webkit_glue::kInvalidFrameId :
webkit_glue::GetIdentifier(frame->parent());
base::string16 name = frame->uniqueName();
// Notify the browser that the frame has been identified.
Send(new CefHostMsg_FrameIdentified(routing_id(), frame_id, parent_id, name));
return framePtr;
}
CefRefPtr<CefFrameImpl> CefBrowserImpl::GetWebFrameImpl(int64 frame_id) {
if (frame_id == webkit_glue::kInvalidFrameId) {
if (render_view()->GetWebView() && render_view()->GetWebView()->mainFrame())
return GetWebFrameImpl(render_view()->GetWebView()->mainFrame());
return NULL;
}
// Check if we already know about the frame.
FrameMap::const_iterator it = frames_.find(frame_id);
if (it != frames_.end())
return it->second;
if (render_view()->GetWebView()) {
// Check if the frame exists but we don't know about it yet.
WebFrame* main_frame = render_view()->GetWebView()->mainFrame();
if (main_frame) {
WebFrame* cur = main_frame;
do {
if (webkit_glue::GetIdentifier(cur) == frame_id)
return GetWebFrameImpl(cur);
cur = cur->traverseNext(true);
} while (cur != main_frame);
}
}
return NULL;
}
void CefBrowserImpl::AddFrameObject(int64 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);
}
bool CefBrowserImpl::is_swapped_out() const {
content::RenderViewImpl* render_view_impl =
static_cast<content::RenderViewImpl*>(render_view());
return (!render_view_impl || render_view_impl->is_swapped_out());
}
// RenderViewObserver methods.
// -----------------------------------------------------------------------------
void CefBrowserImpl::OnDestruct() {
// Notify that the browser window has been destroyed.
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
if (app.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
app->GetRenderProcessHandler();
if (handler.get())
handler->OnBrowserDestroyed(this);
}
response_manager_.reset(NULL);
CefContentRendererClient::Get()->OnBrowserDestroyed(this);
}
void CefBrowserImpl::DidStartLoading() {
OnLoadingStateChange(true);
}
void CefBrowserImpl::DidStopLoading() {
OnLoadingStateChange(false);
}
void CefBrowserImpl::DidFailLoad(
blink::WebLocalFrame* frame,
const blink::WebURLError& error) {
OnLoadError(frame, error);
OnLoadEnd(frame);
}
void CefBrowserImpl::DidFinishLoad(blink::WebLocalFrame* frame) {
blink::WebDataSource* ds = frame->dataSource();
Send(new CefHostMsg_DidFinishLoad(routing_id(),
webkit_glue::GetIdentifier(frame),
ds->request().url(),
!frame->parent(),
ds->response().httpStatusCode()));
OnLoadEnd(frame);
}
void CefBrowserImpl::DidStartProvisionalLoad(blink::WebLocalFrame* frame) {
// Send the frame creation notification if necessary.
GetWebFrameImpl(frame);
}
void CefBrowserImpl::DidFailProvisionalLoad(
blink::WebLocalFrame* frame,
const blink::WebURLError& error) {
OnLoadError(frame, error);
}
void CefBrowserImpl::DidCommitProvisionalLoad(blink::WebLocalFrame* frame,
bool is_new_navigation) {
OnLoadStart(frame);
}
void CefBrowserImpl::FrameDetached(WebFrame* frame) {
int64 frame_id = webkit_glue::GetIdentifier(frame);
if (!frames_.empty()) {
// Remove the frame from the map.
FrameMap::iterator it = frames_.find(frame_id);
if (it != frames_.end()) {
it->second->Detach();
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::FocusedNodeChanged(const blink::WebNode& node) {
// Notify the handler.
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
if (app.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
app->GetRenderProcessHandler();
if (handler.get()) {
if (node.isNull()) {
handler->OnFocusedNodeChanged(this, GetFocusedFrame(), NULL);
} else {
const blink::WebDocument& document = node.document();
if (!document.isNull()) {
blink::WebFrame* frame = document.frame();
CefRefPtr<CefDOMDocumentImpl> documentImpl =
new CefDOMDocumentImpl(this, frame);
handler->OnFocusedNodeChanged(this,
GetWebFrameImpl(frame).get(),
documentImpl->GetOrCreateNode(node));
documentImpl->Detach();
}
}
}
}
}
void CefBrowserImpl::DidCreateDataSource(blink::WebLocalFrame* frame,
blink::WebDataSource* ds) {
const blink::WebURLRequest& request = ds->request();
if (request.requestorID() == -1) {
// Mark the request as browser-initiated so
// RenderViewImpl::decidePolicyForNavigation won't attempt to fork it.
content::DocumentState* document_state =
content::DocumentState::FromDataSource(ds);
document_state->set_navigation_state(
content::NavigationState::CreateBrowserInitiated(-1, -1, false,
ui::PAGE_TRANSITION_LINK));
}
if (frame->parent() == 0) {
GURL url = ds->request().url();
if (!url.is_empty()) {
// Notify that the loading URL has changed.
Send(new CefHostMsg_LoadingURLChange(routing_id(), url));
}
}
}
bool CefBrowserImpl::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(CefBrowserImpl, message)
IPC_MESSAGE_HANDLER(CefMsg_Request, OnRequest)
IPC_MESSAGE_HANDLER(CefMsg_Response, OnResponse)
IPC_MESSAGE_HANDLER(CefMsg_ResponseAck, OnResponseAck)
IPC_MESSAGE_HANDLER(CefMsg_LoadRequest, LoadRequest)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
// RenderViewObserver::OnMessageReceived message handlers.
// -----------------------------------------------------------------------------
void CefBrowserImpl::OnRequest(const Cef_Request_Params& params) {
bool success = false;
std::string response;
bool expect_response_ack = false;
TRACE_EVENT2("libcef", "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 = CefContentClient::Get()->application();
if (app.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
app->GetRenderProcessHandler();
if (handler.get()) {
CefRefPtr<CefProcessMessageImpl> message(
new CefProcessMessageImpl(const_cast<Cef_Request_Params*>(&params),
false, true));
success = handler->OnProcessMessageReceived(this, PID_BROWSER,
message.get());
message->Detach(NULL);
}
}
} else if (params.name == "execute-code") {
// Execute code.
CefRefPtr<CefFrameImpl> framePtr = GetWebFrameImpl(params.frame_id);
if (framePtr.get()) {
WebFrame* web_frame = framePtr->web_frame();
if (web_frame) {
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) {
web_frame->executeScript(
WebScriptSource(base::UTF8ToUTF16(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.
CefRefPtr<CefFrameImpl> framePtr = GetWebFrameImpl(params.frame_id);
if (framePtr.get()) {
WebFrame* web_frame = framePtr->web_frame();
if (web_frame) {
DCHECK_EQ(params.arguments.GetSize(), (size_t)1);
std::string command;
params.arguments.GetString(0, &command);
DCHECK(!command.empty());
if (LowerCaseEqualsASCII(command, "getsource")) {
response = web_frame->contentAsMarkup().utf8();
success = true;
} else if (LowerCaseEqualsASCII(command, "gettext")) {
response = webkit_glue::DumpDocumentText(web_frame);
success = true;
} else if (web_frame->executeCommand(base::UTF8ToUTF16(command))) {
success = true;
}
}
}
} else if (params.name == "load-string") {
// Load a string.
CefRefPtr<CefFrameImpl> framePtr = GetWebFrameImpl(params.frame_id);
if (framePtr.get()) {
WebFrame* web_frame = framePtr->web_frame();
if (web_frame) {
DCHECK_EQ(params.arguments.GetSize(), (size_t)2);
std::string string, url;
params.arguments.GetString(0, &string);
params.arguments.GetString(1, &url);
web_frame->loadHTMLString(string, GURL(url));
}
}
} 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(routing_id(), response_params));
}
}
void CefBrowserImpl::OnResponse(const Cef_Response_Params& params) {
response_manager_->RunHandler(params);
if (params.expect_response_ack)
Send(new CefHostMsg_ResponseAck(routing_id(), params.request_id));
}
void CefBrowserImpl::OnResponseAck(int request_id) {
response_manager_->RunAckHandler(request_id);
}
void CefBrowserImpl::OnLoadingStateChange(bool isLoading) {
if (is_swapped_out())
return;
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
if (app.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
app->GetRenderProcessHandler();
if (handler.get()) {
CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
if (load_handler.get()) {
WebView* web_view = render_view()->GetWebView();
const bool canGoBack = webkit_glue::CanGoBack(web_view);
const bool canGoForward = webkit_glue::CanGoForward(web_view);
load_handler->OnLoadingStateChange(this, isLoading, canGoBack,
canGoForward);
}
}
}
}
void CefBrowserImpl::OnLoadStart(blink::WebLocalFrame* frame) {
if (is_swapped_out())
return;
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
if (app.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
app->GetRenderProcessHandler();
if (handler.get()) {
CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
if (load_handler.get()) {
CefRefPtr<CefFrameImpl> cef_frame = GetWebFrameImpl(frame);
load_handler->OnLoadStart(this, cef_frame.get());
}
}
}
}
void CefBrowserImpl::OnLoadEnd(blink::WebLocalFrame* frame) {
if (is_swapped_out())
return;
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
if (app.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
app->GetRenderProcessHandler();
if (handler.get()) {
CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
if (load_handler.get()) {
CefRefPtr<CefFrameImpl> cef_frame = GetWebFrameImpl(frame);
int httpStatusCode = frame->dataSource()->response().httpStatusCode();
load_handler->OnLoadEnd(this, cef_frame.get(), httpStatusCode);
}
}
}
}
void CefBrowserImpl::OnLoadError(blink::WebLocalFrame* frame,
const blink::WebURLError& error) {
if (is_swapped_out())
return;
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
if (app.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
app->GetRenderProcessHandler();
if (handler.get()) {
CefRefPtr<CefLoadHandler> load_handler = handler->GetLoadHandler();
if (load_handler.get()) {
CefRefPtr<CefFrameImpl> cef_frame = GetWebFrameImpl(frame);
const cef_errorcode_t errorCode =
static_cast<cef_errorcode_t>(error.reason);
const std::string& errorText = error.localizedDescription.utf8();
const GURL& failedUrl = error.unreachableURL;
load_handler->OnLoadError(this, cef_frame.get(), errorCode, errorText,
failedUrl.spec());
}
}
}
}

View File

@@ -0,0 +1,160 @@
// 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.
#ifndef CEF_LIBCEF_RENDERER_BROWSER_IMPL_H_
#define CEF_LIBCEF_RENDERER_BROWSER_IMPL_H_
#pragma once
#include <map>
#include <string>
#include <vector>
#include "include/cef_browser.h"
#include "include/cef_client.h"
#include "libcef/common/tracker.h"
#include "libcef/renderer/frame_impl.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/renderer/render_view_observer.h"
class GURL;
struct CefMsg_LoadRequest_Params;
struct Cef_Request_Params;
struct Cef_Response_Params;
class CefContentRendererClient;
class CefResponseManager;
namespace base {
class ListValue;
}
// Renderer plumbing for CEF features. There is a one-to-one relationship
// between RenderView on the renderer side and RenderViewHost on the browser
// side.
//
// RenderViewObserver: Interface for observing RenderView notifications and IPC
// messages. IPC messages received by the RenderView will be forwarded to this
// RenderViewObserver implementation. IPC messages sent using
// RenderViewObserver::Send() will be forwarded to the RenderView. Use
// RenderViewObserver::routing_id() when sending IPC messages.
class CefBrowserImpl : public CefBrowser,
public content::RenderViewObserver {
public:
// Returns the browser associated with the specified RenderView.
static CefRefPtr<CefBrowserImpl> GetBrowserForView(content::RenderView* view);
// Returns the browser associated with the specified main WebFrame.
static CefRefPtr<CefBrowserImpl> GetBrowserForMainFrame(
blink::WebFrame* frame);
// CefBrowser methods.
CefRefPtr<CefBrowserHost> GetHost() override;
bool CanGoBack() override;
void GoBack() override;
bool CanGoForward() override;
void GoForward() override;
bool IsLoading() override;
void Reload() override;
void ReloadIgnoreCache() override;
void StopLoad() override;
int GetIdentifier() override;
bool IsSame(CefRefPtr<CefBrowser> that) override;
bool IsPopup() override;
bool HasDocument() override;
CefRefPtr<CefFrame> GetMainFrame() override;
CefRefPtr<CefFrame> GetFocusedFrame() override;
CefRefPtr<CefFrame> GetFrame(int64 identifier) override;
CefRefPtr<CefFrame> GetFrame(const CefString& name) override;
size_t GetFrameCount() override;
void GetFrameIdentifiers(std::vector<int64>& identifiers) override;
void GetFrameNames(std::vector<CefString>& names) override;
bool SendProcessMessage(
CefProcessId target_process,
CefRefPtr<CefProcessMessage> message) override;
CefBrowserImpl(content::RenderView* render_view,
int browser_id,
bool is_popup,
bool is_windowless);
~CefBrowserImpl() override;
void LoadRequest(const CefMsg_LoadRequest_Params& params);
// Avoids unnecessary string type conversions.
bool SendProcessMessage(CefProcessId target_process,
const std::string& name,
base::ListValue* arguments,
bool user_initiated);
// Returns the matching CefFrameImpl reference or creates a new one.
CefRefPtr<CefFrameImpl> GetWebFrameImpl(blink::WebFrame* frame);
CefRefPtr<CefFrameImpl> GetWebFrameImpl(int64 frame_id);
// Frame objects will be deleted immediately before the frame is closed.
void AddFrameObject(int64 frame_id, CefTrackNode* tracked_object);
int browser_id() const { return browser_id_; }
bool is_popup() const { return is_popup_; }
bool is_windowless() const { return is_windowless_; }
content::RenderView* render_view() const {
return content::RenderViewObserver::render_view();
}
bool is_swapped_out() const;
private:
// RenderViewObserver methods.
void OnDestruct() override;
void DidStartLoading() override;
void DidStopLoading() override;
void DidFailLoad(blink::WebLocalFrame* frame,
const blink::WebURLError& error) override;
void DidFinishLoad(blink::WebLocalFrame* frame) override;
void DidStartProvisionalLoad(blink::WebLocalFrame* frame) override;
void DidFailProvisionalLoad(
blink::WebLocalFrame* frame,
const blink::WebURLError& error) override;
void DidCommitProvisionalLoad(blink::WebLocalFrame* frame,
bool is_new_navigation) override;
void FrameDetached(blink::WebFrame* frame) override;
void FocusedNodeChanged(const blink::WebNode& node) override;
void DidCreateDataSource(blink::WebLocalFrame* frame,
blink::WebDataSource* ds) override;
bool OnMessageReceived(const IPC::Message& message) override;
// RenderViewObserver::OnMessageReceived message handlers.
void OnRequest(const Cef_Request_Params& params);
void OnResponse(const Cef_Response_Params& params);
void OnResponseAck(int request_id);
void OnLoadingStateChange(bool isLoading);
void OnLoadStart(blink::WebLocalFrame* frame);
void OnLoadEnd(blink::WebLocalFrame* frame);
void OnLoadError(blink::WebLocalFrame* frame,
const blink::WebURLError& error);
// ID of the browser that this RenderView is associated with. During loading
// of cross-origin requests multiple RenderViews may be associated with the
// same browser ID.
int browser_id_;
bool is_popup_;
bool is_windowless_;
// Map of unique frame ids to CefFrameImpl references.
typedef std::map<int64, CefRefPtr<CefFrameImpl> > FrameMap;
FrameMap frames_;
// Map of unique frame ids to CefTrackManager objects that need to be cleaned
// up when the frame is deleted.
typedef std::map<int64, CefRefPtr<CefTrackManager> > FrameObjectMap;
FrameObjectMap frame_objects_;
// Manages response registrations.
scoped_ptr<CefResponseManager> response_manager_;
IMPLEMENT_REFCOUNTING(CefBrowserImpl);
DISALLOW_COPY_AND_ASSIGN(CefBrowserImpl);
};
#endif // CEF_LIBCEF_RENDERER_BROWSER_IMPL_H_

View File

@@ -0,0 +1,831 @@
// Copyright (c) 2013 The Chromium Embedded Framework Authors.
// Portions copyright (c) 2012 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 "base/compiler_specific.h"
#include "config.h"
MSVC_PUSH_WARNING_LEVEL(0);
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8RecursionScope.h"
MSVC_POP_WARNING();
#undef ceil
#undef FROM_HERE
#undef LOG
#include "libcef/renderer/content_renderer_client.h"
#include "libcef/browser/context.h"
#include "libcef/common/cef_messages.h"
#include "libcef/common/cef_switches.h"
#include "libcef/common/content_client.h"
#include "libcef/common/request_impl.h"
#include "libcef/common/values_impl.h"
#include "libcef/renderer/browser_impl.h"
#include "libcef/renderer/render_frame_observer.h"
#include "libcef/renderer/render_message_filter.h"
#include "libcef/renderer/render_process_observer.h"
#include "libcef/renderer/thread_util.h"
#include "libcef/renderer/v8_impl.h"
#include "libcef/renderer/webkit_glue.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/renderer/loadtimes_extension_bindings.h"
#include "chrome/renderer/pepper/chrome_pdf_print_client.h"
#include "chrome/renderer/printing/print_web_view_helper.h"
#include "chrome/renderer/spellchecker/spellcheck.h"
#include "chrome/renderer/spellchecker/spellcheck_provider.h"
#include "components/pdf/renderer/ppb_pdf_impl.h"
#include "components/web_cache/renderer/web_cache_render_process_observer.h"
#include "content/child/child_thread.h"
#include "content/child/worker_task_runner.h"
#include "content/common/frame_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_constants.h"
#include "content/public/common/content_paths.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/render_view_visitor.h"
#include "content/renderer/render_frame_impl.h"
#include "ipc/ipc_sync_channel.h"
#include "media/base/media.h"
#include "ppapi/c/private/ppb_pdf.h"
#include "third_party/WebKit/public/platform/WebPrerenderingSupport.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebWorkerRunLoop.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebPluginParams.h"
#include "third_party/WebKit/public/web/WebPrerendererClient.h"
#include "third_party/WebKit/public/web/WebRuntimeFeatures.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "v8/include/v8.h"
#if defined(OS_WIN)
#include "base/win/iat_patch_function.h"
#endif
namespace {
// Stub implementation of blink::WebPrerenderingSupport.
class CefPrerenderingSupport : public blink::WebPrerenderingSupport {
private:
void add(const blink::WebPrerender& prerender) override {}
void cancel(const blink::WebPrerender& prerender) override {}
void abandon(const blink::WebPrerender& prerender) override {}
};
// Stub implementation of blink::WebPrerendererClient.
class CefPrerendererClient : public content::RenderViewObserver,
public blink::WebPrerendererClient {
public:
explicit CefPrerendererClient(content::RenderView* render_view)
: content::RenderViewObserver(render_view) {
DCHECK(render_view);
render_view->GetWebView()->setPrerendererClient(this);
}
private:
~CefPrerendererClient() override {}
void willAddPrerender(blink::WebPrerender* prerender) override {}
};
// Implementation of SequencedTaskRunner for WebWorker threads.
class CefWebWorkerTaskRunner : public base::SequencedTaskRunner,
public content::WorkerTaskRunner::Observer {
public:
CefWebWorkerTaskRunner(content::WorkerTaskRunner* runner,
int worker_id)
: runner_(runner),
worker_id_(worker_id) {
DCHECK(runner_);
DCHECK_GT(worker_id_, 0);
DCHECK(RunsTasksOnCurrentThread());
// Adds an observer for the current thread.
runner_->AddStopObserver(this);
}
// SequencedTaskRunner methods:
bool PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) override {
return PostDelayedTask(from_here, task, delay);
}
// TaskRunner methods:
bool PostDelayedTask(const tracked_objects::Location& from_here,
const base::Closure& task,
base::TimeDelta delay) override {
if (delay != base::TimeDelta())
LOG(WARNING) << "Delayed tasks are not supported on WebWorker threads";
runner_->PostTask(worker_id_, task);
return true;
}
bool RunsTasksOnCurrentThread() const override {
return (runner_->CurrentWorkerId() == worker_id_);
}
// WorkerTaskRunner::Observer methods:
void OnWorkerRunLoopStopped() override {
CefContentRendererClient::Get()->RemoveWorkerTaskRunner(worker_id_);
}
private:
content::WorkerTaskRunner* runner_;
int worker_id_;
};
class CefPrintWebViewHelperDelegate :
public printing::PrintWebViewHelper::Delegate {
public:
CefPrintWebViewHelperDelegate() {}
bool CancelPrerender(content::RenderView* render_view,
int routing_id) override {
return false;
}
blink::WebElement GetPdfElement(blink::WebLocalFrame* frame) override {
return blink::WebElement();
}
private:
DISALLOW_COPY_AND_ASSIGN(CefPrintWebViewHelperDelegate);
};
#if defined(OS_WIN)
static base::win::IATPatchFunction g_iat_patch_createdca;
HDC WINAPI CreateDCAPatch(LPCSTR driver_name,
LPCSTR device_name,
LPCSTR output,
const void* init_data) {
DCHECK(std::string("DISPLAY") == std::string(driver_name));
DCHECK(!device_name);
DCHECK(!output);
DCHECK(!init_data);
// CreateDC fails behind the sandbox, but not CreateCompatibleDC.
return CreateCompatibleDC(NULL);
}
static base::win::IATPatchFunction g_iat_patch_get_font_data;
DWORD WINAPI GetFontDataPatch(HDC hdc,
DWORD table,
DWORD offset,
LPVOID buffer,
DWORD length) {
int rv = GetFontData(hdc, table, offset, buffer, length);
if (rv == GDI_ERROR && hdc) {
HFONT font = static_cast<HFONT>(GetCurrentObject(hdc, OBJ_FONT));
LOGFONT logfont;
if (GetObject(font, sizeof(LOGFONT), &logfont)) {
std::vector<char> font_data;
content::RenderThread::Get()->PreCacheFont(logfont);
rv = GetFontData(hdc, table, offset, buffer, length);
content::RenderThread::Get()->ReleaseCachedFonts();
}
}
return rv;
}
#endif // OS_WIN
} // namespace
CefContentRendererClient::CefContentRendererClient()
: devtools_agent_count_(0),
uncaught_exception_stack_size_(0),
single_process_cleanup_complete_(false) {
}
CefContentRendererClient::~CefContentRendererClient() {
}
// static
CefContentRendererClient* CefContentRendererClient::Get() {
return static_cast<CefContentRendererClient*>(
CefContentClient::Get()->renderer());
}
CefRefPtr<CefBrowserImpl> CefContentRendererClient::GetBrowserForView(
content::RenderView* view) {
CEF_REQUIRE_RT_RETURN(NULL);
BrowserMap::const_iterator it = browsers_.find(view);
if (it != browsers_.end())
return it->second;
return NULL;
}
CefRefPtr<CefBrowserImpl> CefContentRendererClient::GetBrowserForMainFrame(
blink::WebFrame* frame) {
CEF_REQUIRE_RT_RETURN(NULL);
BrowserMap::const_iterator it = browsers_.begin();
for (; it != browsers_.end(); ++it) {
content::RenderView* render_view = it->second->render_view();
if (render_view && render_view->GetWebView() &&
render_view->GetWebView()->mainFrame() == frame) {
return it->second;
}
}
return NULL;
}
void CefContentRendererClient::OnBrowserDestroyed(CefBrowserImpl* browser) {
BrowserMap::iterator it = browsers_.begin();
for (; it != browsers_.end(); ++it) {
if (it->second.get() == browser) {
browsers_.erase(it);
return;
}
}
// No browser was found in the map.
NOTREACHED();
}
void CefContentRendererClient::WebKitInitialized() {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
// Create global objects associated with the default Isolate.
CefV8IsolateCreated();
blink::WebRuntimeFeatures::enableMediaPlayer(
media::IsMediaLibraryInitialized());
// TODO(cef): Enable these once the implementation supports it.
blink::WebRuntimeFeatures::enableNotifications(false);
#if defined(OS_WIN)
// Need to patch a few functions for font loading to work correctly.
// From chrome/renderer/chrome_render_process_observer.cc.
base::FilePath pdf;
if (PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf) &&
base::PathExists(pdf)) {
g_iat_patch_createdca.Patch(
pdf.value().c_str(), "gdi32.dll", "CreateDCA", CreateDCAPatch);
g_iat_patch_get_font_data.Patch(
pdf.value().c_str(), "gdi32.dll", "GetFontData", GetFontDataPatch);
}
#endif // defined(OS_WIN)
const CefContentClient::SchemeInfoList* schemes =
CefContentClient::Get()->GetCustomSchemes();
if (!schemes->empty()) {
// Register the custom schemes.
CefContentClient::SchemeInfoList::const_iterator it = schemes->begin();
for (; it != schemes->end(); ++it) {
const CefContentClient::SchemeInfo& info = *it;
const blink::WebString& scheme =
blink::WebString::fromUTF8(info.scheme_name);
if (info.is_standard) {
// Standard schemes must also be registered as CORS enabled to support
// CORS-restricted requests (for example, XMLHttpRequest redirects).
blink::WebSecurityPolicy::registerURLSchemeAsCORSEnabled(scheme);
}
if (info.is_local)
blink::WebSecurityPolicy::registerURLSchemeAsLocal(scheme);
if (info.is_display_isolated)
blink::WebSecurityPolicy::registerURLSchemeAsDisplayIsolated(scheme);
}
}
if (!cross_origin_whitelist_entries_.empty()) {
// Add the cross-origin white list entries.
for (size_t i = 0; i < cross_origin_whitelist_entries_.size(); ++i) {
const Cef_CrossOriginWhiteListEntry_Params& entry =
cross_origin_whitelist_entries_[i];
GURL gurl = GURL(entry.source_origin);
blink::WebSecurityPolicy::addOriginAccessWhitelistEntry(
gurl,
blink::WebString::fromUTF8(entry.target_protocol),
blink::WebString::fromUTF8(entry.target_domain),
entry.allow_target_subdomains);
}
cross_origin_whitelist_entries_.clear();
}
// The number of stack trace frames to capture for uncaught exceptions.
if (command_line->HasSwitch(switches::kUncaughtExceptionStackSize)) {
int uncaught_exception_stack_size = 0;
base::StringToInt(
command_line->GetSwitchValueASCII(
switches::kUncaughtExceptionStackSize),
&uncaught_exception_stack_size);
if (uncaught_exception_stack_size > 0) {
uncaught_exception_stack_size_ = uncaught_exception_stack_size;
CefV8SetUncaughtExceptionStackSize(uncaught_exception_stack_size_);
}
}
// Notify the render process handler.
CefRefPtr<CefApp> application = CefContentClient::Get()->application();
if (application.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
application->GetRenderProcessHandler();
if (handler.get())
handler->OnWebKitInitialized();
}
}
void CefContentRendererClient::OnRenderProcessShutdown() {
// Destroy global objects associated with the default Isolate.
CefV8IsolateDestroyed();
}
void CefContentRendererClient::DevToolsAgentAttached() {
CEF_REQUIRE_RT();
++devtools_agent_count_;
}
void CefContentRendererClient::DevToolsAgentDetached() {
CEF_REQUIRE_RT();
--devtools_agent_count_;
if (devtools_agent_count_ == 0 && uncaught_exception_stack_size_ > 0) {
// When the last DevToolsAgent is detached the stack size is set to 0.
// Restore the user-specified stack size here.
CefV8SetUncaughtExceptionStackSize(uncaught_exception_stack_size_);
// And do the same for any WebWorker threads.
WorkerTaskRunnerMap map_copy;
{
base::AutoLock lock_scope(worker_task_runner_lock_);
map_copy = worker_task_runner_map_;
}
WorkerTaskRunnerMap::const_iterator it = map_copy.begin();
for (; it != map_copy.end(); ++it) {
it->second->PostTask(FROM_HERE,
base::Bind(CefV8SetUncaughtExceptionStackSize,
uncaught_exception_stack_size_));
}
}
}
scoped_refptr<base::SequencedTaskRunner>
CefContentRendererClient::GetCurrentTaskRunner() {
// Check if currently on the render thread.
if (CEF_CURRENTLY_ON_RT())
return render_task_runner_;
// Check if a WebWorker exists for the current thread.
content::WorkerTaskRunner* worker_runner =
content::WorkerTaskRunner::Instance();
int worker_id = worker_runner->CurrentWorkerId();
if (worker_id > 0) {
base::AutoLock lock_scope(worker_task_runner_lock_);
WorkerTaskRunnerMap::const_iterator it =
worker_task_runner_map_.find(worker_id);
if (it != worker_task_runner_map_.end())
return it->second;
scoped_refptr<base::SequencedTaskRunner> task_runner =
new CefWebWorkerTaskRunner(worker_runner, worker_id);
worker_task_runner_map_[worker_id] = task_runner;
return task_runner;
}
return NULL;
}
scoped_refptr<base::SequencedTaskRunner>
CefContentRendererClient::GetWorkerTaskRunner(int worker_id) {
base::AutoLock lock_scope(worker_task_runner_lock_);
WorkerTaskRunnerMap::const_iterator it =
worker_task_runner_map_.find(worker_id);
if (it != worker_task_runner_map_.end())
return it->second;
return NULL;
}
void CefContentRendererClient::RemoveWorkerTaskRunner(int worker_id) {
base::AutoLock lock_scope(worker_task_runner_lock_);
WorkerTaskRunnerMap::iterator it = worker_task_runner_map_.find(worker_id);
if (it != worker_task_runner_map_.end())
worker_task_runner_map_.erase(it);
}
void CefContentRendererClient::RunSingleProcessCleanup() {
DCHECK(content::RenderProcessHost::run_renderer_in_process());
// Make sure the render thread was actually started.
if (!render_task_runner_.get())
return;
if (content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
RunSingleProcessCleanupOnUIThread();
} else {
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
base::Bind(&CefContentRendererClient::RunSingleProcessCleanupOnUIThread,
base::Unretained(this)));
}
// Wait for the render thread cleanup to complete. Spin instead of using
// base::WaitableEvent because calling Wait() is not allowed on the UI
// thread.
bool complete = false;
do {
{
base::AutoLock lock_scope(single_process_cleanup_lock_);
complete = single_process_cleanup_complete_;
}
if (!complete)
base::PlatformThread::YieldCurrentThread();
} while (!complete);
}
void CefContentRendererClient::RenderThreadStarted() {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
render_task_runner_ = base::MessageLoopProxy::current();
observer_.reset(new CefRenderProcessObserver());
web_cache_observer_.reset(new web_cache::WebCacheRenderProcessObserver());
content::RenderThread* thread = content::RenderThread::Get();
thread->AddObserver(observer_.get());
thread->AddObserver(web_cache_observer_.get());
thread->GetChannel()->AddFilter(new CefRenderMessageFilter);
thread->RegisterExtension(extensions_v8::LoadTimesExtension::Get());
if (!command_line->HasSwitch(switches::kDisableSpellChecking)) {
spellcheck_.reset(new SpellCheck());
thread->AddObserver(spellcheck_.get());
}
if (content::RenderProcessHost::run_renderer_in_process()) {
// When running in single-process mode register as a destruction observer
// on the render thread's MessageLoop.
base::MessageLoop::current()->AddDestructionObserver(this);
}
// Note that under Linux, the media library will normally already have
// been initialized by the Zygote before this instance became a Renderer.
base::FilePath media_path;
PathService::Get(content::DIR_MEDIA_LIBS, &media_path);
if (!media_path.empty())
media::InitializeMediaLibrary(media_path);
blink::WebPrerenderingSupport::initialize(new CefPrerenderingSupport());
// Retrieve the new render thread information synchronously.
CefProcessHostMsg_GetNewRenderThreadInfo_Params params;
thread->Send(new CefProcessHostMsg_GetNewRenderThreadInfo(&params));
// Cross-origin entries need to be added after WebKit is initialized.
cross_origin_whitelist_entries_ = params.cross_origin_whitelist_entries;
pdf_print_client_.reset(new ChromePDFPrintClient());
pdf::PPB_PDF_Impl::SetPrintClient(pdf_print_client_.get());
// Notify the render process handler.
CefRefPtr<CefApp> application = CefContentClient::Get()->application();
if (application.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
application->GetRenderProcessHandler();
if (handler.get()) {
CefRefPtr<CefListValueImpl> listValuePtr(
new CefListValueImpl(&params.extra_info, false, true));
handler->OnRenderThreadCreated(listValuePtr.get());
listValuePtr->Detach(NULL);
}
}
}
void CefContentRendererClient::RenderFrameCreated(
content::RenderFrame* render_frame) {
new CefRenderFrameObserver(render_frame);
BrowserCreated(render_frame->GetRenderView(), render_frame);
}
void CefContentRendererClient::RenderViewCreated(
content::RenderView* render_view) {
BrowserCreated(render_view, render_view->GetMainRenderFrame());
}
bool CefContentRendererClient::OverrideCreatePlugin(
content::RenderFrame* render_frame,
blink::WebLocalFrame* frame,
const blink::WebPluginParams& params,
blink::WebPlugin** plugin) {
CefRefPtr<CefBrowserImpl> browser =
CefBrowserImpl::GetBrowserForMainFrame(frame->top());
if (!browser.get() || !browser->is_windowless())
return false;
#if defined(ENABLE_PLUGINS)
if (base::UTF16ToASCII(params.mimeType) == content::kBrowserPluginMimeType)
return false;
content::RenderFrameImpl* render_frame_impl =
static_cast<content::RenderFrameImpl*>(render_frame);
content::WebPluginInfo info;
std::string mime_type;
bool found = false;
render_frame_impl->Send(
new FrameHostMsg_GetPluginInfo(
render_frame_impl->GetRoutingID(),
params.url,
frame->top()->document().url(),
params.mimeType.utf8(),
&found,
&info,
&mime_type));
if (!found)
return false;
bool flash = LowerCaseEqualsASCII(mime_type,
"application/x-shockwave-flash");
bool silverlight = StartsWithASCII(mime_type,
"application/x-silverlight", false);
if (flash) {
// "wmode" values of "opaque" or "transparent" are allowed.
size_t size = params.attributeNames.size();
for (size_t i = 0; i < size; ++i) {
std::string name = params.attributeNames[i].utf8();
if (name == "wmode") {
std::string value = params.attributeValues[i].utf8();
if (value == "opaque" || value == "transparent")
flash = false;
break;
}
}
}
if (flash || silverlight) {
// Force Flash and Silverlight plugins to use windowless mode.
blink::WebPluginParams params_to_use = params;
params_to_use.mimeType = blink::WebString::fromUTF8(mime_type);
size_t size = params.attributeNames.size();
blink::WebVector<blink::WebString> new_names(size+1),
new_values(size+1);
for (size_t i = 0; i < size; ++i) {
new_names[i] = params.attributeNames[i];
new_values[i] = params.attributeValues[i];
}
if (flash) {
new_names[size] = "wmode";
new_values[size] = "opaque";
} else if (silverlight) {
new_names[size] = "windowless";
new_values[size] = "true";
}
params_to_use.attributeNames.swap(new_names);
params_to_use.attributeValues.swap(new_values);
*plugin = render_frame_impl->CreatePlugin(
frame, info, params_to_use,
content::RenderFrame::POWER_SAVER_MODE_ESSENTIAL);
return true;
}
#endif // defined(ENABLE_PLUGINS)
return false;
}
bool CefContentRendererClient::HandleNavigation(
content::RenderFrame* render_frame,
content::DocumentState* document_state,
int opener_id,
blink::WebFrame* frame,
const blink::WebURLRequest& request,
blink::WebNavigationType type,
blink::WebNavigationPolicy default_policy,
bool is_redirect) {
CefRefPtr<CefApp> application = CefContentClient::Get()->application();
if (application.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
application->GetRenderProcessHandler();
if (handler.get()) {
CefRefPtr<CefBrowserImpl> browserPtr =
CefBrowserImpl::GetBrowserForMainFrame(frame->top());
DCHECK(browserPtr.get());
if (browserPtr.get()) {
CefRefPtr<CefFrameImpl> framePtr = browserPtr->GetWebFrameImpl(frame);
CefRefPtr<CefRequest> requestPtr(CefRequest::Create());
CefRequestImpl* requestImpl =
static_cast<CefRequestImpl*>(requestPtr.get());
requestImpl->Set(request);
requestImpl->SetReadOnly(true);
cef_navigation_type_t navigation_type = NAVIGATION_OTHER;
switch (type) {
case blink::WebNavigationTypeLinkClicked:
navigation_type = NAVIGATION_LINK_CLICKED;
break;
case blink::WebNavigationTypeFormSubmitted:
navigation_type = NAVIGATION_FORM_SUBMITTED;
break;
case blink::WebNavigationTypeBackForward:
navigation_type = NAVIGATION_BACK_FORWARD;
break;
case blink::WebNavigationTypeReload:
navigation_type = NAVIGATION_RELOAD;
break;
case blink::WebNavigationTypeFormResubmitted:
navigation_type = NAVIGATION_FORM_RESUBMITTED;
break;
case blink::WebNavigationTypeOther:
navigation_type = NAVIGATION_OTHER;
break;
}
if (handler->OnBeforeNavigation(browserPtr.get(), framePtr.get(),
requestPtr.get(), navigation_type,
is_redirect)) {
return true;
}
}
}
}
return false;
}
void CefContentRendererClient::DidCreateScriptContext(
blink::WebFrame* frame, v8::Handle<v8::Context> context,
int extension_group, int world_id) {
CefRefPtr<CefBrowserImpl> browserPtr =
CefBrowserImpl::GetBrowserForMainFrame(frame->top());
DCHECK(browserPtr.get());
if (!browserPtr.get())
return;
CefRefPtr<CefFrameImpl> framePtr = browserPtr->GetWebFrameImpl(frame);
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Context::Scope scope(context);
blink::V8RecursionScope recursion_scope(isolate);
CefRefPtr<CefV8Context> contextPtr(new CefV8ContextImpl(isolate, context));
// Notify the render process handler.
CefRefPtr<CefApp> application = CefContentClient::Get()->application();
if (application.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
application->GetRenderProcessHandler();
if (handler.get())
handler->OnContextCreated(browserPtr.get(), framePtr.get(), contextPtr);
}
}
const void* CefContentRendererClient::CreatePPAPIInterface(
const std::string& interface_name) {
#if defined(ENABLE_PLUGINS)
// Used for in-process PDF plugin.
if (interface_name == PPB_PDF_INTERFACE)
return pdf::PPB_PDF_Impl::GetInterface();
#endif
return NULL;
}
void CefContentRendererClient::WillReleaseScriptContext(
blink::WebLocalFrame* frame,
v8::Handle<v8::Context> context,
int world_id) {
// Notify the render process handler.
CefRefPtr<CefApp> application = CefContentClient::Get()->application();
if (application.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
application->GetRenderProcessHandler();
if (handler.get()) {
CefRefPtr<CefBrowserImpl> browserPtr =
CefBrowserImpl::GetBrowserForMainFrame(frame->top());
DCHECK(browserPtr.get());
if (browserPtr.get()) {
CefRefPtr<CefFrameImpl> framePtr = browserPtr->GetWebFrameImpl(frame);
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
v8::Context::Scope scope(context);
blink::V8RecursionScope recursion_scope(isolate);
CefRefPtr<CefV8Context> contextPtr(
new CefV8ContextImpl(isolate, context));
handler->OnContextReleased(browserPtr.get(), framePtr.get(),
contextPtr);
}
}
}
CefV8ReleaseContext(context);
}
void CefContentRendererClient::WillDestroyCurrentMessageLoop() {
base::AutoLock lock_scope(single_process_cleanup_lock_);
single_process_cleanup_complete_ = true;
}
void CefContentRendererClient::BrowserCreated(
content::RenderView* render_view,
content::RenderFrame* render_frame) {
const base::CommandLine* command_line =
base::CommandLine::ForCurrentProcess();
// Retrieve the browser information synchronously. This will also register
// the routing ids with the browser info object in the browser process.
CefProcessHostMsg_GetNewBrowserInfo_Params params;
content::RenderThread::Get()->Send(
new CefProcessHostMsg_GetNewBrowserInfo(
render_view->GetRoutingID(),
render_frame->GetRoutingID(),
&params));
DCHECK_GT(params.browser_id, 0);
// Don't create another browser object if one already exists for the view.
if (GetBrowserForView(render_view).get())
return;
#if defined(OS_MACOSX)
// FIXME: It would be better if this API would be a callback from the
// WebKit layer, or if it would be exposed as an WebView instance method; the
// current implementation uses a static variable, and WebKit needs to be
// patched in order to make it work for each WebView instance
render_view->GetWebView()->setUseExternalPopupMenusThisInstance(
!params.is_windowless);
#endif
CefRefPtr<CefBrowserImpl> browser =
new CefBrowserImpl(render_view, params.browser_id, params.is_popup,
params.is_windowless);
browsers_.insert(std::make_pair(render_view, browser));
new CefPrerendererClient(render_view);
new printing::PrintWebViewHelper(
render_view,
false,
true,
make_scoped_ptr<printing::PrintWebViewHelper::Delegate>(
new CefPrintWebViewHelperDelegate()));
if (!command_line->HasSwitch(switches::kDisableSpellChecking))
new SpellCheckProvider(render_view, spellcheck_.get());
// Notify the render process handler.
CefRefPtr<CefApp> application = CefContentClient::Get()->application();
if (application.get()) {
CefRefPtr<CefRenderProcessHandler> handler =
application->GetRenderProcessHandler();
if (handler.get())
handler->OnBrowserCreated(browser.get());
}
}
void CefContentRendererClient::RunSingleProcessCleanupOnUIThread() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Clean up the single existing RenderProcessHost.
content::RenderProcessHost* host = NULL;
content::RenderProcessHost::iterator iterator(
content::RenderProcessHost::AllHostsIterator());
if (!iterator.IsAtEnd()) {
host = iterator.GetCurrentValue();
host->Cleanup();
iterator.Advance();
DCHECK(iterator.IsAtEnd());
}
DCHECK(host);
// Clear the run_renderer_in_process() flag to avoid a DCHECK in the
// RenderProcessHost destructor.
content::RenderProcessHost::SetRunRendererInProcess(false);
// Deletion of the RenderProcessHost object will stop the render thread and
// result in a call to WillDestroyCurrentMessageLoop.
// Cleanup() will cause deletion to be posted as a task on the UI thread but
// this task will only execute when running in multi-threaded message loop
// mode (because otherwise the UI message loop has already stopped). Therefore
// we need to explicitly delete the object when not running in this mode.
if (!CefContext::Get()->settings().multi_threaded_message_loop)
delete host;
}

View File

@@ -0,0 +1,150 @@
// Copyright (c) 2013 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.
#ifndef CEF_LIBCEF_RENDERER_CONTENT_RENDERER_CLIENT_H_
#define CEF_LIBCEF_RENDERER_CONTENT_RENDERER_CLIENT_H_
#pragma once
#include <list>
#include <map>
#include <string>
#include <vector>
#include "libcef/renderer/browser_impl.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/sequenced_task_runner.h"
#include "content/public/renderer/content_renderer_client.h"
namespace web_cache {
class WebCacheRenderProcessObserver;
}
class CefRenderProcessObserver;
struct Cef_CrossOriginWhiteListEntry_Params;
class ChromePDFPrintClient;
class SpellCheck;
class CefContentRendererClient : public content::ContentRendererClient,
public base::MessageLoop::DestructionObserver {
public:
CefContentRendererClient();
~CefContentRendererClient() override;
// Returns the singleton CefContentRendererClient instance.
static CefContentRendererClient* Get();
// Returns the browser associated with the specified RenderView.
CefRefPtr<CefBrowserImpl> GetBrowserForView(content::RenderView* view);
// Returns the browser associated with the specified main WebFrame.
CefRefPtr<CefBrowserImpl> GetBrowserForMainFrame(blink::WebFrame* frame);
// Called from CefBrowserImpl::OnDestruct().
void OnBrowserDestroyed(CefBrowserImpl* browser);
// Render thread task runner.
base::SequencedTaskRunner* render_task_runner() const {
return render_task_runner_.get();
}
int uncaught_exception_stack_size() const {
return uncaught_exception_stack_size_;
}
void WebKitInitialized();
void OnRenderProcessShutdown();
void DevToolsAgentAttached();
void DevToolsAgentDetached();
// Returns the task runner for the current thread. If this is a WebWorker
// thread and the task runner does not already exist it will be created.
// Returns NULL if the current thread is not a valid render process thread.
scoped_refptr<base::SequencedTaskRunner> GetCurrentTaskRunner();
// Returns the task runner for the specified worker ID or NULL if the
// specified worker ID is not valid.
scoped_refptr<base::SequencedTaskRunner> GetWorkerTaskRunner(int worker_id);
// Remove the task runner associated with the specified worker ID.
void RemoveWorkerTaskRunner(int worker_id);
// Perform cleanup work that needs to occur before shutdown when running in
// single-process mode. Blocks until cleanup is complete.
void RunSingleProcessCleanup();
// ContentRendererClient implementation.
void RenderThreadStarted() override;
void RenderFrameCreated(content::RenderFrame* render_frame) override;
void RenderViewCreated(content::RenderView* render_view) override;
bool OverrideCreatePlugin(
content::RenderFrame* render_frame,
blink::WebLocalFrame* frame,
const blink::WebPluginParams& params,
blink::WebPlugin** plugin) override;
bool HandleNavigation(content::RenderFrame* render_frame,
content::DocumentState* document_state,
int opener_id,
blink::WebFrame* frame,
const blink::WebURLRequest& request,
blink::WebNavigationType type,
blink::WebNavigationPolicy default_policy,
bool is_redirect) override;
void DidCreateScriptContext(blink::WebFrame* frame,
v8::Handle<v8::Context> context,
int extension_group,
int world_id) override;
const void* CreatePPAPIInterface(
const std::string& interface_name) override;
void WillReleaseScriptContext(blink::WebLocalFrame* frame,
v8::Handle<v8::Context> context,
int world_id);
// MessageLoop::DestructionObserver implementation.
void WillDestroyCurrentMessageLoop() override;
private:
void BrowserCreated(content::RenderView* render_view,
content::RenderFrame* render_frame);
// Perform cleanup work for single-process mode.
void RunSingleProcessCleanupOnUIThread();
scoped_refptr<base::SequencedTaskRunner> render_task_runner_;
scoped_ptr<CefRenderProcessObserver> observer_;
scoped_ptr<web_cache::WebCacheRenderProcessObserver> web_cache_observer_;
scoped_ptr<SpellCheck> spellcheck_;
// Map of RenderView pointers to CefBrowserImpl references.
typedef std::map<content::RenderView*, CefRefPtr<CefBrowserImpl> > BrowserMap;
BrowserMap browsers_;
// Cross-origin white list entries that need to be registered with WebKit.
typedef std::vector<Cef_CrossOriginWhiteListEntry_Params> CrossOriginList;
CrossOriginList cross_origin_whitelist_entries_;
scoped_ptr<ChromePDFPrintClient> pdf_print_client_;
int devtools_agent_count_;
int uncaught_exception_stack_size_;
// Map of worker thread IDs to task runners. Access must be protected by
// |worker_task_runner_lock_|.
typedef std::map<int, scoped_refptr<base::SequencedTaskRunner> >
WorkerTaskRunnerMap;
WorkerTaskRunnerMap worker_task_runner_map_;
base::Lock worker_task_runner_lock_;
// Used in single-process mode to test when cleanup is complete.
// Access must be protected by |single_process_cleanup_lock_|.
bool single_process_cleanup_complete_;
base::Lock single_process_cleanup_lock_;
};
#endif // CEF_LIBCEF_RENDERER_CONTENT_RENDERER_CLIENT_H_

View File

@@ -0,0 +1,238 @@
// 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/dom_document_impl.h"
#include "libcef/renderer/dom_node_impl.h"
#include "libcef/renderer/thread_util.h"
#include "base/logging.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebRange.h"
using blink::WebDocument;
using blink::WebElement;
using blink::WebFrame;
using blink::WebNode;
using blink::WebRange;
using blink::WebString;
using blink::WebURL;
CefDOMDocumentImpl::CefDOMDocumentImpl(CefBrowserImpl* browser,
WebFrame* frame)
: browser_(browser),
frame_(frame) {
const WebDocument& document = frame_->document();
DCHECK(!document.isNull());
}
CefDOMDocumentImpl::~CefDOMDocumentImpl() {
CEF_REQUIRE_RT();
// Verify that the Detach() method has been called.
DCHECK(frame_ == NULL);
}
CefDOMDocumentImpl::Type CefDOMDocumentImpl::GetType() {
if (!VerifyContext())
return DOM_DOCUMENT_TYPE_UNKNOWN;
const WebDocument& document = frame_->document();
if (document.isHTMLDocument())
return DOM_DOCUMENT_TYPE_HTML;
if (document.isXHTMLDocument())
return DOM_DOCUMENT_TYPE_XHTML;
if (document.isPluginDocument())
return DOM_DOCUMENT_TYPE_PLUGIN;
return DOM_DOCUMENT_TYPE_UNKNOWN;
}
CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetDocument() {
const WebDocument& document = frame_->document();
return GetOrCreateNode(document.document());
}
CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetBody() {
const WebDocument& document = frame_->document();
return GetOrCreateNode(document.body());
}
CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetHead() {
WebDocument document = frame_->document();
return GetOrCreateNode(document.head());
}
CefString CefDOMDocumentImpl::GetTitle() {
CefString str;
if (!VerifyContext())
return str;
const WebDocument& document = frame_->document();
const WebString& title = document.title();
if (!title.isNull())
str = title;
return str;
}
CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetElementById(const CefString& id) {
const WebDocument& document = frame_->document();
return GetOrCreateNode(document.getElementById(base::string16(id)));
}
CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetFocusedNode() {
const WebDocument& document = frame_->document();
return GetOrCreateNode(document.focusedElement());
}
bool CefDOMDocumentImpl::HasSelection() {
if (!VerifyContext())
return false;
return frame_->hasSelection();
}
int CefDOMDocumentImpl::GetSelectionStartOffset() {
if (!VerifyContext() || !frame_->hasSelection())
return 0;
const WebRange& range = frame_->selectionRange();
if (range.isNull())
return 0;
return range.startOffset();
}
int CefDOMDocumentImpl::GetSelectionEndOffset() {
if (!VerifyContext() || !frame_->hasSelection())
return 0;
const WebRange& range = frame_->selectionRange();
if (range.isNull())
return 0;
return range.endOffset();
}
CefString CefDOMDocumentImpl::GetSelectionAsMarkup() {
CefString str;
if (!VerifyContext() || !frame_->hasSelection())
return str;
const WebString& markup = frame_->selectionAsMarkup();
if (!markup.isNull())
str = markup;
return str;
}
CefString CefDOMDocumentImpl::GetSelectionAsText() {
CefString str;
if (!VerifyContext() || !frame_->hasSelection())
return str;
const WebString& text = frame_->selectionAsText();
if (!text.isNull())
str = text;
return str;
}
CefString CefDOMDocumentImpl::GetBaseURL() {
CefString str;
if (!VerifyContext())
return str;
const WebDocument& document = frame_->document();
const WebURL& url = document.baseURL();
if (!url.isNull()) {
GURL gurl = url;
str = gurl.spec();
}
return str;
}
CefString CefDOMDocumentImpl::GetCompleteURL(const CefString& partialURL) {
CefString str;
if (!VerifyContext())
return str;
const WebDocument& document = frame_->document();
const WebURL& url = document.completeURL(base::string16(partialURL));
if (!url.isNull()) {
GURL gurl = url;
str = gurl.spec();
}
return str;
}
CefRefPtr<CefDOMNode> CefDOMDocumentImpl::GetOrCreateNode(
const blink::WebNode& node) {
if (!VerifyContext())
return NULL;
// Nodes may potentially be null.
if (node.isNull())
return NULL;
if (!node_map_.empty()) {
// Locate the existing node, if any.
NodeMap::const_iterator it = node_map_.find(node);
if (it != node_map_.end())
return it->second;
}
// Create the new node object.
CefRefPtr<CefDOMNode> nodeImpl(new CefDOMNodeImpl(this, node));
node_map_.insert(std::make_pair(node, nodeImpl.get()));
return nodeImpl;
}
void CefDOMDocumentImpl::RemoveNode(const blink::WebNode& node) {
if (!VerifyContext())
return;
if (!node_map_.empty()) {
NodeMap::iterator it = node_map_.find(node);
if (it != node_map_.end())
node_map_.erase(it);
}
}
void CefDOMDocumentImpl::Detach() {
if (!VerifyContext())
return;
// If you hit this assert it means that you are keeping references to node
// objects beyond the valid scope.
DCHECK(node_map_.empty());
// If you hit this assert it means that you are keeping references to this
// document object beyond the valid scope.
DCHECK(HasOneRef());
if (!node_map_.empty()) {
NodeMap::const_iterator it = node_map_.begin();
for (; it != node_map_.end(); ++it)
static_cast<CefDOMNodeImpl*>(it->second)->Detach();
node_map_.clear();
}
frame_ = NULL;
}
bool CefDOMDocumentImpl::VerifyContext() {
if (!CEF_CURRENTLY_ON_RT() || frame_ == NULL) {
NOTREACHED();
return false;
}
return true;
}

View File

@@ -0,0 +1,64 @@
// 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_DOM_DOCUMENT_IMPL_H_
#define CEF_LIBCEF_DOM_DOCUMENT_IMPL_H_
#pragma once
#include <map>
#include "include/cef_dom.h"
namespace blink {
class WebFrame;
class WebNode;
};
class CefBrowserImpl;
class CefDOMDocumentImpl : public CefDOMDocument {
public:
CefDOMDocumentImpl(CefBrowserImpl* browser,
blink::WebFrame* frame);
~CefDOMDocumentImpl() override;
// CefDOMDocument methods.
Type GetType() override;
CefRefPtr<CefDOMNode> GetDocument() override;
CefRefPtr<CefDOMNode> GetBody() override;
CefRefPtr<CefDOMNode> GetHead() override;
CefString GetTitle() override;
CefRefPtr<CefDOMNode> GetElementById(const CefString& id) override;
CefRefPtr<CefDOMNode> GetFocusedNode() override;
bool HasSelection() override;
int GetSelectionStartOffset() override;
int GetSelectionEndOffset() override;
CefString GetSelectionAsMarkup() override;
CefString GetSelectionAsText() override;
CefString GetBaseURL() override;
CefString GetCompleteURL(const CefString& partialURL) override;
CefBrowserImpl* GetBrowser() { return browser_; }
blink::WebFrame* GetFrame() { return frame_; }
// The document maintains a map of all existing node objects.
CefRefPtr<CefDOMNode> GetOrCreateNode(const blink::WebNode& node);
void RemoveNode(const blink::WebNode& node);
// Must be called before the object is destroyed.
void Detach();
// Verify that the object exists and is being accessed on the UI thread.
bool VerifyContext();
protected:
CefBrowserImpl* browser_;
blink::WebFrame* frame_;
typedef std::map<blink::WebNode, CefDOMNode*> NodeMap;
NodeMap node_map_;
IMPLEMENT_REFCOUNTING(CefDOMDocumentImpl);
};
#endif // CEF_LIBCEF_DOM_DOCUMENT_IMPL_H_

View File

@@ -0,0 +1,415 @@
// 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/dom_node_impl.h"
#include "libcef/common/tracker.h"
#include "libcef/renderer/browser_impl.h"
#include "libcef/renderer/dom_document_impl.h"
#include "libcef/renderer/thread_util.h"
#include "libcef/renderer/webkit_glue.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebDOMEvent.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebFormControlElement.h"
#include "third_party/WebKit/public/web/WebInputElement.h"
#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebSelectElement.h"
using blink::WebDocument;
using blink::WebDOMEvent;
using blink::WebElement;
using blink::WebFrame;
using blink::WebFormControlElement;
using blink::WebInputElement;
using blink::WebNode;
using blink::WebSelectElement;
using blink::WebString;
CefDOMNodeImpl::CefDOMNodeImpl(CefRefPtr<CefDOMDocumentImpl> document,
const blink::WebNode& node)
: document_(document),
node_(node) {
}
CefDOMNodeImpl::~CefDOMNodeImpl() {
CEF_REQUIRE_RT();
if (document_.get() && !node_.isNull()) {
// Remove the node from the document.
document_->RemoveNode(node_);
}
}
CefDOMNodeImpl::Type CefDOMNodeImpl::GetType() {
if (!VerifyContext())
return DOM_NODE_TYPE_UNSUPPORTED;
switch (node_.nodeType()) {
case WebNode::ElementNode:
return DOM_NODE_TYPE_ELEMENT;
case WebNode::AttributeNode:
return DOM_NODE_TYPE_ATTRIBUTE;
case WebNode::TextNode:
return DOM_NODE_TYPE_TEXT;
case WebNode::CDataSectionNode:
return DOM_NODE_TYPE_CDATA_SECTION;
case WebNode::ProcessingInstructionsNode:
return DOM_NODE_TYPE_PROCESSING_INSTRUCTIONS;
case WebNode::CommentNode:
return DOM_NODE_TYPE_COMMENT;
case WebNode::DocumentNode:
return DOM_NODE_TYPE_DOCUMENT;
case WebNode::DocumentTypeNode:
return DOM_NODE_TYPE_DOCUMENT_TYPE;
case WebNode::DocumentFragmentNode:
return DOM_NODE_TYPE_DOCUMENT_FRAGMENT;
default:
return DOM_NODE_TYPE_UNSUPPORTED;
}
}
bool CefDOMNodeImpl::IsText() {
if (!VerifyContext())
return false;
return node_.isTextNode();
}
bool CefDOMNodeImpl::IsElement() {
if (!VerifyContext())
return false;
return node_.isElementNode();
}
// Logic copied from RenderViewImpl::IsEditableNode.
bool CefDOMNodeImpl::IsEditable() {
if (!VerifyContext())
return false;
if (node_.isContentEditable())
return true;
if (node_.isElementNode()) {
const WebElement& element = node_.toConst<WebElement>();
if (element.isTextFormControlElement())
return true;
// Also return true if it has an ARIA role of 'textbox'.
for (unsigned i = 0; i < element.attributeCount(); ++i) {
if (LowerCaseEqualsASCII(element.attributeLocalName(i), "role")) {
if (LowerCaseEqualsASCII(element.attributeValue(i), "textbox"))
return true;
break;
}
}
}
return false;
}
bool CefDOMNodeImpl::IsFormControlElement() {
if (!VerifyContext())
return false;
if (node_.isElementNode()) {
const WebElement& element = node_.toConst<WebElement>();
return element.isFormControlElement();
}
return false;
}
CefString CefDOMNodeImpl::GetFormControlElementType() {
CefString str;
if (!VerifyContext())
return str;
if (node_.isElementNode()) {
const WebElement& element = node_.toConst<WebElement>();
if (element.isFormControlElement()) {
// Retrieve the type from the form control element.
const WebFormControlElement& formElement =
node_.toConst<WebFormControlElement>();
const base::string16& form_control_type = formElement.formControlType();
str = form_control_type;
}
}
return str;
}
bool CefDOMNodeImpl::IsSame(CefRefPtr<CefDOMNode> that) {
if (!VerifyContext())
return false;
CefDOMNodeImpl* impl = static_cast<CefDOMNodeImpl*>(that.get());
if (!impl || !impl->VerifyContext())
return false;
return node_.equals(impl->node_);
}
CefString CefDOMNodeImpl::GetName() {
CefString str;
if (!VerifyContext())
return str;
const WebString& name = node_.nodeName();
if (!name.isNull())
str = name;
return str;
}
CefString CefDOMNodeImpl::GetValue() {
CefString str;
if (!VerifyContext())
return str;
if (node_.isElementNode()) {
const WebElement& element = node_.toConst<WebElement>();
if (element.isFormControlElement()) {
// Retrieve the value from the form control element.
const WebFormControlElement& formElement =
node_.toConst<WebFormControlElement>();
base::string16 value;
const base::string16& form_control_type = formElement.formControlType();
if (form_control_type == base::ASCIIToUTF16("text")) {
const WebInputElement& input_element =
formElement.toConst<WebInputElement>();
value = input_element.value();
} else if (form_control_type == base::ASCIIToUTF16("select-one")) {
const WebSelectElement& select_element =
formElement.toConst<WebSelectElement>();
value = select_element.value();
}
base::TrimWhitespace(value, base::TRIM_LEADING, &value);
str = value;
}
}
if (str.empty()) {
const WebString& value = node_.nodeValue();
if (!value.isNull())
str = value;
}
return str;
}
bool CefDOMNodeImpl::SetValue(const CefString& value) {
if (!VerifyContext())
return false;
if (node_.isElementNode())
return false;
return webkit_glue::SetNodeValue(node_, base::string16(value));
}
CefString CefDOMNodeImpl::GetAsMarkup() {
CefString str;
if (!VerifyContext())
return str;
const WebString& markup = node_.createMarkup();
if (!markup.isNull())
str = markup;
return str;
}
CefRefPtr<CefDOMDocument> CefDOMNodeImpl::GetDocument() {
if (!VerifyContext())
return NULL;
return document_.get();
}
CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetParent() {
if (!VerifyContext())
return NULL;
return document_->GetOrCreateNode(node_.parentNode());
}
CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetPreviousSibling() {
if (!VerifyContext())
return NULL;
return document_->GetOrCreateNode(node_.previousSibling());
}
CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetNextSibling() {
if (!VerifyContext())
return NULL;
return document_->GetOrCreateNode(node_.nextSibling());
}
bool CefDOMNodeImpl::HasChildren() {
if (!VerifyContext())
return false;
return node_.hasChildNodes();
}
CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetFirstChild() {
if (!VerifyContext())
return NULL;
return document_->GetOrCreateNode(node_.firstChild());
}
CefRefPtr<CefDOMNode> CefDOMNodeImpl::GetLastChild() {
if (!VerifyContext())
return NULL;
return document_->GetOrCreateNode(node_.lastChild());
}
CefString CefDOMNodeImpl::GetElementTagName() {
CefString str;
if (!VerifyContext())
return str;
if (!node_.isElementNode()) {
NOTREACHED();
return str;
}
const WebElement& element = node_.toConst<blink::WebElement>();
const WebString& tagname = element.tagName();
if (!tagname.isNull())
str = tagname;
return str;
}
bool CefDOMNodeImpl::HasElementAttributes() {
if (!VerifyContext())
return false;
if (!node_.isElementNode()) {
NOTREACHED();
return false;
}
const WebElement& element = node_.toConst<blink::WebElement>();
return (element.attributeCount() > 0);
}
bool CefDOMNodeImpl::HasElementAttribute(const CefString& attrName) {
if (!VerifyContext())
return false;
if (!node_.isElementNode()) {
NOTREACHED();
return false;
}
const WebElement& element = node_.toConst<blink::WebElement>();
return element.hasAttribute(base::string16(attrName));
}
CefString CefDOMNodeImpl::GetElementAttribute(const CefString& attrName) {
CefString str;
if (!VerifyContext())
return str;
if (!node_.isElementNode()) {
NOTREACHED();
return str;
}
const WebElement& element = node_.toConst<blink::WebElement>();
const WebString& attr = element.getAttribute(base::string16(attrName));
if (!attr.isNull())
str = attr;
return str;
}
void CefDOMNodeImpl::GetElementAttributes(AttributeMap& attrMap) {
if (!VerifyContext())
return;
if (!node_.isElementNode()) {
NOTREACHED();
return;
}
const WebElement& element = node_.toConst<blink::WebElement>();
unsigned int len = element.attributeCount();
if (len == 0)
return;
for (unsigned int i = 0; i < len; ++i) {
base::string16 name = element.attributeLocalName(i);
base::string16 value = element.attributeValue(i);
attrMap.insert(std::make_pair(name, value));
}
}
bool CefDOMNodeImpl::SetElementAttribute(const CefString& attrName,
const CefString& value) {
if (!VerifyContext())
return false;
if (!node_.isElementNode()) {
NOTREACHED();
return false;
}
WebElement element = node_.to<blink::WebElement>();
return element.setAttribute(base::string16(attrName),
base::string16(value));
}
CefString CefDOMNodeImpl::GetElementInnerText() {
CefString str;
if (!VerifyContext())
return str;
if (!node_.isElementNode()) {
NOTREACHED();
return str;
}
WebElement element = node_.to<blink::WebElement>();
const WebString& text = element.innerText();
if (!text.isNull())
str = text;
return str;
}
void CefDOMNodeImpl::Detach() {
document_ = NULL;
node_.assign(WebNode());
}
bool CefDOMNodeImpl::VerifyContext() {
if (!document_.get()) {
NOTREACHED();
return false;
}
if (!document_->VerifyContext())
return false;
if (node_.isNull()) {
NOTREACHED();
return false;
}
return true;
}

View File

@@ -0,0 +1,61 @@
// 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_DOM_NODE_IMPL_H_
#define CEF_LIBCEF_DOM_NODE_IMPL_H_
#pragma once
#include "include/cef_dom.h"
#include "third_party/WebKit/public/web/WebNode.h"
class CefDOMDocumentImpl;
class CefDOMNodeImpl : public CefDOMNode {
public:
CefDOMNodeImpl(CefRefPtr<CefDOMDocumentImpl> document,
const blink::WebNode& node);
~CefDOMNodeImpl() override;
// CefDOMNode methods.
Type GetType() override;
bool IsText() override;
bool IsElement() override;
bool IsEditable() override;
bool IsFormControlElement() override;
CefString GetFormControlElementType() override;
bool IsSame(CefRefPtr<CefDOMNode> that) override;
CefString GetName() override;
CefString GetValue() override;
bool SetValue(const CefString& value) override;
CefString GetAsMarkup() override;
CefRefPtr<CefDOMDocument> GetDocument() override;
CefRefPtr<CefDOMNode> GetParent() override;
CefRefPtr<CefDOMNode> GetPreviousSibling() override;
CefRefPtr<CefDOMNode> GetNextSibling() override;
bool HasChildren() override;
CefRefPtr<CefDOMNode> GetFirstChild() override;
CefRefPtr<CefDOMNode> GetLastChild() override;
CefString GetElementTagName() override;
bool HasElementAttributes() override;
bool HasElementAttribute(const CefString& attrName) override;
CefString GetElementAttribute(const CefString& attrName) override;
void GetElementAttributes(AttributeMap& attrMap) override;
bool SetElementAttribute(const CefString& attrName,
const CefString& value) override;
CefString GetElementInnerText() override;
// Will be called from CefDOMDocumentImpl::Detach().
void Detach();
// Verify that the object exists and is being accessed on the UI thread.
bool VerifyContext();
protected:
CefRefPtr<CefDOMDocumentImpl> document_;
blink::WebNode node_;
IMPLEMENT_REFCOUNTING(CefDOMNodeImpl);
};
#endif // CEF_LIBCEF_DOM_NODE_IMPL_H_

View File

@@ -0,0 +1,272 @@
// 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 "libcef/common/cef_messages.h"
#include "libcef/common/http_header_utils.h"
#include "libcef/common/request_impl.h"
#include "libcef/renderer/browser_impl.h"
#include "libcef/renderer/dom_document_impl.h"
#include "libcef/renderer/thread_util.h"
#include "libcef/renderer/v8_impl.h"
#include "libcef/renderer/webkit_glue.h"
#include "third_party/WebKit/public/platform/WebData.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/WebKit/public/web/WebView.h"
#include "third_party/WebKit/public/web/WebScriptSource.h"
using blink::WebString;
CefFrameImpl::CefFrameImpl(CefBrowserImpl* browser,
blink::WebFrame* frame)
: browser_(browser),
frame_(frame),
frame_id_(webkit_glue::GetIdentifier(frame)) {
}
CefFrameImpl::~CefFrameImpl() {
}
bool CefFrameImpl::IsValid() {
CEF_REQUIRE_RT_RETURN(false);
return (frame_ != NULL);
}
void CefFrameImpl::Undo() {
CEF_REQUIRE_RT_RETURN_VOID();
if (frame_)
frame_->executeCommand(WebString::fromUTF8("Undo"));
}
void CefFrameImpl::Redo() {
CEF_REQUIRE_RT_RETURN_VOID();
if (frame_)
frame_->executeCommand(WebString::fromUTF8("Redo"));
}
void CefFrameImpl::Cut() {
CEF_REQUIRE_RT_RETURN_VOID();
if (frame_)
frame_->executeCommand(WebString::fromUTF8("Cut"));
}
void CefFrameImpl::Copy() {
CEF_REQUIRE_RT_RETURN_VOID();
if (frame_)
frame_->executeCommand(WebString::fromUTF8("Copy"));
}
void CefFrameImpl::Paste() {
CEF_REQUIRE_RT_RETURN_VOID();
if (frame_)
frame_->executeCommand(WebString::fromUTF8("Paste"));
}
void CefFrameImpl::Delete() {
CEF_REQUIRE_RT_RETURN_VOID();
if (frame_)
frame_->executeCommand(WebString::fromUTF8("Delete"));
}
void CefFrameImpl::SelectAll() {
CEF_REQUIRE_RT_RETURN_VOID();
if (frame_)
frame_->executeCommand(WebString::fromUTF8("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_) {
CefString content = std::string(frame_->contentAsMarkup().utf8());
visitor->Visit(content);
}
}
void CefFrameImpl::GetText(CefRefPtr<CefStringVisitor> visitor) {
CEF_REQUIRE_RT_RETURN_VOID();
if (frame_) {
CefString content = webkit_glue::DumpDocumentText(frame_);
visitor->Visit(content);
}
}
void CefFrameImpl::LoadRequest(CefRefPtr<CefRequest> request) {
CEF_REQUIRE_RT_RETURN_VOID();
if (!browser_)
return;
CefMsg_LoadRequest_Params params;
params.url = GURL(std::string(request->GetURL()));
params.method = request->GetMethod();
params.frame_id = frame_id_;
params.first_party_for_cookies =
GURL(std::string(request->GetFirstPartyForCookies()));
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();
browser_->LoadRequest(params);
}
void CefFrameImpl::LoadURL(const CefString& url) {
CEF_REQUIRE_RT_RETURN_VOID();
if (!browser_)
return;
CefMsg_LoadRequest_Params params;
params.url = GURL(url.ToString());
params.method = "GET";
params.frame_id = frame_id_;
browser_->LoadRequest(params);
}
void CefFrameImpl::LoadString(const CefString& string,
const CefString& url) {
CEF_REQUIRE_RT_RETURN_VOID();
if (frame_) {
GURL gurl = GURL(url.ToString());
frame_->loadHTMLString(string.ToString(), gurl);
}
}
void CefFrameImpl::ExecuteJavaScript(const CefString& jsCode,
const CefString& scriptUrl,
int startLine) {
CEF_REQUIRE_RT_RETURN_VOID();
if (jsCode.empty())
return;
if (startLine < 0)
startLine = 0;
if (frame_) {
GURL gurl = GURL(scriptUrl.ToString());
frame_->executeScript(
blink::WebScriptSource(jsCode.ToString16(), gurl, startLine));
}
}
bool CefFrameImpl::IsMain() {
CEF_REQUIRE_RT_RETURN(false);
if (frame_)
return (frame_->parent() == NULL);
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 = frame_->uniqueName();
return name;
}
int64 CefFrameImpl::GetIdentifier() {
CEF_REQUIRE_RT_RETURN(0);
return frame_id_;
}
CefRefPtr<CefFrame> CefFrameImpl::GetParent() {
CEF_REQUIRE_RT_RETURN(NULL);
if (frame_) {
blink::WebFrame* parent = frame_->parent();
if (parent)
return browser_->GetWebFrameImpl(parent).get();
}
return NULL;
}
CefString CefFrameImpl::GetURL() {
CefString url;
CEF_REQUIRE_RT_RETURN(url);
if (frame_) {
GURL gurl = frame_->document().url();
url = gurl.spec();
}
return url;
}
CefRefPtr<CefBrowser> CefFrameImpl::GetBrowser() {
CEF_REQUIRE_RT_RETURN(NULL);
return browser_;
}
CefRefPtr<CefV8Context> CefFrameImpl::GetV8Context() {
CEF_REQUIRE_RT_RETURN(NULL);
if (frame_) {
v8::Isolate* isolate = blink::mainThreadIsolate();
v8::HandleScope handle_scope(isolate);
return new CefV8ContextImpl(isolate, frame_->mainWorldScriptContext());
} else {
return NULL;
}
}
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_->document();
if (!document.isNull())
documentImpl = new CefDOMDocumentImpl(browser_, frame_);
visitor->Visit(documentImpl.get());
if (documentImpl.get())
documentImpl->Detach();
}
void CefFrameImpl::Detach() {
browser_ = NULL;
frame_ = NULL;
}

View File

@@ -0,0 +1,70 @@
// 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_RENDERER_FRAME_IMPL_H_
#define CEF_LIBCEF_RENDERER_FRAME_IMPL_H_
#pragma once
#include <string>
#include "include/cef_frame.h"
#include "include/cef_v8.h"
class CefBrowserImpl;
namespace blink {
class WebFrame;
}
// 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:
CefFrameImpl(CefBrowserImpl* browser,
blink::WebFrame* frame);
~CefFrameImpl() override;
// CefFrame implementation.
bool IsValid() override;
void Undo() override;
void Redo() override;
void Cut() override;
void Copy() override;
void Paste() override;
void Delete() override;
void SelectAll() override;
void ViewSource() override;
void GetSource(CefRefPtr<CefStringVisitor> visitor) override;
void GetText(CefRefPtr<CefStringVisitor> visitor) override;
void LoadRequest(CefRefPtr<CefRequest> request) override;
void LoadURL(const CefString& url) override;
void LoadString(const CefString& string,
const CefString& url) override;
void ExecuteJavaScript(const CefString& jsCode,
const CefString& scriptUrl,
int startLine) override;
bool IsMain() override;
bool IsFocused() override;
CefString GetName() override;
int64 GetIdentifier() override;
CefRefPtr<CefFrame> GetParent() override;
CefString GetURL() override;
CefRefPtr<CefBrowser> GetBrowser() override;
CefRefPtr<CefV8Context> GetV8Context() override;
void VisitDOM(CefRefPtr<CefDOMVisitor> visitor) override;
void Detach();
blink::WebFrame* web_frame() const { return frame_; }
protected:
CefBrowserImpl* browser_;
blink::WebFrame* frame_;
int64 frame_id_;
IMPLEMENT_REFCOUNTING(CefFrameImpl);
DISALLOW_EVIL_CONSTRUCTORS(CefFrameImpl);
};
#endif // CEF_LIBCEF_RENDERER_FRAME_IMPL_H_

View File

@@ -0,0 +1,24 @@
// Copyright 2014 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/render_frame_observer.h"
#include "libcef/renderer/content_renderer_client.h"
#include "content/public/renderer/render_frame.h"
CefRenderFrameObserver::CefRenderFrameObserver(
content::RenderFrame* render_frame)
: content::RenderFrameObserver(render_frame) {
}
CefRenderFrameObserver::~CefRenderFrameObserver() {
}
void CefRenderFrameObserver::WillReleaseScriptContext(
v8::Handle<v8::Context> context,
int world_id) {
CefContentRendererClient::Get()->WillReleaseScriptContext(
render_frame()->GetWebFrame(), context, world_id);
}

View File

@@ -0,0 +1,26 @@
// Copyright 2014 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 LIBCEF_RENDERER_RENDER_FRAME_OBSERVER_H_
#define LIBCEF_RENDERER_RENDER_FRAME_OBSERVER_H_
#include "content/public/renderer/render_frame_observer.h"
namespace content {
class RenderFrame;
}
class CefRenderFrameObserver : public content::RenderFrameObserver {
public:
explicit CefRenderFrameObserver(content::RenderFrame* render_frame);
~CefRenderFrameObserver() override;
void WillReleaseScriptContext(v8::Handle<v8::Context> context,
int world_id) override;
private:
DISALLOW_COPY_AND_ASSIGN(CefRenderFrameObserver);
};
#endif // LIBCEF_RENDERER_RENDER_FRAME_OBSERVER_H_

View File

@@ -0,0 +1,75 @@
/// Copyright (c) 2012 The Chromium Embedded Framework Authors.
// Portions (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/render_message_filter.h"
#include "libcef/renderer/thread_util.h"
#include "libcef/common/cef_messages.h"
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "content/common/devtools_messages.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
#include "url/gurl.h"
#include "url/url_util.h"
CefRenderMessageFilter::CefRenderMessageFilter()
: sender_(NULL) {
}
CefRenderMessageFilter::~CefRenderMessageFilter() {
}
void CefRenderMessageFilter::OnFilterAdded(IPC::Sender* sender) {
sender_ = sender;
}
void CefRenderMessageFilter::OnFilterRemoved() {
}
bool CefRenderMessageFilter::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
if (message.type() == DevToolsAgentMsg_Attach::ID ||
message.type() == DevToolsAgentMsg_Detach::ID) {
// Observe the DevTools messages but don't handle them.
handled = false;
}
IPC_BEGIN_MESSAGE_MAP(CefRenderMessageFilter, message)
IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Attach, OnDevToolsAgentAttach)
IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Detach, OnDevToolsAgentDetach)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void CefRenderMessageFilter::OnDevToolsAgentAttach(
const std::string& host_id) {
CEF_POST_TASK_RT(
base::Bind(&CefRenderMessageFilter::OnDevToolsAgentAttach_RT, this));
}
void CefRenderMessageFilter::OnDevToolsAgentDetach() {
// CefContentRendererClient::DevToolsAgentDetached() needs to be called after
// the IPC message has been handled by DevToolsAgent. A workaround for this is
// to first post to the IO thread and then post to the renderer thread.
base::MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(&CefRenderMessageFilter::OnDevToolsAgentDetach_IOT, this));
}
void CefRenderMessageFilter::OnDevToolsAgentAttach_RT() {
CEF_REQUIRE_RT();
CefContentRendererClient::Get()->DevToolsAgentAttached();
}
void CefRenderMessageFilter::OnDevToolsAgentDetach_IOT() {
CEF_POST_TASK_RT(
base::Bind(&CefRenderMessageFilter::OnDevToolsAgentDetach_RT, this));
}
void CefRenderMessageFilter::OnDevToolsAgentDetach_RT() {
CEF_REQUIRE_RT();
CefContentRendererClient::Get()->DevToolsAgentDetached();
}

View File

@@ -0,0 +1,39 @@
// 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.
#ifndef CEF_LIBCEF_RENDERER_RENDER_MESSAGE_FILTER_H_
#define CEF_LIBCEF_RENDERER_RENDER_MESSAGE_FILTER_H_
#include <string>
#include "ipc/ipc_channel_proxy.h"
#include "ipc/message_filter.h"
// This class sends and receives control messages on the renderer process.
class CefRenderMessageFilter : public IPC::MessageFilter {
public:
CefRenderMessageFilter();
~CefRenderMessageFilter() override;
// IPC::ChannelProxy::MessageFilter implementation.
void OnFilterAdded(IPC::Sender* sender) override;
void OnFilterRemoved() override;
bool OnMessageReceived(const IPC::Message& message) override;
private:
// Message handlers called on the IO thread.
void OnDevToolsAgentAttach(const std::string& host_id);
void OnDevToolsAgentDetach();
void OnDevToolsAgentAttach_RT();
void OnDevToolsAgentDetach_IOT();
void OnDevToolsAgentDetach_RT();
IPC::Sender* sender_;
DISALLOW_COPY_AND_ASSIGN(CefRenderMessageFilter);
};
#endif // CEF_LIBCEF_RENDERER_RENDER_MESSAGE_FILTER_H_

View File

@@ -0,0 +1,65 @@
/// Copyright (c) 2013 The Chromium Embedded Framework Authors.
// Portions (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/render_process_observer.h"
#include "libcef/common/cef_messages.h"
#include "libcef/common/net_resource_provider.h"
#include "libcef/renderer/content_renderer_client.h"
#include "net/base/net_module.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
CefRenderProcessObserver::CefRenderProcessObserver() {
net::NetModule::SetResourceProvider(NetResourceProvider);
}
CefRenderProcessObserver::~CefRenderProcessObserver() {
}
bool CefRenderProcessObserver::OnControlMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(CefRenderProcessObserver, message)
IPC_MESSAGE_HANDLER(CefProcessMsg_ModifyCrossOriginWhitelistEntry,
OnModifyCrossOriginWhitelistEntry)
IPC_MESSAGE_HANDLER(CefProcessMsg_ClearCrossOriginWhitelist,
OnClearCrossOriginWhitelist)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void CefRenderProcessObserver::WebKitInitialized() {
CefContentRendererClient::Get()->WebKitInitialized();
}
void CefRenderProcessObserver::OnRenderProcessShutdown() {
CefContentRendererClient::Get()->OnRenderProcessShutdown();
}
void CefRenderProcessObserver::OnModifyCrossOriginWhitelistEntry(
bool add,
const Cef_CrossOriginWhiteListEntry_Params& params) {
GURL gurl = GURL(params.source_origin);
if (add) {
blink::WebSecurityPolicy::addOriginAccessWhitelistEntry(
gurl,
blink::WebString::fromUTF8(params.target_protocol),
blink::WebString::fromUTF8(params.target_domain),
params.allow_target_subdomains);
} else {
blink::WebSecurityPolicy::removeOriginAccessWhitelistEntry(
gurl,
blink::WebString::fromUTF8(params.target_protocol),
blink::WebString::fromUTF8(params.target_domain),
params.allow_target_subdomains);
}
}
void CefRenderProcessObserver::OnClearCrossOriginWhitelist() {
blink::WebSecurityPolicy::resetOriginAccessWhitelists();
}

View File

@@ -0,0 +1,35 @@
// Copyright (c) 2013 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.
#ifndef CEF_LIBCEF_RENDERER_RENDER_PROCESS_OBSERVER_H_
#define CEF_LIBCEF_RENDERER_RENDER_PROCESS_OBSERVER_H_
#include "base/compiler_specific.h"
#include "content/public/renderer/render_process_observer.h"
struct Cef_CrossOriginWhiteListEntry_Params;
// This class sends and receives control messages on the renderer process.
class CefRenderProcessObserver : public content::RenderProcessObserver {
public:
CefRenderProcessObserver();
~CefRenderProcessObserver() override;
// RenderProcessObserver implementation.
bool OnControlMessageReceived(const IPC::Message& message) override;
void WebKitInitialized() override;
void OnRenderProcessShutdown() override;
private:
// Message handlers called on the render thread.
void OnModifyCrossOriginWhitelistEntry(
bool add,
const Cef_CrossOriginWhiteListEntry_Params& params);
void OnClearCrossOriginWhitelist();
DISALLOW_COPY_AND_ASSIGN(CefRenderProcessObserver);
};
#endif // CEF_LIBCEF_RENDERER_RENDER_PROCESS_OBSERVER_H_

View File

@@ -0,0 +1,379 @@
// 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/render_urlrequest_impl.h"
#include "libcef/common/request_impl.h"
#include "libcef/common/response_impl.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "third_party/WebKit/public/platform/Platform.h"
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/WebURLError.h"
#include "third_party/WebKit/public/platform/WebURLLoader.h"
#include "third_party/WebKit/public/platform/WebURLLoaderClient.h"
#include "third_party/WebKit/public/platform/WebURLRequest.h"
#include "third_party/WebKit/public/platform/WebURLResponse.h"
using blink::WebString;
using blink::WebURL;
using blink::WebURLError;
using blink::WebURLLoader;
using blink::WebURLRequest;
using blink::WebURLResponse;
namespace {
class CefWebURLLoaderClient : public blink::WebURLLoaderClient {
public:
CefWebURLLoaderClient(CefRenderURLRequest::Context* context,
int request_flags);
~CefWebURLLoaderClient() override;
// blink::WebURLLoaderClient methods.
void willSendRequest(
WebURLLoader* loader,
WebURLRequest& newRequest,
const WebURLResponse& redirectResponse) override;
void didSendData(
WebURLLoader* loader,
unsigned long long bytesSent,
unsigned long long totalBytesToBeSent) override;
void didReceiveResponse(
WebURLLoader* loader,
const WebURLResponse& response) override;
void didDownloadData(WebURLLoader* loader,
int dataLength,
int encodedDataLength) override;
void didReceiveData(WebURLLoader* loader,
const char* data,
int dataLength,
int encodedDataLength) override;
void didReceiveCachedMetadata(WebURLLoader* loader,
const char* data,
int dataLength) override;
void didFinishLoading(WebURLLoader* loader,
double finishTime,
int64_t totalEncodedDataLength) override;
void didFail(WebURLLoader* loader,
const WebURLError& error) override;
protected:
// The context_ pointer will outlive this object.
CefRenderURLRequest::Context* context_;
int request_flags_;
};
} // namespace
// CefRenderURLRequest::Context -----------------------------------------------
class CefRenderURLRequest::Context
: public base::RefCountedThreadSafe<CefRenderURLRequest::Context> {
public:
Context(CefRefPtr<CefRenderURLRequest> url_request,
CefRefPtr<CefRequest> request,
CefRefPtr<CefURLRequestClient> client)
: url_request_(url_request),
request_(request),
client_(client),
message_loop_proxy_(base::MessageLoop::current()->message_loop_proxy()),
status_(UR_IO_PENDING),
error_code_(ERR_NONE),
upload_data_size_(0),
got_upload_progress_complete_(false),
download_data_received_(0),
download_data_total_(-1) {
// Mark the request as read-only.
static_cast<CefRequestImpl*>(request_.get())->SetReadOnly(true);
}
inline bool CalledOnValidThread() {
return message_loop_proxy_->BelongsToCurrentThread();
}
bool Start() {
DCHECK(CalledOnValidThread());
GURL url = GURL(request_->GetURL().ToString());
if (!url.is_valid())
return false;
loader_.reset(blink::Platform::current()->createURLLoader());
url_client_.reset(new CefWebURLLoaderClient(this, request_->GetFlags()));
WebURLRequest urlRequest;
static_cast<CefRequestImpl*>(request_.get())->Get(urlRequest);
if (urlRequest.reportUploadProgress()) {
// Attempt to determine the upload data size.
CefRefPtr<CefPostData> post_data = request_->GetPostData();
if (post_data.get()) {
CefPostData::ElementVector elements;
post_data->GetElements(elements);
if (elements.size() == 1 && elements[0]->GetType() == PDE_TYPE_BYTES) {
CefPostDataElementImpl* impl =
static_cast<CefPostDataElementImpl*>(elements[0].get());
upload_data_size_ = impl->GetBytesCount();
}
}
}
loader_->loadAsynchronously(urlRequest, url_client_.get());
return true;
}
void Cancel() {
DCHECK(CalledOnValidThread());
// The request may already be complete.
if (!loader_.get() || status_ != UR_IO_PENDING)
return;
status_ = UR_CANCELED;
error_code_ = ERR_ABORTED;
// Will result in a call to OnError().
loader_->cancel();
}
void OnResponse(const WebURLResponse& response) {
DCHECK(CalledOnValidThread());
response_ = CefResponse::Create();
CefResponseImpl* responseImpl =
static_cast<CefResponseImpl*>(response_.get());
responseImpl->Set(response);
responseImpl->SetReadOnly(true);
download_data_total_ = response.expectedContentLength();
}
void OnError(const WebURLError& error) {
DCHECK(CalledOnValidThread());
if (status_ == UR_IO_PENDING) {
status_ = UR_FAILED;
error_code_ = static_cast<CefURLRequest::ErrorCode>(error.reason);
}
OnComplete();
}
void OnComplete() {
DCHECK(CalledOnValidThread());
if (status_ == UR_IO_PENDING) {
status_ = UR_SUCCESS;
NotifyUploadProgressIfNecessary();
}
if (loader_.get())
loader_.reset(NULL);
DCHECK(url_request_.get());
client_->OnRequestComplete(url_request_.get());
// This may result in the Context object being deleted.
url_request_ = NULL;
}
void OnDownloadProgress(int64 current) {
DCHECK(CalledOnValidThread());
DCHECK(url_request_.get());
NotifyUploadProgressIfNecessary();
download_data_received_ += current;
client_->OnDownloadProgress(url_request_.get(), download_data_received_,
download_data_total_);
}
void OnDownloadData(const char* data, int dataLength) {
DCHECK(CalledOnValidThread());
DCHECK(url_request_.get());
client_->OnDownloadData(url_request_.get(), data, dataLength);
}
void OnUploadProgress(int64 current, int64 total) {
DCHECK(CalledOnValidThread());
DCHECK(url_request_.get());
if (current == total)
got_upload_progress_complete_ = true;
client_->OnUploadProgress(url_request_.get(), current, total);
}
CefRefPtr<CefRequest> request() { return request_; }
CefRefPtr<CefURLRequestClient> client() { return client_; }
CefURLRequest::Status status() { return status_; }
CefURLRequest::ErrorCode error_code() { return error_code_; }
CefRefPtr<CefResponse> response() { return response_; }
private:
friend class base::RefCountedThreadSafe<CefRenderURLRequest::Context>;
virtual ~Context() {}
void NotifyUploadProgressIfNecessary() {
if (!got_upload_progress_complete_ && upload_data_size_ > 0) {
// URLFetcher sends upload notifications using a timer and will not send
// a notification if the request completes too quickly. We therefore
// send the notification here if necessary.
client_->OnUploadProgress(url_request_.get(), upload_data_size_,
upload_data_size_);
got_upload_progress_complete_ = true;
}
}
// Members only accessed on the initialization thread.
CefRefPtr<CefRenderURLRequest> url_request_;
CefRefPtr<CefRequest> request_;
CefRefPtr<CefURLRequestClient> client_;
scoped_refptr<base::MessageLoopProxy> message_loop_proxy_;
CefURLRequest::Status status_;
CefURLRequest::ErrorCode error_code_;
CefRefPtr<CefResponse> response_;
scoped_ptr<blink::WebURLLoader> loader_;
scoped_ptr<CefWebURLLoaderClient> url_client_;
int64 upload_data_size_;
bool got_upload_progress_complete_;
int64 download_data_received_;
int64 download_data_total_;
};
// CefWebURLLoaderClient --------------------------------------------------
namespace {
CefWebURLLoaderClient::CefWebURLLoaderClient(
CefRenderURLRequest::Context* context,
int request_flags)
: context_(context),
request_flags_(request_flags) {
}
CefWebURLLoaderClient::~CefWebURLLoaderClient() {
}
void CefWebURLLoaderClient::willSendRequest(
WebURLLoader* loader,
WebURLRequest& newRequest,
const WebURLResponse& redirectResponse) {
}
void CefWebURLLoaderClient::didSendData(
WebURLLoader* loader,
unsigned long long bytesSent,
unsigned long long totalBytesToBeSent) {
if (request_flags_ & UR_FLAG_REPORT_UPLOAD_PROGRESS)
context_->OnUploadProgress(bytesSent, totalBytesToBeSent);
}
void CefWebURLLoaderClient::didReceiveResponse(
WebURLLoader* loader,
const WebURLResponse& response) {
context_->OnResponse(response);
}
void CefWebURLLoaderClient::didDownloadData(WebURLLoader* loader,
int dataLength,
int encodedDataLength) {
}
void CefWebURLLoaderClient::didReceiveData(WebURLLoader* loader,
const char* data,
int dataLength,
int encodedDataLength) {
context_->OnDownloadProgress(dataLength);
if (!(request_flags_ & UR_FLAG_NO_DOWNLOAD_DATA))
context_->OnDownloadData(data, dataLength);
}
void CefWebURLLoaderClient::didReceiveCachedMetadata(WebURLLoader* loader,
const char* data,
int dataLength) {
}
void CefWebURLLoaderClient::didFinishLoading(WebURLLoader* loader,
double finishTime,
int64_t totalEncodedDataLength) {
context_->OnComplete();
}
void CefWebURLLoaderClient::didFail(WebURLLoader* loader,
const WebURLError& error) {
context_->OnError(error);
}
} // namespace
// CefRenderURLRequest --------------------------------------------------------
CefRenderURLRequest::CefRenderURLRequest(
CefRefPtr<CefRequest> request,
CefRefPtr<CefURLRequestClient> client) {
context_ = new Context(this, request, client);
}
CefRenderURLRequest::~CefRenderURLRequest() {
}
bool CefRenderURLRequest::Start() {
if (!VerifyContext())
return false;
return context_->Start();
}
CefRefPtr<CefRequest> CefRenderURLRequest::GetRequest() {
if (!VerifyContext())
return NULL;
return context_->request();
}
CefRefPtr<CefURLRequestClient> CefRenderURLRequest::GetClient() {
if (!VerifyContext())
return NULL;
return context_->client();
}
CefURLRequest::Status CefRenderURLRequest::GetRequestStatus() {
if (!VerifyContext())
return UR_UNKNOWN;
return context_->status();
}
CefURLRequest::ErrorCode CefRenderURLRequest::GetRequestError() {
if (!VerifyContext())
return ERR_NONE;
return context_->error_code();
}
CefRefPtr<CefResponse> CefRenderURLRequest::GetResponse() {
if (!VerifyContext())
return NULL;
return context_->response();
}
void CefRenderURLRequest::Cancel() {
if (!VerifyContext())
return;
return context_->Cancel();
}
bool CefRenderURLRequest::VerifyContext() {
DCHECK(context_.get());
if (!context_->CalledOnValidThread()) {
NOTREACHED() << "called on invalid thread";
return false;
}
return true;
}

View File

@@ -0,0 +1,37 @@
// 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_RENDERER_RENDER_URLREQUEST_IMPL_H_
#define CEF_LIBCEF_RENDERER_RENDER_URLREQUEST_IMPL_H_
#include "include/cef_urlrequest.h"
#include "base/memory/ref_counted.h"
class CefRenderURLRequest : public CefURLRequest {
public:
class Context;
CefRenderURLRequest(CefRefPtr<CefRequest> request,
CefRefPtr<CefURLRequestClient> client);
~CefRenderURLRequest() override;
bool Start();
// CefURLRequest methods.
CefRefPtr<CefRequest> GetRequest() override;
CefRefPtr<CefURLRequestClient> GetClient() override;
Status GetRequestStatus() override;
ErrorCode GetRequestError() override;
CefRefPtr<CefResponse> GetResponse() override;
void Cancel() override;
private:
bool VerifyContext();
scoped_refptr<Context> context_;
IMPLEMENT_REFCOUNTING(CefRenderURLRequest);
};
#endif // CEF_LIBCEF_RENDERER_RENDER_URLREQUEST_IMPL_H_

View File

@@ -0,0 +1,59 @@
// Copyright (c) 2013 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_RENDERER_THREAD_UTIL_H_
#define CEF_LIBCEF_RENDERER_THREAD_UTIL_H_
#pragma once
#include "libcef/renderer/content_renderer_client.h"
#include "base/location.h"
#include "base/logging.h"
#include "content/public/renderer/render_thread.h"
#define CEF_CURRENTLY_ON_RT() (!!content::RenderThread::Get())
#define CEF_REQUIRE_RT() DCHECK(CEF_CURRENTLY_ON_RT())
#define CEF_REQUIRE_RT_RETURN(var) \
if (!CEF_CURRENTLY_ON_RT()) { \
NOTREACHED() << "called on invalid thread"; \
return var; \
}
#define CEF_REQUIRE_RT_RETURN_VOID() \
if (!CEF_CURRENTLY_ON_RT()) { \
NOTREACHED() << "called on invalid thread"; \
return; \
}
#define CEF_RENDER_LOOP() \
(CefContentRendererClient::Get()->render_task_runner())
#define CEF_POST_TASK_RT(task) \
CEF_RENDER_LOOP()->PostTask(FROM_HERE, task)
#define CEF_POST_DELAYED_TASK_RT(task, delay_ms) \
CEF_RENDER_LOOP()->PostDelayedTask(FROM_HERE, task, \
base::TimeDelta::FromMilliseconds(delay_ms))
// Use this template in conjuction with RefCountedThreadSafe when you want to
// ensure that an object is deleted on the render thread.
struct CefDeleteOnRenderThread {
template<typename T>
static void Destruct(const T* x) {
if (CEF_CURRENTLY_ON_RT()) {
delete x;
} else {
if (!CEF_RENDER_LOOP()->DeleteSoon(FROM_HERE, x)) {
#if defined(UNIT_TEST)
// Only logged under unit testing because leaks at shutdown
// are acceptable under normal circumstances.
LOG(ERROR) << "DeleteSoon failed on thread " << thread;
#endif // UNIT_TEST
}
}
}
};
#endif // CEF_LIBCEF_RENDERER_THREAD_UTIL_H_

2134
libcef/renderer/v8_impl.cc Normal file

File diff suppressed because it is too large Load Diff

401
libcef/renderer/v8_impl.h Normal file
View File

@@ -0,0 +1,401 @@
// Copyright (c) 2013 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_RENDERER_V8_IMPL_H_
#define CEF_LIBCEF_RENDERER_V8_IMPL_H_
#pragma once
#include <vector>
#include "include/cef_v8.h"
#include "libcef/common/tracker.h"
#include "v8/include/v8.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
class CefTrackNode;
class GURL;
namespace blink {
class WebFrame;
};
// Call after a V8 Isolate has been created and entered for the first time.
void CefV8IsolateCreated();
// Call before a V8 Isolate is exited and destroyed.
void CefV8IsolateDestroyed();
// Call to detach all handles associated with the specified context.
void CefV8ReleaseContext(v8::Handle<v8::Context> context);
// Set the stack size for uncaught exceptions.
void CefV8SetUncaughtExceptionStackSize(int stack_size);
// Set attributes associated with a WebWorker thread.
void CefV8SetWorkerAttributes(int worker_id, const GURL& worker_url);
// Used to detach handles when the associated context is released.
class CefV8ContextState : public base::RefCounted<CefV8ContextState> {
public:
CefV8ContextState() : valid_(true) {}
bool IsValid() { return valid_; }
void Detach() {
DCHECK(valid_);
valid_ = false;
track_manager_.DeleteAll();
}
void AddTrackObject(CefTrackNode* object) {
DCHECK(valid_);
track_manager_.Add(object);
}
void DeleteTrackObject(CefTrackNode* object) {
DCHECK(valid_);
track_manager_.Delete(object);
}
private:
friend class base::RefCounted<CefV8ContextState>;
~CefV8ContextState() {}
bool valid_;
CefTrackManager track_manager_;
};
// Use this template in conjuction with RefCountedThreadSafe to ensure that a
// V8 object is deleted on the correct thread.
struct CefV8DeleteOnMessageLoopThread {
template<typename T>
static void Destruct(const T* x) {
if (x->task_runner()->RunsTasksOnCurrentThread()) {
delete x;
} else {
if (!x->task_runner()->DeleteSoon(FROM_HERE, x)) {
#if defined(UNIT_TEST)
// Only logged under unit testing because leaks at shutdown
// are acceptable under normal circumstances.
LOG(ERROR) << "DeleteSoon failed on thread " << thread;
#endif // UNIT_TEST
}
}
}
};
// Base class for V8 Handle types.
class CefV8HandleBase :
public base::RefCountedThreadSafe<CefV8HandleBase,
CefV8DeleteOnMessageLoopThread> {
public:
// Returns true if there is no underlying context or if the underlying context
// is valid.
bool IsValid() const {
return (!context_state_.get() || context_state_->IsValid());
}
bool BelongsToCurrentThread() const;
v8::Isolate* isolate() const { return isolate_; }
scoped_refptr<base::SequencedTaskRunner> task_runner() const {
return task_runner_;
}
protected:
friend class base::DeleteHelper<CefV8HandleBase>;
friend class base::RefCountedThreadSafe<CefV8HandleBase,
CefV8DeleteOnMessageLoopThread>;
friend struct CefV8DeleteOnMessageLoopThread;
// |context| is the context that owns this handle. If empty the current
// context will be used.
CefV8HandleBase(v8::Isolate* isolate,
v8::Handle<v8::Context> context);
virtual ~CefV8HandleBase();
protected:
v8::Isolate* isolate_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
scoped_refptr<CefV8ContextState> context_state_;
};
// Template for V8 Handle types. This class is used to ensure that V8 objects
// are only released on the render thread.
template <typename v8class>
class CefV8Handle : public CefV8HandleBase {
public:
typedef v8::Local<v8class> handleType;
typedef v8::Persistent<v8class> persistentType;
CefV8Handle(v8::Isolate* isolate,
v8::Handle<v8::Context> context,
handleType v)
: CefV8HandleBase(isolate, context),
handle_(isolate, v) {
}
handleType GetNewV8Handle() {
DCHECK(IsValid());
return handleType::New(isolate(), handle_);
}
persistentType& GetPersistentV8Handle() {
return handle_;
}
protected:
~CefV8Handle() override {
handle_.Reset();
}
persistentType handle_;
DISALLOW_COPY_AND_ASSIGN(CefV8Handle);
};
// Specialization for v8::Value with empty implementation to avoid incorrect
// usage.
template <>
class CefV8Handle<v8::Value> {
};
class CefV8ContextImpl : public CefV8Context {
public:
CefV8ContextImpl(v8::Isolate* isolate,
v8::Handle<v8::Context> context);
~CefV8ContextImpl() override;
CefRefPtr<CefTaskRunner> GetTaskRunner() override;
bool IsValid() override;
CefRefPtr<CefBrowser> GetBrowser() override;
CefRefPtr<CefFrame> GetFrame() override;
CefRefPtr<CefV8Value> GetGlobal() override;
bool Enter() override;
bool Exit() override;
bool IsSame(CefRefPtr<CefV8Context> that) override;
bool Eval(const CefString& code,
CefRefPtr<CefV8Value>& retval,
CefRefPtr<CefV8Exception>& exception) override;
v8::Handle<v8::Context> GetV8Context();
blink::WebFrame* GetWebFrame();
protected:
typedef CefV8Handle<v8::Context> Handle;
scoped_refptr<Handle> handle_;
#ifndef NDEBUG
// Used in debug builds to catch missing Exits in destructor.
int enter_count_;
#endif
IMPLEMENT_REFCOUNTING(CefV8ContextImpl);
DISALLOW_COPY_AND_ASSIGN(CefV8ContextImpl);
};
class CefV8ValueImpl : public CefV8Value {
public:
explicit CefV8ValueImpl(v8::Isolate* isolate);
CefV8ValueImpl(v8::Isolate* isolate,
v8::Handle<v8::Value> value);
~CefV8ValueImpl() override;
// Used for initializing the CefV8ValueImpl. Should be called a single time
// after the CefV8ValueImpl is created.
void InitFromV8Value(v8::Handle<v8::Value> value);
void InitUndefined();
void InitNull();
void InitBool(bool value);
void InitInt(int32 value);
void InitUInt(uint32 value);
void InitDouble(double value);
void InitDate(const CefTime& value);
void InitString(CefString& value);
void InitObject(v8::Handle<v8::Value> value, CefTrackNode* tracker);
// Creates a new V8 value for the underlying value or returns the existing
// object handle.
v8::Handle<v8::Value> GetV8Value(bool should_persist);
bool IsValid() override;
bool IsUndefined() override;
bool IsNull() override;
bool IsBool() override;
bool IsInt() override;
bool IsUInt() override;
bool IsDouble() override;
bool IsDate() override;
bool IsString() override;
bool IsObject() override;
bool IsArray() override;
bool IsFunction() override;
bool IsSame(CefRefPtr<CefV8Value> value) override;
bool GetBoolValue() override;
int32 GetIntValue() override;
uint32 GetUIntValue() override;
double GetDoubleValue() override;
CefTime GetDateValue() override;
CefString GetStringValue() override;
bool IsUserCreated() override;
bool HasException() override;
CefRefPtr<CefV8Exception> GetException() override;
bool ClearException() override;
bool WillRethrowExceptions() override;
bool SetRethrowExceptions(bool rethrow) override;
bool HasValue(const CefString& key) override;
bool HasValue(int index) override;
bool DeleteValue(const CefString& key) override;
bool DeleteValue(int index) override;
CefRefPtr<CefV8Value> GetValue(const CefString& key) override;
CefRefPtr<CefV8Value> GetValue(int index) override;
bool SetValue(const CefString& key, CefRefPtr<CefV8Value> value,
PropertyAttribute attribute) override;
bool SetValue(int index, CefRefPtr<CefV8Value> value) override;
bool SetValue(const CefString& key, AccessControl settings,
PropertyAttribute attribute) override;
bool GetKeys(std::vector<CefString>& keys) override;
bool SetUserData(CefRefPtr<CefBase> user_data) override;
CefRefPtr<CefBase> GetUserData() override;
int GetExternallyAllocatedMemory() override;
int AdjustExternallyAllocatedMemory(int change_in_bytes) override;
int GetArrayLength() override;
CefString GetFunctionName() override;
CefRefPtr<CefV8Handler> GetFunctionHandler() override;
CefRefPtr<CefV8Value> ExecuteFunction(
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments) override;
CefRefPtr<CefV8Value> ExecuteFunctionWithContext(
CefRefPtr<CefV8Context> context,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments) override;
protected:
// Test for and record any exception.
bool HasCaught(v8::TryCatch& try_catch);
class Handle : public CefV8HandleBase {
public:
typedef v8::Local<v8::Value> handleType;
typedef v8::Persistent<v8::Value> persistentType;
Handle(v8::Isolate* isolate,
v8::Handle<v8::Context> context,
handleType v,
CefTrackNode* tracker);
handleType GetNewV8Handle(bool should_persist);
persistentType& GetPersistentV8Handle();
void SetWeakIfNecessary();
protected:
~Handle() override;
private:
// Callback for weak persistent reference destruction.
static void Destructor(const v8::WeakCallbackData<v8::Value, Handle>& data);
persistentType handle_;
// For Object and Function types, we need to hold on to a reference to their
// internal data or function handler objects that are reference counted.
CefTrackNode* tracker_;
// True if the handle needs to persist due to it being passed into V8.
bool should_persist_;
// True if the handle has been set as weak.
bool is_set_weak_;
DISALLOW_COPY_AND_ASSIGN(Handle);
};
v8::Isolate* isolate_;
enum {
TYPE_INVALID = 0,
TYPE_UNDEFINED,
TYPE_NULL,
TYPE_BOOL,
TYPE_INT,
TYPE_UINT,
TYPE_DOUBLE,
TYPE_DATE,
TYPE_STRING,
TYPE_OBJECT,
} type_;
union {
bool bool_value_;
int32 int_value_;
uint32 uint_value_;
double double_value_;
cef_time_t date_value_;
cef_string_t string_value_;
};
// Used with Object, Function and Array types.
scoped_refptr<Handle> handle_;
CefRefPtr<CefV8Exception> last_exception_;
bool rethrow_exceptions_;
IMPLEMENT_REFCOUNTING(CefV8ValueImpl);
DISALLOW_COPY_AND_ASSIGN(CefV8ValueImpl);
};
class CefV8StackTraceImpl : public CefV8StackTrace {
public:
CefV8StackTraceImpl(v8::Isolate* isolate,
v8::Handle<v8::StackTrace> handle);
~CefV8StackTraceImpl() override;
bool IsValid() override;
int GetFrameCount() override;
CefRefPtr<CefV8StackFrame> GetFrame(int index) override;
protected:
std::vector<CefRefPtr<CefV8StackFrame> > frames_;
IMPLEMENT_REFCOUNTING(CefV8StackTraceImpl);
DISALLOW_COPY_AND_ASSIGN(CefV8StackTraceImpl);
};
class CefV8StackFrameImpl : public CefV8StackFrame {
public:
CefV8StackFrameImpl(v8::Isolate* isolate,
v8::Handle<v8::StackFrame> handle);
~CefV8StackFrameImpl() override;
bool IsValid() override;
CefString GetScriptName() override;
CefString GetScriptNameOrSourceURL() override;
CefString GetFunctionName() override;
int GetLineNumber() override;
int GetColumn() override;
bool IsEval() override;
bool IsConstructor() override;
protected:
CefString script_name_;
CefString script_name_or_source_url_;
CefString function_name_;
int line_number_;
int column_;
bool is_eval_;
bool is_constructor_;
IMPLEMENT_REFCOUNTING(CefV8StackFrameImpl);
DISALLOW_COPY_AND_ASSIGN(CefV8StackFrameImpl);
};
#endif // CEF_LIBCEF_RENDERER_V8_IMPL_H_

View File

@@ -0,0 +1,124 @@
// 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.
// MSVC++ requires this to be set before any other includes to get M_PI.
// Otherwise there will be compile errors in wtf/MathExtras.h.
#define _USE_MATH_DEFINES
// Defines required to access Blink internals (unwrap WebNode).
#undef BLINK_IMPLEMENTATION
#define BLINK_IMPLEMENTATION 1
#undef INSIDE_BLINK
#define INSIDE_BLINK 1
#include "libcef/renderer/webkit_glue.h"
#include "base/compiler_specific.h"
#include "config.h"
MSVC_PUSH_WARNING_LEVEL(0);
#include "third_party/WebKit/public/platform/WebString.h"
#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebElement.h"
#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebViewClient.h"
#include "third_party/WebKit/Source/core/dom/Node.h"
#include "third_party/WebKit/Source/web/WebLocalFrameImpl.h"
#include "third_party/WebKit/Source/web/WebViewImpl.h"
MSVC_POP_WARNING();
#undef LOG
#include "base/logging.h"
#include "content/public/renderer/render_frame.h"
namespace webkit_glue {
const int64 kInvalidFrameId = -1;
bool CanGoBack(blink::WebView* view) {
if (!view)
return false;
blink::WebViewImpl* impl = reinterpret_cast<blink::WebViewImpl*>(view);
return (impl->client()->historyBackListCount() > 0);
}
bool CanGoForward(blink::WebView* view) {
if (!view)
return false;
blink::WebViewImpl* impl = reinterpret_cast<blink::WebViewImpl*>(view);
return (impl->client()->historyForwardListCount() > 0);
}
void GoBack(blink::WebView* view) {
if (!view)
return;
blink::WebViewImpl* impl = reinterpret_cast<blink::WebViewImpl*>(view);
if (impl->client()->historyBackListCount() > 0)
impl->client()->navigateBackForwardSoon(-1);
}
void GoForward(blink::WebView* view) {
if (!view)
return;
blink::WebViewImpl* impl = reinterpret_cast<blink::WebViewImpl*>(view);
if (impl->client()->historyForwardListCount() > 0)
impl->client()->navigateBackForwardSoon(1);
}
std::string DumpDocumentText(blink::WebFrame* frame) {
// We use the document element's text instead of the body text here because
// not all documents have a body, such as XML documents.
blink::WebElement document_element = frame->document().documentElement();
if (document_element.isNull())
return std::string();
return document_element.innerText().utf8();
}
bool SetNodeValue(blink::WebNode& node, const blink::WebString& value) {
blink::Node* web_node = node.unwrap<blink::Node>();
web_node->setNodeValue(value);
return true;
}
int64 GetIdentifier(blink::WebFrame* frame) {
// Each WebFrame will have an associated RenderFrame. The RenderFrame
// routing IDs are unique within a given renderer process.
content::RenderFrame* render_frame =
content::RenderFrame::FromWebFrame(frame);
DCHECK(render_frame);
if (render_frame)
return render_frame->GetRoutingID();
return kInvalidFrameId;
}
// Based on WebViewImpl::findFrameByName and FrameTree::find.
blink::WebFrame* FindFrameByUniqueName(const blink::WebString& unique_name,
blink::WebFrame* relative_to_frame) {
blink::Frame* start_frame = toWebLocalFrameImpl(relative_to_frame)->frame();
if (!start_frame)
return NULL;
const AtomicString& atomic_name = unique_name;
blink::Frame* found_frame = NULL;
// Search the subtree starting with |start_frame|.
for (blink::Frame* frame = start_frame;
frame;
frame = frame->tree().traverseNext(start_frame)) {
if (frame->tree().uniqueName() == atomic_name) {
found_frame = frame;
break;
}
}
if (found_frame && found_frame->isLocalFrame())
return blink::WebLocalFrameImpl::fromFrame(toLocalFrame(found_frame));
return NULL;
}
} // webkit_glue

View File

@@ -0,0 +1,48 @@
// 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.
#ifndef CEF_LIBCEF_RENDERER_WEBKIT_GLUE_H_
#define CEF_LIBCEF_RENDERER_WEBKIT_GLUE_H_
#include <string>
#include "base/basictypes.h"
namespace v8 {
class Context;
template <class T> class Handle;
class Isolate;
}
namespace blink {
class WebFrame;
class WebNode;
class WebString;
class WebView;
}
namespace webkit_glue {
extern const int64 kInvalidFrameId;
bool CanGoBack(blink::WebView* view);
bool CanGoForward(blink::WebView* view);
void GoBack(blink::WebView* view);
void GoForward(blink::WebView* view);
// Returns the text of the document element.
std::string DumpDocumentText(blink::WebFrame* frame);
bool SetNodeValue(blink::WebNode& node, const blink::WebString& value);
int64 GetIdentifier(blink::WebFrame* frame);
// Find the frame with the specified |unique_name| relative to
// |relative_to_frame| in the frame hierarchy.
blink::WebFrame* FindFrameByUniqueName(const blink::WebString& unique_name,
blink::WebFrame* relative_to_frame);
} // webkit_glue
#endif // CEF_LIBCEF_RENDERER_WEBKIT_GLUE_H_