300 lines
9.4 KiB
C++
300 lines
9.4 KiB
C++
// Copyright (c) 2016 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 "context.h"
|
|
|
|
#include "include/cef_app.h"
|
|
|
|
#include "client_app.h"
|
|
#include "jni_util.h"
|
|
|
|
#if defined(OS_MACOSX)
|
|
#include "util_mac.h"
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
Context* g_context = nullptr;
|
|
|
|
CefSettings GetJNISettings(JNIEnv* env, jobject obj) {
|
|
CefString tmp;
|
|
CefSettings settings;
|
|
|
|
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
|
settings.disable_signal_handlers = true;
|
|
#endif
|
|
|
|
if (!obj)
|
|
return settings;
|
|
|
|
ScopedJNIClass cls(env, "org/cef/CefSettings");
|
|
if (!cls)
|
|
return settings;
|
|
|
|
if (GetJNIFieldString(env, cls, obj, "browser_subprocess_path", &tmp) &&
|
|
!tmp.empty()) {
|
|
CefString(&settings.browser_subprocess_path) = tmp;
|
|
tmp.clear();
|
|
}
|
|
GetJNIFieldBoolean(env, cls, obj, "windowless_rendering_enabled",
|
|
&settings.windowless_rendering_enabled);
|
|
GetJNIFieldBoolean(env, cls, obj, "command_line_args_disabled",
|
|
&settings.command_line_args_disabled);
|
|
if (GetJNIFieldString(env, cls, obj, "cache_path", &tmp) && !tmp.empty()) {
|
|
CefString(&settings.cache_path) = tmp;
|
|
tmp.clear();
|
|
}
|
|
if (GetJNIFieldString(env, cls, obj, "root_cache_path", &tmp) &&
|
|
!tmp.empty()) {
|
|
CefString(&settings.root_cache_path) = tmp;
|
|
tmp.clear();
|
|
}
|
|
GetJNIFieldBoolean(env, cls, obj, "persist_session_cookies",
|
|
&settings.persist_session_cookies);
|
|
if (GetJNIFieldString(env, cls, obj, "user_agent", &tmp) && !tmp.empty()) {
|
|
CefString(&settings.user_agent) = tmp;
|
|
tmp.clear();
|
|
}
|
|
if (GetJNIFieldString(env, cls, obj, "user_agent_product", &tmp) &&
|
|
!tmp.empty()) {
|
|
CefString(&settings.user_agent_product) = tmp;
|
|
tmp.clear();
|
|
}
|
|
if (GetJNIFieldString(env, cls, obj, "locale", &tmp) && !tmp.empty()) {
|
|
CefString(&settings.locale) = tmp;
|
|
tmp.clear();
|
|
}
|
|
if (GetJNIFieldString(env, cls, obj, "log_file", &tmp) && !tmp.empty()) {
|
|
CefString(&settings.log_file) = tmp;
|
|
tmp.clear();
|
|
}
|
|
jobject obj_sev = nullptr;
|
|
if (GetJNIFieldObject(env, cls, obj, "log_severity", &obj_sev,
|
|
"Lorg/cef/CefSettings$LogSeverity;")) {
|
|
ScopedJNIObjectLocal severity(env, obj_sev);
|
|
if (IsJNIEnumValue(env, severity, "org/cef/CefSettings$LogSeverity",
|
|
"LOGSEVERITY_VERBOSE")) {
|
|
settings.log_severity = LOGSEVERITY_VERBOSE;
|
|
} else if (IsJNIEnumValue(env, severity, "org/cef/CefSettings$LogSeverity",
|
|
"LOGSEVERITY_INFO")) {
|
|
settings.log_severity = LOGSEVERITY_INFO;
|
|
} else if (IsJNIEnumValue(env, severity, "org/cef/CefSettings$LogSeverity",
|
|
"LOGSEVERITY_WARNING")) {
|
|
settings.log_severity = LOGSEVERITY_WARNING;
|
|
} else if (IsJNIEnumValue(env, severity, "org/cef/CefSettings$LogSeverity",
|
|
"LOGSEVERITY_ERROR")) {
|
|
settings.log_severity = LOGSEVERITY_ERROR;
|
|
} else if (IsJNIEnumValue(env, severity, "org/cef/CefSettings$LogSeverity",
|
|
"LOGSEVERITY_DISABLE")) {
|
|
settings.log_severity = LOGSEVERITY_DISABLE;
|
|
} else {
|
|
settings.log_severity = LOGSEVERITY_DEFAULT;
|
|
}
|
|
}
|
|
if (GetJNIFieldString(env, cls, obj, "javascript_flags", &tmp) &&
|
|
!tmp.empty()) {
|
|
CefString(&settings.javascript_flags) = tmp;
|
|
tmp.clear();
|
|
}
|
|
if (GetJNIFieldString(env, cls, obj, "resources_dir_path", &tmp) &&
|
|
!tmp.empty()) {
|
|
CefString(&settings.resources_dir_path) = tmp;
|
|
tmp.clear();
|
|
}
|
|
if (GetJNIFieldString(env, cls, obj, "locales_dir_path", &tmp) &&
|
|
!tmp.empty()) {
|
|
CefString(&settings.locales_dir_path) = tmp;
|
|
tmp.clear();
|
|
}
|
|
GetJNIFieldInt(env, cls, obj, "remote_debugging_port",
|
|
&settings.remote_debugging_port);
|
|
if (GetJNIFieldString(env, cls, obj, "chrome_policy_id", &tmp) &&
|
|
!tmp.empty()) {
|
|
CefString(&settings.chrome_policy_id) = tmp;
|
|
tmp.clear();
|
|
}
|
|
GetJNIFieldInt(env, cls, obj, "uncaught_exception_stack_size",
|
|
&settings.uncaught_exception_stack_size);
|
|
jobject obj_col = nullptr;
|
|
if (GetJNIFieldObject(env, cls, obj, "background_color", &obj_col,
|
|
"Lorg/cef/CefSettings$ColorType;")) {
|
|
ScopedJNIObjectLocal color_type(env, obj_col);
|
|
jlong jcolor = 0;
|
|
JNI_CALL_METHOD(env, color_type, "getColor", "()J", Long, jcolor);
|
|
settings.background_color = (cef_color_t)jcolor;
|
|
}
|
|
if (GetJNIFieldString(env, cls, obj, "cookieable_schemes_list", &tmp) &&
|
|
!tmp.empty()) {
|
|
CefString(&settings.cookieable_schemes_list) = tmp;
|
|
tmp.clear();
|
|
}
|
|
GetJNIFieldBoolean(env, cls, obj, "cookieable_schemes_exclude_defaults",
|
|
&settings.cookieable_schemes_exclude_defaults);
|
|
|
|
return settings;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// static
|
|
void Context::Create() {
|
|
new Context();
|
|
}
|
|
|
|
// static
|
|
void Context::Destroy() {
|
|
DCHECK(g_context);
|
|
if (g_context)
|
|
delete g_context;
|
|
}
|
|
|
|
// static
|
|
Context* Context::GetInstance() {
|
|
return g_context;
|
|
}
|
|
|
|
bool Context::PreInitialize(JNIEnv* env, jobject c) {
|
|
DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
|
JavaVM* jvm;
|
|
jint rs = env->GetJavaVM(&jvm);
|
|
DCHECK_EQ(rs, JNI_OK);
|
|
if (rs != JNI_OK)
|
|
return JNI_FALSE;
|
|
SetJVM(jvm);
|
|
|
|
ScopedJNIClass javaClass(env, env->GetObjectClass(c));
|
|
ScopedJNIObjectResult javaClassLoader(env);
|
|
JNI_CALL_METHOD(env, javaClass, "getClassLoader", "()Ljava/lang/ClassLoader;",
|
|
Object, javaClassLoader);
|
|
ASSERT(javaClassLoader);
|
|
if (!javaClassLoader)
|
|
return false;
|
|
SetJavaClassLoader(env, javaClassLoader);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Context::Initialize(JNIEnv* env,
|
|
jobject c,
|
|
jobject appHandler,
|
|
jobject jsettings) {
|
|
DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
|
#if defined(OS_WIN)
|
|
CefMainArgs main_args(::GetModuleHandle(nullptr));
|
|
#else
|
|
CefMainArgs main_args(0, nullptr);
|
|
#endif
|
|
|
|
CefSettings settings = GetJNISettings(env, jsettings);
|
|
|
|
// Sandbox is not supported because:
|
|
// - Use of a separate sub-process executable on Windows.
|
|
// - Use of a temporary file to communicate custom schemes to the
|
|
// renderer process.
|
|
settings.no_sandbox = true;
|
|
|
|
#if defined(OS_WIN) || defined(OS_LINUX)
|
|
// Use external message pump with OSR.
|
|
external_message_pump_ = !!settings.windowless_rendering_enabled;
|
|
if (!external_message_pump_) {
|
|
// Windowed rendering on Windows requires multi-threaded message loop,
|
|
// otherwise something eats the messages required by Java and the Java
|
|
// window becomes unresponsive.
|
|
//
|
|
// Actually the same appears to be true for Linux, which is why we also
|
|
// need multithreaded message loops there. Note that however, on Linux
|
|
// it is more difficult to get this to work: it is necessary for the first
|
|
// call to Xlib to be a call to XInitThreads! Since Java itself calls
|
|
// Xlib when it initializes the first window, an application must make
|
|
// sure to invoke this method before any other Xlib functions are called
|
|
// - including by the Java runtime itself, which makes this feat a little
|
|
// tricky. The CefApp class exposes a static method for this purpose,
|
|
// initXlibForMultithreading(), but the host application must load the
|
|
// jcef native lib by itself in order to use it, and it must invoke it
|
|
// VERY early, ideally at the beginning of the main method.
|
|
// Another neat trick to get this done is to create a special native lib
|
|
// just for this purpose like described in this StackOverflow thread:
|
|
// https://stackoverflow.com/questions/24559368
|
|
settings.multi_threaded_message_loop = true;
|
|
}
|
|
#endif
|
|
|
|
// Use CefAppHandler.onScheduleMessagePumpWork to schedule calls to
|
|
// DoMessageLoopWork.
|
|
settings.external_message_pump = external_message_pump_;
|
|
|
|
CefRefPtr<ClientApp> client_app(
|
|
new ClientApp(CefString(&settings.cache_path), env, appHandler));
|
|
bool res = false;
|
|
|
|
#if defined(OS_MACOSX)
|
|
res = util_mac::CefInitializeOnMainThread(main_args, settings,
|
|
client_app.get());
|
|
#else
|
|
res = CefInitialize(main_args, settings, client_app.get(), nullptr);
|
|
#endif
|
|
|
|
return res;
|
|
}
|
|
|
|
void Context::OnContextInitialized() {
|
|
REQUIRE_UI_THREAD();
|
|
temp_window_.reset(new TempWindow());
|
|
}
|
|
|
|
void Context::DoMessageLoopWork() {
|
|
DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
|
#if defined(OS_MACOSX)
|
|
util_mac::CefDoMessageLoopWorkOnMainThread();
|
|
#else
|
|
CefDoMessageLoopWork();
|
|
#endif
|
|
}
|
|
|
|
void Context::Shutdown() {
|
|
DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
|
// Clear scheme handler factories on shutdown to avoid refcount DCHECK.
|
|
CefClearSchemeHandlerFactories();
|
|
|
|
ClientApp::eraseTempFiles();
|
|
#if defined(OS_MACOSX)
|
|
util_mac::CefShutdownOnMainThread();
|
|
#else
|
|
// Pump CefDoMessageLoopWork a few times before shutting down.
|
|
if (external_message_pump_) {
|
|
for (int i = 0; i < 10; ++i)
|
|
CefDoMessageLoopWork();
|
|
}
|
|
|
|
temp_window_.reset(nullptr);
|
|
|
|
CefShutdown();
|
|
#endif
|
|
}
|
|
|
|
Context::Context() : external_message_pump_(true) {
|
|
DCHECK(!g_context);
|
|
g_context = this;
|
|
|
|
#if defined(OS_MACOSX)
|
|
// On macOS we create this object very early to allow LibraryLoader
|
|
// assignment. However, we still want the PreInitialize() call to determine
|
|
// thread ownership.
|
|
thread_checker_.DetachFromThread();
|
|
#endif
|
|
}
|
|
|
|
Context::~Context() {
|
|
DCHECK(thread_checker_.CalledOnValidThread());
|
|
g_context = nullptr;
|
|
|
|
#if defined(OS_MACOSX)
|
|
cef_unload_library();
|
|
#endif
|
|
}
|