native/CefBrowser_N.cpp (1,300 lines of code) (raw):

// 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. #include "CefBrowser_N.h" #include "include/base/cef_callback.h" #include "include/cef_browser.h" #include "include/cef_parser.h" #include "include/cef_task.h" #include "include/wrapper/cef_closure_task.h" #include "browser_process_handler.h" #include "client_handler.h" #include "critical_wait.h" #include "devtools_message_observer.h" #include "int_callback.h" #include "jni_util.h" #include "keyboard_utils.h" #include "life_span_handler.h" #include "pdf_print_callback.h" #include "run_file_dialog_callback.h" #include "string_visitor.h" #include "temp_window.h" #include "window_handler.h" #if defined(OS_LINUX) #define XK_3270 // for XK_3270_BackTab #include <X11/XF86keysym.h> #include <X11/keysym.h> #include <memory> #endif #if defined(OS_MAC) #include "util_mac.h" #endif #if defined(OS_WIN) #include <memory> #include <synchapi.h> #undef MOUSE_MOVED #endif namespace { int GetCefModifiers(JNIEnv* env, jclass cls, int modifiers) { JNI_STATIC_DEFINE_INT_RV(env, cls, ALT_DOWN_MASK, 0); JNI_STATIC_DEFINE_INT_RV(env, cls, BUTTON1_DOWN_MASK, 0); JNI_STATIC_DEFINE_INT_RV(env, cls, BUTTON2_DOWN_MASK, 0); JNI_STATIC_DEFINE_INT_RV(env, cls, BUTTON3_DOWN_MASK, 0); JNI_STATIC_DEFINE_INT_RV(env, cls, CTRL_DOWN_MASK, 0); JNI_STATIC_DEFINE_INT_RV(env, cls, META_DOWN_MASK, 0); JNI_STATIC_DEFINE_INT_RV(env, cls, SHIFT_DOWN_MASK, 0); int cef_modifiers = 0; if (modifiers & JNI_STATIC(ALT_DOWN_MASK)) cef_modifiers |= EVENTFLAG_ALT_DOWN; if (modifiers & JNI_STATIC(BUTTON1_DOWN_MASK)) cef_modifiers |= EVENTFLAG_LEFT_MOUSE_BUTTON; if (modifiers & JNI_STATIC(BUTTON2_DOWN_MASK)) cef_modifiers |= EVENTFLAG_MIDDLE_MOUSE_BUTTON; if (modifiers & JNI_STATIC(BUTTON3_DOWN_MASK)) cef_modifiers |= EVENTFLAG_RIGHT_MOUSE_BUTTON; if (modifiers & JNI_STATIC(CTRL_DOWN_MASK)) cef_modifiers |= EVENTFLAG_CONTROL_DOWN; if (modifiers & JNI_STATIC(META_DOWN_MASK)) cef_modifiers |= EVENTFLAG_COMMAND_DOWN; if (modifiers & JNI_STATIC(SHIFT_DOWN_MASK)) cef_modifiers |= EVENTFLAG_SHIFT_DOWN; return cef_modifiers; } struct JNIObjectsForCreate { public: ScopedJNIObjectGlobal jbrowser; ScopedJNIObjectGlobal jparentBrowser; ScopedJNIObjectGlobal jclientHandler; ScopedJNIObjectGlobal url; ScopedJNIObjectGlobal canvas; ScopedJNIObjectGlobal jcontext; ScopedJNIObjectGlobal jinspectAt; ScopedJNIObjectGlobal jbrowserSettings; JNIObjectsForCreate(JNIEnv* env, jobject _jbrowser, jobject _jparentBrowser, jobject _jclientHandler, jstring _url, jobject _canvas, jobject _jcontext, jobject _jinspectAt, jobject _browserSettings) : jbrowser(env, _jbrowser), jparentBrowser(env, _jparentBrowser), jclientHandler(env, _jclientHandler), url(env, _url), canvas(env, _canvas), jcontext(env, _jcontext), jinspectAt(env, _jinspectAt), jbrowserSettings(env, _browserSettings) {} }; #if defined(OS_MAC) class WindowHandleHolder { public: WindowHandleHolder(jlong _handle) : handle(_handle) {} ~WindowHandleHolder() { util_mac::releaseObj(handle); } private: jlong handle; }; #endif void create(std::shared_ptr<JNIObjectsForCreate> objs, jlong windowHandle, jboolean osr, jboolean transparent) { #if defined(OS_MAC) WindowHandleHolder windowHandleHolder(windowHandle); #endif ScopedJNIEnv env; CefRefPtr<ClientHandler> clientHandler = GetCefFromJNIObject_sync<ClientHandler>( env, objs->jclientHandler, "CefClientHandler"); if (!clientHandler.get()) return; CefRefPtr<LifeSpanHandler> lifeSpanHandler = (LifeSpanHandler*)clientHandler->GetLifeSpanHandler().get(); if (!lifeSpanHandler.get()) return; CefRefPtr<CefBrowser> parentBrowser = GetCefFromJNIObject<CefBrowser>(env, objs->jparentBrowser, "CefBrowser"); CefWindowInfo windowInfo; CefBrowserSettings settings; // If parentBrowser is set, we want to show the DEV-Tools for that browser. // Since that cannot be an Alloy-style window, it cannot be integrated into // Java UI but must be opened as a pop-up. if (parentBrowser.get() != nullptr) { CefPoint inspectAt; if (objs->jinspectAt != nullptr) { int x, y; GetJNIPoint(env, objs->jinspectAt, &x, &y); inspectAt.Set(x, y); } parentBrowser->GetHost()->ShowDevTools(windowInfo, clientHandler.get(), settings, inspectAt); JNI_CALL_VOID_METHOD(env, objs->jbrowser, "notifyBrowserCreated", "()V"); return; } if (osr == JNI_FALSE) { CefRect rect; CefRefPtr<WindowHandler> windowHandler = (WindowHandler*)clientHandler->GetWindowHandler().get(); if (windowHandler.get()) { windowHandler->GetRect(objs->jbrowser, rect); } #if defined(OS_WIN) CefWindowHandle parent = TempWindow::GetWindowHandle(); if (objs->canvas != nullptr) { parent = GetHwndOfCanvas(objs->canvas, env); } else { // Do not activate hidden browser windows on creation. windowInfo.ex_style |= WS_EX_NOACTIVATE; } windowInfo.SetAsChild(parent, rect); #elif defined(OS_MAC) NSWindow* parent = nullptr; if (windowHandle != 0) { parent = (NSWindow*)windowHandle; } else { parent = TempWindow::GetWindow(); } CefWindowHandle browserContentView = util_mac::CreateBrowserContentView(parent, rect); windowInfo.SetAsChild(browserContentView, rect); #elif defined(OS_LINUX) CefWindowHandle parent = TempWindow::GetWindowHandle(); if (objs->canvas != nullptr) { parent = GetDrawableOfCanvas(objs->canvas, env); } windowInfo.SetAsChild(parent, rect); #endif } else { #if defined(OS_MAC) windowInfo.SetAsWindowless( (CefWindowHandle)util_mac::GetNSView((void*)windowHandle)); #else windowInfo.SetAsWindowless((CefWindowHandle)windowHandle); #endif } ScopedJNIClass cefBrowserSettings(env, "org/cef/CefBrowserSettings"); if (cefBrowserSettings != nullptr && objs->jbrowserSettings != nullptr) { // Dev-tools settings are null GetJNIFieldInt(env, cefBrowserSettings, objs->jbrowserSettings, "windowless_frame_rate", &settings.windowless_frame_rate); GetJNIFieldBoolean(env, cefBrowserSettings, objs->jbrowserSettings, "sharedTexturesEnabled", &windowInfo.shared_texture_enabled); } CefRefPtr<CefBrowser> browserObj; CefString strUrl = GetJNIString(env, static_cast<jstring>(objs->url.get())); CefRefPtr<CefRequestContext> context = GetCefFromJNIObject_sync<CefRequestContext>( env, objs->jcontext, "CefRequestContext"); // Add a global ref that will be released in LifeSpanHandler::OnAfterCreated. jobject globalRef = env->NewGlobalRef(objs->jbrowser); lifeSpanHandler->registerJBrowser(globalRef); CefRefPtr<CefDictionaryValue> extra_info; auto router_configs = BrowserProcessHandler::GetMessageRouterConfigs(); if (router_configs) { // Send the message router config to CefHelperApp::OnBrowserCreated. extra_info = CefDictionaryValue::Create(); extra_info->SetList("router_configs", router_configs); } // JCEF requires Alloy runtime style for "normal" browsers in order for them // to be integratable into Java UI. windowInfo.runtime_style = CEF_RUNTIME_STYLE_ALLOY; bool result = CefBrowserHost::CreateBrowser( windowInfo, clientHandler.get(), strUrl, settings, extra_info, context); if (!result) { lifeSpanHandler->unregisterJBrowser(globalRef); env->DeleteGlobalRef(globalRef); return; } JNI_CALL_VOID_METHOD(env, objs->jbrowser, "notifyBrowserCreated", "()V"); } static void getZoomLevel(CefRefPtr<CefBrowserHost> host, std::shared_ptr<double> result) { *result = host->GetZoomLevel(); } void executeDevToolsMethod(CefRefPtr<CefBrowserHost> host, const CefString& method, const CefString& parametersAsJson, CefRefPtr<IntCallback> callback) { CefRefPtr<CefDictionaryValue> parameters = nullptr; if (!parametersAsJson.empty()) { CefRefPtr<CefValue> value = CefParseJSON( parametersAsJson, cef_json_parser_options_t::JSON_PARSER_RFC); if (!value || value->GetType() != VTYPE_DICTIONARY) { callback->onComplete(0); return; } parameters = value->GetDictionary(); } callback->onComplete(host->ExecuteDevToolsMethod(0, method, parameters)); } void OnAfterParentChanged(CefRefPtr<CefBrowser> browser) { if (!CefCurrentlyOn(TID_UI)) { CefPostTask(TID_UI, base::BindOnce(&OnAfterParentChanged, browser)); return; } if (browser->GetHost()->GetClient()) { CefRefPtr<LifeSpanHandler> lifeSpanHandler = (LifeSpanHandler*)browser->GetHost() ->GetClient() ->GetLifeSpanHandler() .get(); if (lifeSpanHandler) { lifeSpanHandler->OnAfterParentChanged(browser); } } } CefPdfPrintSettings GetJNIPdfPrintSettings(JNIEnv* env, jobject obj) { CefString tmp; CefPdfPrintSettings settings; if (!obj) return settings; ScopedJNIClass cls(env, "org/cef/misc/CefPdfPrintSettings"); if (!cls) return settings; GetJNIFieldBoolean(env, cls, obj, "landscape", &settings.landscape); GetJNIFieldBoolean(env, cls, obj, "print_background", &settings.print_background); GetJNIFieldDouble(env, cls, obj, "scale", &settings.scale); GetJNIFieldDouble(env, cls, obj, "paper_width", &settings.paper_width); GetJNIFieldDouble(env, cls, obj, "paper_height", &settings.paper_height); GetJNIFieldBoolean(env, cls, obj, "prefer_css_page_size", &settings.prefer_css_page_size); jobject obj_margin_type = nullptr; if (GetJNIFieldObject(env, cls, obj, "margin_type", &obj_margin_type, "Lorg/cef/misc/CefPdfPrintSettings$MarginType;")) { ScopedJNIObjectLocal margin_type(env, obj_margin_type); if (IsJNIEnumValue(env, margin_type, "org/cef/misc/CefPdfPrintSettings$MarginType", "DEFAULT")) { settings.margin_type = PDF_PRINT_MARGIN_DEFAULT; } else if (IsJNIEnumValue(env, margin_type, "org/cef/misc/CefPdfPrintSettings$MarginType", "NONE")) { settings.margin_type = PDF_PRINT_MARGIN_NONE; } else if (IsJNIEnumValue(env, margin_type, "org/cef/misc/CefPdfPrintSettings$MarginType", "CUSTOM")) { settings.margin_type = PDF_PRINT_MARGIN_CUSTOM; } } GetJNIFieldDouble(env, cls, obj, "margin_top", &settings.margin_top); GetJNIFieldDouble(env, cls, obj, "margin_bottom", &settings.margin_bottom); GetJNIFieldDouble(env, cls, obj, "margin_right", &settings.margin_right); GetJNIFieldDouble(env, cls, obj, "margin_left", &settings.margin_left); if (GetJNIFieldString(env, cls, obj, "page_ranges", &tmp) && !tmp.empty()) { CefString(&settings.page_ranges) = tmp; tmp.clear(); } GetJNIFieldBoolean(env, cls, obj, "display_header_footer", &settings.display_header_footer); if (GetJNIFieldString(env, cls, obj, "header_template", &tmp) && !tmp.empty()) { CefString(&settings.header_template) = tmp; tmp.clear(); } if (GetJNIFieldString(env, cls, obj, "footer_template", &tmp) && !tmp.empty()) { CefString(&settings.footer_template) = tmp; tmp.clear(); } GetJNIFieldBoolean(env, cls, obj, "generate_tagged_pdf", &settings.generate_tagged_pdf); GetJNIFieldBoolean(env, cls, obj, "generate_document_outline", &settings.generate_document_outline); return settings; } // JNI CefRegistration object. class ScopedJNIRegistration : public ScopedJNIObject<CefRegistration> { public: ScopedJNIRegistration(JNIEnv* env, CefRefPtr<CefRegistration> obj) : ScopedJNIObject<CefRegistration>(env, obj, "org/cef/browser/CefRegistration_N", "CefRegistration") {} }; } // namespace JNIEXPORT jboolean JNICALL Java_org_cef_browser_CefBrowser_1N_N_1CreateBrowser(JNIEnv* env, jobject jbrowser, jobject jclientHandler, jlong windowHandle, jstring url, jboolean osr, jboolean transparent, jobject canvas, jobject jcontext, jobject browserSettings) { std::shared_ptr<JNIObjectsForCreate> objs( new JNIObjectsForCreate(env, jbrowser, nullptr, jclientHandler, url, canvas, jcontext, nullptr, browserSettings)); #if defined(OS_MAC) if (windowHandle != 0) // Retain handle to prevent crash, see JBR-6603 util_mac::retainObj(windowHandle); #endif if (CefCurrentlyOn(TID_UI)) { create(objs, windowHandle, osr, transparent); } else { CefPostTask(TID_UI, base::BindOnce(&create, objs, windowHandle, osr, transparent)); } return JNI_FALSE; // set asynchronously } JNIEXPORT jboolean JNICALL Java_org_cef_browser_CefBrowser_1N_N_1CreateDevTools(JNIEnv* env, jobject jbrowser, jobject jparent, jobject jclientHandler, jlong windowHandle, jboolean osr, jboolean transparent, jobject canvas, jobject inspect) { std::shared_ptr<JNIObjectsForCreate> objs( new JNIObjectsForCreate(env, jbrowser, jparent, jclientHandler, nullptr, canvas, nullptr, inspect, nullptr)); #if defined(OS_MAC) if (windowHandle != 0) // Retain handle to prevent crash, see JBR-6603 util_mac::retainObj(windowHandle); #endif if (CefCurrentlyOn(TID_UI)) { create(objs, windowHandle, osr, transparent); } else { CefPostTask(TID_UI, base::BindOnce(&create, objs, windowHandle, osr, transparent)); } return JNI_FALSE; // set asynchronously } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1ExecuteDevToolsMethod( JNIEnv* env, jobject jbrowser, jstring method, jstring parametersAsJson, jobject jcallback) { CefRefPtr<IntCallback> callback = new IntCallback(env, jcallback); CefRefPtr<CefBrowser> browser = GetJNIBrowser(env, jbrowser); if (!browser.get()) { callback->onComplete(0); return; } CefString strMethod = GetJNIString(env, method); CefString strParametersAsJson = GetJNIString(env, parametersAsJson); if (CefCurrentlyOn(TID_UI)) { executeDevToolsMethod(browser->GetHost(), strMethod, strParametersAsJson, callback); } else { CefPostTask(TID_UI, base::BindOnce(executeDevToolsMethod, browser->GetHost(), strMethod, strParametersAsJson, callback)); } } JNIEXPORT jobject JNICALL Java_org_cef_browser_CefBrowser_1N_N_1AddDevToolsMessageObserver( JNIEnv* env, jobject jbrowser, jobject jobserver) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, jbrowser, NULL); CefRefPtr<DevToolsMessageObserver> observer = new DevToolsMessageObserver(env, jobserver); CefRefPtr<CefRegistration> registration = browser->GetHost()->AddDevToolsMessageObserver(observer); ScopedJNIRegistration jregistration(env, registration); return jregistration.Release(); } JNIEXPORT jlong JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetWindowHandle(JNIEnv* env, jobject obj, jlong displayHandle) { CefWindowHandle windowHandle = kNullWindowHandle; #if defined(OS_WIN) windowHandle = ::WindowFromDC((HDC)displayHandle); #elif defined(OS_LINUX) return displayHandle; #elif defined(OS_MAC) ASSERT(util_mac::IsNSView((void*)displayHandle)); #endif return (jlong)windowHandle; } JNIEXPORT jboolean JNICALL Java_org_cef_browser_CefBrowser_1N_N_1CanGoBack(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, JNI_FALSE); return browser->CanGoBack() ? JNI_TRUE : JNI_FALSE; } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GoBack(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GoBack(); } JNIEXPORT jboolean JNICALL Java_org_cef_browser_CefBrowser_1N_N_1CanGoForward(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, JNI_FALSE); return browser->CanGoForward() ? JNI_TRUE : JNI_FALSE; } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GoForward(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GoForward(); } JNIEXPORT jboolean JNICALL Java_org_cef_browser_CefBrowser_1N_N_1IsLoading(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, JNI_FALSE); return browser->IsLoading() ? JNI_TRUE : JNI_FALSE; } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1Reload(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->Reload(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1ReloadIgnoreCache(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->ReloadIgnoreCache(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1StopLoad(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->StopLoad(); } JNIEXPORT jint JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetIdentifier(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, -1); return browser->GetIdentifier(); } JNIEXPORT jobject JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetMainFrame(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, nullptr); CefRefPtr<CefFrame> frame = browser->GetMainFrame(); if (!frame) return nullptr; ScopedJNIFrame jframe(env, frame); return jframe.Release(); } JNIEXPORT jobject JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetFocusedFrame(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, nullptr); CefRefPtr<CefFrame> frame = browser->GetFocusedFrame(); if (!frame) return nullptr; ScopedJNIFrame jframe(env, frame); return jframe.Release(); } JNIEXPORT jobject JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetFrame(JNIEnv* env, jobject obj, jstring identifier) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, nullptr); CefRefPtr<CefFrame> frame = browser->GetFrameByIdentifier(GetJNIString(env, identifier)); if (!frame) return nullptr; ScopedJNIFrame jframe(env, frame); return jframe.Release(); } JNIEXPORT jobject JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetFrame2(JNIEnv* env, jobject obj, jstring name) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, nullptr); CefRefPtr<CefFrame> frame = browser->GetFrameByName(GetJNIString(env, name)); if (!frame) return nullptr; ScopedJNIFrame jframe(env, frame); return jframe.Release(); } JNIEXPORT jint JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetFrameCount(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, -1); return (jint)browser->GetFrameCount(); } JNIEXPORT jobject JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetFrameIdentifiers(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, nullptr); std::vector<CefString> identifiers; browser->GetFrameIdentifiers(identifiers); return NewJNIStringVector(env, identifiers); } JNIEXPORT jobject JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetFrameNames(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, nullptr); std::vector<CefString> names; browser->GetFrameNames(names); return NewJNIStringVector(env, names); } JNIEXPORT jboolean JNICALL Java_org_cef_browser_CefBrowser_1N_N_1IsPopup(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, JNI_FALSE); return browser->IsPopup() ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jboolean JNICALL Java_org_cef_browser_CefBrowser_1N_N_1HasDocument(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, JNI_FALSE); return browser->HasDocument() ? JNI_TRUE : JNI_FALSE; } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1ViewSource(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); CefRefPtr<CefFrame> mainFrame = browser->GetMainFrame(); CefPostTask(TID_UI, base::BindOnce(&CefFrame::ViewSource, mainFrame.get())); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetSource(JNIEnv* env, jobject obj, jobject jvisitor) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetMainFrame()->GetSource(new StringVisitor(env, jvisitor)); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetText(JNIEnv* env, jobject obj, jobject jvisitor) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetMainFrame()->GetText(new StringVisitor(env, jvisitor)); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1LoadRequest(JNIEnv* env, jobject obj, jobject jrequest) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); ScopedJNIRequest requestObj(env); requestObj.SetHandle(jrequest, false /* should_delete */); CefRefPtr<CefRequest> request = requestObj.GetCefObject(); if (!request) return; browser->GetMainFrame()->LoadRequest(request); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1LoadURL(JNIEnv* env, jobject obj, jstring url) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetMainFrame()->LoadURL(GetJNIString(env, url)); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1ExecuteJavaScript(JNIEnv* env, jobject obj, jstring code, jstring url, jint line) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetMainFrame()->ExecuteJavaScript(GetJNIString(env, code), GetJNIString(env, url), line); } JNIEXPORT jstring JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetURL(JNIEnv* env, jobject obj) { jstring tmp = env->NewStringUTF(""); CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, tmp); return NewJNIString(env, browser->GetMainFrame()->GetURL()); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1Close(JNIEnv* env, jobject obj, jboolean force) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); if (force != JNI_FALSE) { if (browser->GetHost()->IsWindowRenderingDisabled()) { browser->GetHost()->CloseBrowser(true); } else { // Destroy the native window representation. if (CefCurrentlyOn(TID_UI)) util::DestroyCefBrowser(browser); else CefPostTask(TID_UI, base::BindOnce(&util::DestroyCefBrowser, browser)); } } else { browser->GetHost()->CloseBrowser(false); } } namespace { void _runTaskAndWakeup(std::shared_ptr<CriticalWait> waitCond, base::OnceClosure task) { waitCond->lock()->Lock(); std::move(task).Run(); waitCond->WakeUp(); waitCond->lock()->Unlock(); } void CefPostTaskAndWait(CefThreadId threadId, base::OnceClosure task, long waitMillis) { std::shared_ptr<CriticalLock> lock = std::make_shared<CriticalLock>(); std::shared_ptr<CriticalWait> waitCond = std::make_shared<CriticalWait>(lock.get()); lock.get()->Lock(); CefPostTask(threadId, base::BindOnce(_runTaskAndWakeup, waitCond, std::move(task))); waitCond.get()->Wait(static_cast<unsigned int>(waitMillis)); lock.get()->Unlock(); } } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1SetFocus(JNIEnv* env, jobject obj, jboolean enable) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->SetFocus(enable != JNI_FALSE); #if defined(OS_WIN) if (!browser->GetHost()->IsWindowRenderingDisabled()) { if (enable == JNI_FALSE) { if (CefCurrentlyOn(TID_UI)) { util::UnfocusCefBrowser(browser); } else { CefPostTaskAndWait(TID_UI, base::BindOnce(&util::UnfocusCefBrowser, browser), 1000); } } } #endif } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1SetWindowVisibility(JNIEnv* env, jobject obj, jboolean visible) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); #if defined(OS_MAC) if (!browser->GetHost()->IsWindowRenderingDisabled()) { util_mac::SetVisibility(browser->GetHost()->GetWindowHandle(), visible != JNI_FALSE); } #endif } JNIEXPORT jdouble JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetZoomLevel(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj, 0.0); CefRefPtr<CefBrowserHost> host = browser->GetHost(); if (CefCurrentlyOn(TID_UI)) { return host->GetZoomLevel(); } std::shared_ptr<double> result = std::make_shared<double>(0.0); CefPostTaskAndWait(TID_UI, base::BindOnce(getZoomLevel, host, result), 1000); return *result; } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1SetZoomLevel(JNIEnv* env, jobject obj, jdouble zoom) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->SetZoomLevel(zoom); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1RunFileDialog(JNIEnv* env, jobject obj, jobject jmode, jstring jtitle, jstring jdefaultFilePath, jobject jacceptFilters, jobject jcallback) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); std::vector<CefString> accept_types; GetJNIStringVector(env, jacceptFilters, accept_types); CefBrowserHost::FileDialogMode mode; if (IsJNIEnumValue(env, jmode, "org/cef/handler/CefDialogHandler$FileDialogMode", "FILE_DIALOG_OPEN")) { mode = FILE_DIALOG_OPEN; } else if (IsJNIEnumValue(env, jmode, "org/cef/handler/CefDialogHandler$FileDialogMode", "FILE_DIALOG_OPEN_MULTIPLE")) { mode = FILE_DIALOG_OPEN_MULTIPLE; } else if (IsJNIEnumValue(env, jmode, "org/cef/handler/CefDialogHandler$FileDialogMode", "FILE_DIALOG_SAVE")) { mode = FILE_DIALOG_SAVE; } else { mode = FILE_DIALOG_OPEN; } browser->GetHost()->RunFileDialog( mode, GetJNIString(env, jtitle), GetJNIString(env, jdefaultFilePath), accept_types, new RunFileDialogCallback(env, jcallback)); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1StartDownload(JNIEnv* env, jobject obj, jstring url) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->StartDownload(GetJNIString(env, url)); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1Print(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->Print(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1PrintToPDF(JNIEnv* env, jobject obj, jstring jpath, jobject jsettings, jobject jcallback) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); CefPdfPrintSettings settings = GetJNIPdfPrintSettings(env, jsettings); browser->GetHost()->PrintToPDF(GetJNIString(env, jpath), settings, new PdfPrintCallback(env, jcallback)); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1Find(JNIEnv* env, jobject obj, jstring searchText, jboolean forward, jboolean matchCase, jboolean findNext) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->Find(GetJNIString(env, searchText), (forward != JNI_FALSE), (matchCase != JNI_FALSE), (findNext != JNI_FALSE)); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1StopFinding(JNIEnv* env, jobject obj, jboolean clearSelection) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->StopFinding(clearSelection != JNI_FALSE); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1CloseDevTools(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->CloseDevTools(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1ReplaceMisspelling(JNIEnv* env, jobject obj, jstring jword) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->ReplaceMisspelling(GetJNIString(env, jword)); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1WasResized(JNIEnv* env, jobject obj, jint width, jint height) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); if (browser->GetHost()->IsWindowRenderingDisabled()) { browser->GetHost()->WasResized(); } #if (defined(OS_WIN) || defined(OS_LINUX)) else { CefWindowHandle browserHandle = browser->GetHost()->GetWindowHandle(); if (CefCurrentlyOn(TID_UI)) { util::SetWindowSize(browserHandle, width, height); } else { CefPostTask(TID_UI, base::BindOnce(util::SetWindowSize, browserHandle, (int)width, (int)height)); } } #endif } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1Invalidate(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->Invalidate(PET_VIEW); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1SendKeyEvent(JNIEnv* env, jobject obj, jobject key_event) { using namespace jcef_keyboard_utils; CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); CefKeyEventAttributes eventAttributes{}; if (!javaKeyEventToCef(env, key_event, &eventAttributes)) { LOG(ERROR) << "CefBrowser#SendKeyEvent: failed to convert the key event"; return; } CefKeyEvent cef_key_event{}; cef_key_event.type = static_cast<cef_key_event_type_t>(eventAttributes.type); cef_key_event.modifiers = eventAttributes.modifiers; cef_key_event.character = eventAttributes.character; cef_key_event.unmodified_character = eventAttributes.unmodified_character; cef_key_event.native_key_code = eventAttributes.native_key_code; cef_key_event.windows_key_code = eventAttributes.windows_key_code; cef_key_event.is_system_key = eventAttributes.is_system_key; browser->GetHost()->SendKeyEvent(cef_key_event); } namespace { cef_touch_event_type_t GetTouchEventType(JNIEnv* env, const ScopedJNIObjectResult& jValue) { const char* CLASS_NAME = "org/cef/input/CefTouchEvent$EventType"; if (IsJNIEnumValue(env, jValue, CLASS_NAME, "RELEASED")) { return CEF_TET_RELEASED; } else if (IsJNIEnumValue(env, jValue, CLASS_NAME, "PRESSED")) { return CEF_TET_PRESSED; } else if (IsJNIEnumValue(env, jValue, CLASS_NAME, "MOVED")) { return CEF_TET_MOVED; } return CEF_TET_CANCELLED; } cef_pointer_type_t GetPointerType(JNIEnv* env, const ScopedJNIObjectResult& jValue) { const char* CLASS_NAME = "org/cef/input/CefTouchEvent$PointerType"; if (IsJNIEnumValue(env, jValue, CLASS_NAME, "TOUCH")) { return CEF_POINTER_TYPE_TOUCH; } else if (IsJNIEnumValue(env, jValue, CLASS_NAME, "MOUSE")) { return CEF_POINTER_TYPE_MOUSE; } else if (IsJNIEnumValue(env, jValue, CLASS_NAME, "PEN")) { return CEF_POINTER_TYPE_PEN; } else if (IsJNIEnumValue(env, jValue, CLASS_NAME, "ERASER")) { return CEF_POINTER_TYPE_ERASER; } return CEF_POINTER_TYPE_UNKNOWN; } } // namespace void Java_org_cef_browser_CefBrowser_1N_N_1SendTouchEvent(JNIEnv* env, jobject obj, jobject jEvent) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); ScopedJNIClass cls(env, env->GetObjectClass(jEvent)); if (!cls) return; ScopedJNIObjectResult jEventType(env); int modifiers; ScopedJNIObjectResult jPointerType(env); cef_touch_event_t event = {}; if (!CallJNIMethodI_V(env, cls, jEvent, "getId", &event.id) || !CallJNIMethodF_V(env, cls, jEvent, "getX", &event.x) || !CallJNIMethodF_V(env, cls, jEvent, "getY", &event.y) || !CallJNIMethodF_V(env, cls, jEvent, "getRadiusX", &event.radius_x) || !CallJNIMethodF_V(env, cls, jEvent, "getRadiusY", &event.radius_y) || !CallJNIMethodF_V(env, cls, jEvent, "getRotationAngle", &event.rotation_angle) || !CallJNIMethodObject_V(env, cls, jEvent, "getType", "()Lorg/cef/input/CefTouchEvent$EventType;", &jEventType) || !CallJNIMethodF_V(env, cls, jEvent, "getPressure", &event.pressure) || !CallJNIMethodI_V(env, cls, jEvent, "getModifiersEx", &modifiers) || !CallJNIMethodObject_V(env, cls, jEvent, "getPointerType", "()Lorg/cef/input/CefTouchEvent$PointerType;", &jPointerType) ) { LOG(ERROR) << "SendTouchEvent: Failed to access touch event data"; return; } event.type = GetTouchEventType(env, jEventType); event.modifiers = GetCefModifiers(env, cls, modifiers); event.pointer_type = GetPointerType(env, jPointerType); browser->GetHost()->SendTouchEvent(event); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1SendMouseEvent(JNIEnv* env, jobject obj, jobject mouse_event) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); ScopedJNIClass cls(env, env->GetObjectClass(mouse_event)); if (!cls) return; JNI_STATIC_DEFINE_INT(env, cls, BUTTON1); JNI_STATIC_DEFINE_INT(env, cls, BUTTON2); JNI_STATIC_DEFINE_INT(env, cls, BUTTON3); JNI_STATIC_DEFINE_INT(env, cls, MOUSE_DRAGGED); JNI_STATIC_DEFINE_INT(env, cls, MOUSE_ENTERED); JNI_STATIC_DEFINE_INT(env, cls, MOUSE_EXITED); JNI_STATIC_DEFINE_INT(env, cls, MOUSE_MOVED); JNI_STATIC_DEFINE_INT(env, cls, MOUSE_PRESSED); JNI_STATIC_DEFINE_INT(env, cls, MOUSE_RELEASED); int event_type, x, y, modifiers; if (!CallJNIMethodI_V(env, cls, mouse_event, "getID", &event_type) || !CallJNIMethodI_V(env, cls, mouse_event, "getX", &x) || !CallJNIMethodI_V(env, cls, mouse_event, "getY", &y) || !CallJNIMethodI_V(env, cls, mouse_event, "getModifiersEx", &modifiers)) { return; } CefMouseEvent cef_event; cef_event.x = x; cef_event.y = y; cef_event.modifiers = GetCefModifiers(env, cls, modifiers); if (event_type == JNI_STATIC(MOUSE_PRESSED) || event_type == JNI_STATIC(MOUSE_RELEASED)) { int click_count, button; if (!CallJNIMethodI_V(env, cls, mouse_event, "getClickCount", &click_count) || !CallJNIMethodI_V(env, cls, mouse_event, "getButton", &button)) { return; } CefBrowserHost::MouseButtonType cef_mbt; if (button == JNI_STATIC(BUTTON1)) cef_mbt = MBT_LEFT; else if (button == JNI_STATIC(BUTTON2)) cef_mbt = MBT_MIDDLE; else if (button == JNI_STATIC(BUTTON3)) cef_mbt = MBT_RIGHT; else return; browser->GetHost()->SendMouseClickEvent( cef_event, cef_mbt, (event_type == JNI_STATIC(MOUSE_RELEASED)), click_count); } else if (event_type == JNI_STATIC(MOUSE_MOVED) || event_type == JNI_STATIC(MOUSE_DRAGGED) || event_type == JNI_STATIC(MOUSE_ENTERED) || event_type == JNI_STATIC(MOUSE_EXITED)) { browser->GetHost()->SendMouseMoveEvent( cef_event, (event_type == JNI_STATIC(MOUSE_EXITED))); } } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1SendMouseWheelEvent( JNIEnv* env, jobject obj, jobject mouse_wheel_event) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); ScopedJNIClass cls(env, env->GetObjectClass(mouse_wheel_event)); if (!cls) return; JNI_STATIC_DEFINE_INT(env, cls, WHEEL_UNIT_SCROLL); int scroll_type, delta, x, y, modifiers; if (!CallJNIMethodI_V(env, cls, mouse_wheel_event, "getScrollType", &scroll_type) || !CallJNIMethodI_V(env, cls, mouse_wheel_event, "getWheelRotation", &delta) || !CallJNIMethodI_V(env, cls, mouse_wheel_event, "getX", &x) || !CallJNIMethodI_V(env, cls, mouse_wheel_event, "getY", &y) || !CallJNIMethodI_V(env, cls, mouse_wheel_event, "getModifiersEx", &modifiers)) { return; } CefMouseEvent cef_event; cef_event.x = x; cef_event.y = y; cef_event.modifiers = GetCefModifiers(env, cls, modifiers); if (scroll_type == JNI_STATIC(WHEEL_UNIT_SCROLL)) { // Use the smarter version that considers platform settings. CallJNIMethodI_V(env, cls, mouse_wheel_event, "getUnitsToScroll", &delta); } double deltaX = 0, deltaY = 0; if (cef_event.modifiers & EVENTFLAG_SHIFT_DOWN) deltaX = delta; else #if defined(OS_WIN) deltaY = delta * (-1); #else deltaY = delta; #endif browser->GetHost()->SendMouseWheelEvent(cef_event, deltaX, deltaY); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1DragTargetDragEnter(JNIEnv* env, jobject obj, jobject jdragData, jobject pos, jint jmodifiers, jint allowedOps) { CefRefPtr<CefDragData> drag_data = GetCefFromJNIObject_sync<CefDragData>(env, jdragData, "CefDragData"); if (!drag_data.get()) return; ScopedJNIClass cls(env, "java/awt/event/MouseEvent"); if (!cls) return; CefMouseEvent cef_event; GetJNIPoint(env, pos, &cef_event.x, &cef_event.y); cef_event.modifiers = GetCefModifiers(env, cls, jmodifiers); CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->DragTargetDragEnter( drag_data, cef_event, (CefBrowserHost::DragOperationsMask)allowedOps); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1DragTargetDragOver(JNIEnv* env, jobject obj, jobject pos, jint jmodifiers, jint allowedOps) { ScopedJNIClass cls(env, "java/awt/event/MouseEvent"); if (!cls) return; CefMouseEvent cef_event; GetJNIPoint(env, pos, &cef_event.x, &cef_event.y); cef_event.modifiers = GetCefModifiers(env, cls, jmodifiers); CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->DragTargetDragOver( cef_event, (CefBrowserHost::DragOperationsMask)allowedOps); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1DragTargetDragLeave(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->DragTargetDragLeave(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1DragTargetDrop(JNIEnv* env, jobject obj, jobject pos, jint jmodifiers) { ScopedJNIClass cls(env, "java/awt/event/MouseEvent"); if (!cls) return; CefMouseEvent cef_event; GetJNIPoint(env, pos, &cef_event.x, &cef_event.y); cef_event.modifiers = GetCefModifiers(env, cls, jmodifiers); CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->DragTargetDrop(cef_event); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1DragSourceEndedAt(JNIEnv* env, jobject obj, jobject pos, jint operation) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); int x, y; GetJNIPoint(env, pos, &x, &y); browser->GetHost()->DragSourceEndedAt( x, y, (CefBrowserHost::DragOperationsMask)operation); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1DragSourceSystemDragEnded(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->DragSourceSystemDragEnded(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1UpdateUI(JNIEnv* env, jobject obj, jobject jcontentRect, jobject jbrowserRect) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); CefWindowHandle windowHandle = browser->GetHost()->GetWindowHandle(); if (!windowHandle) // just for insurance return; CefRect contentRect = GetJNIRect(env, jcontentRect); #if defined(OS_MAC) CefRect browserRect = GetJNIRect(env, jbrowserRect); util_mac::UpdateView(windowHandle, contentRect, browserRect); #else // TODO: check that browser extists if (CefCurrentlyOn(TID_UI)) { util::SetWindowBounds(windowHandle, contentRect); } else { CefPostTask(TID_UI, base::BindOnce(util::SetWindowBounds, windowHandle, contentRect)); } #endif } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1SetParent(JNIEnv* env, jobject obj, jlong windowHandle, jobject canvas) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); base::OnceClosure callback = base::BindOnce(&OnAfterParentChanged, browser); #if defined(OS_MAC) util::SetParent(browser->GetHost()->GetWindowHandle(), windowHandle, std::move(callback)); #else CefWindowHandle browserHandle = browser->GetHost()->GetWindowHandle(); CefWindowHandle parentHandle = canvas ? util::GetWindowHandle(env, canvas) : kNullWindowHandle; if (CefCurrentlyOn(TID_UI)) { util::SetParent(browserHandle, parentHandle, std::move(callback)); } else { #if defined(OS_LINUX) CefPostTaskAndWait(TID_UI, base::BindOnce(util::SetParent, browserHandle, parentHandle, std::move(callback)), 1000); #else CefPostTask(TID_UI, base::BindOnce(util::SetParent, browserHandle, parentHandle, std::move(callback))); #endif } #endif } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1NotifyMoveOrResizeStarted(JNIEnv* env, jobject obj) { #if (defined(OS_WIN) || defined(OS_LINUX)) CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); if (!browser->GetHost()->IsWindowRenderingDisabled()) { browser->GetHost()->NotifyMoveOrResizeStarted(); } #endif } void Java_org_cef_browser_CefBrowser_1N_N_1NotifyScreenInfoChanged(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->NotifyScreenInfoChanged(); } namespace { bool GetJNIRange(JNIEnv* env, jobject obj, CefRange& range) { ScopedJNIClass cls(env, "org/cef/misc/CefRange"); if (!cls) { LOG(ERROR) << "Failed to find org.cef.misc.CefRange"; return false; } int from, to; if (!GetJNIFieldInt(env, cls, obj, "from", &from)) { LOG(ERROR) << "Failed to get org.cef.misc.CefRange#from"; return false; } if (!GetJNIFieldInt(env, cls, obj, "to", &to)) { LOG(ERROR) << "Failed to get org.cef.misc.CefRange#to"; return false; } if (from == -1 && to == -1) { range = CefRange::InvalidRange(); } else { range.Set(from, to); } return true; } bool GetJNIColor(JNIEnv *env, jobject jColor, cef_color_t& color) { ScopedJNIClass cls(env, env->GetObjectClass(jColor)); if (!cls) { LOG(ERROR) << "Failed to find java.awt.Color"; return false; } int a, r, g, b; if (!CallJNIMethodI_V(env, cls, jColor, "getAlpha", &a)) { LOG(ERROR) << "Failed to call java.awt.Color#getAlpa"; return false; } if (!CallJNIMethodI_V(env, cls, jColor, "getRed", &r)) { LOG(ERROR) << "Failed to call java.awt.Color#getRed"; return false; } if (!CallJNIMethodI_V(env, cls, jColor, "getGreen", &g)) { LOG(ERROR) << "Failed to call java.awt.Color#getGreen"; return false; } if (!CallJNIMethodI_V(env, cls, jColor, "getBlue", &b)) { LOG(ERROR) << "Failed to call java.awt.Color#getBlue"; return false; } color = CefColorSetARGB(a, r, g, b); return true; } bool GetJNIUnderlineStyle(JNIEnv *env, jobject jStyle, cef_composition_underline_style_t& style) { if (IsJNIEnumValue(env, jStyle, "org/cef/input/CefCompositionUnderline$Style", "SOLID")) { style = CEF_CUS_SOLID; } else if (IsJNIEnumValue(env, jStyle, "org/cef/input/CefCompositionUnderline$Style", "DOT")) { style = CEF_CUS_DOT; } else if (IsJNIEnumValue(env, jStyle, "org/cef/input/CefCompositionUnderline$Style", "DASH")) { style = CEF_CUS_DASH; } else if (IsJNIEnumValue(env, jStyle, "org/cef/input/CefCompositionUnderline$Style", "NONE")) { style = CEF_CUS_NONE; } else { return false; } return true; } bool GetJNIUnderline(JNIEnv *env, jobject jUnderline, CefCompositionUnderline& underline) { ScopedJNIClass cls(env, env->GetObjectClass(jUnderline)); if (!cls) { LOG(ERROR) << "Failed to find org.cef.input.CefCompositionUnderline"; return false; } ScopedJNIObjectResult jRange(env); if (!CallJNIMethodObject_V(env, cls, jUnderline, "getRange", "()Lorg/cef/misc/CefRange;", &jRange)) { LOG(ERROR) << "Failed to call CefCompositionUnderline#getRange();"; return false; } ScopedJNIObjectResult jColor(env); if (!CallJNIMethodObject_V(env, cls, jUnderline, "getColor", "()Ljava/awt/Color;", &jColor)) { LOG(ERROR) << "Failed to call CefCompositionUnderline#getColor();"; return false; } ScopedJNIObjectResult jBackgroundColor(env); if (!CallJNIMethodObject_V(env, cls, jUnderline, "getBackgroundColor", "()Ljava/awt/Color;", &jBackgroundColor)) { LOG(ERROR) << "Failed to call CefCompositionUnderline#getBackgroundColor();"; return false; } int thick; if (!CallJNIMethodI_V(env, cls, jUnderline, "getThick", &thick)) { LOG(ERROR) << "Failed to call CefCompositionUnderline#getThick();"; return false; } ScopedJNIObjectResult jStyle(env); if (!CallJNIMethodObject_V(env, cls, jUnderline, "getStyle", "()Lorg/cef/input/CefCompositionUnderline$Style;", &jStyle)) { LOG(ERROR) << "Failed to call CefCompositionUnderline#getStyle();"; return false; } CefRange range; if (!GetJNIRange(env, jRange, range)) { LOG(ERROR) << "Failed to convert org.cef.misc.CefRange"; return false; } underline.range = range; if (!GetJNIColor(env, jColor, underline.color)) { LOG(ERROR) << "Failed to convert CefCompositionUnderline#getColor()"; return false; } if (!GetJNIColor(env, jBackgroundColor, underline.background_color)) { LOG(ERROR) << "Failed to convert CefCompositionUnderline#getBackgroundColor()"; return false; } underline.thick = thick; if (!GetJNIUnderlineStyle(env, jStyle, underline.style)) { LOG(ERROR) << "Failed to convert CefCompositionUnderline#getStyle()"; return false; } return true; } bool GetJNIUnderlinesList(JNIEnv* env, jobject jList, std::vector<CefCompositionUnderline>& list) { std::vector<ScopedJNIObjectResult> jItems; if (!GetJNIListItems(env, jList, &jItems)) { LOG(ERROR) << "Failed to retrieve CefCompositionUnderline list"; return false; } std::vector<CefCompositionUnderline> result; for (const auto& jItem: jItems) { result.emplace_back(); if (!GetJNIUnderline(env, jItem, result.back())) { LOG(ERROR) << "Failed to convert CefCompositionUnderline list"; return false; } } list = std::move(result); return true; } } // namespace void Java_org_cef_browser_CefBrowser_1N_N_1ImeSetComposition( JNIEnv* env, jobject obj, jstring jText, jobject jUnderlines, jobject jReplacementRange, jobject jSelectionRange) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); CefString text = GetJNIString(env, jText); std::vector<CefCompositionUnderline> underlines; GetJNIUnderlinesList(env, jUnderlines, underlines); CefRange replacement_range{}; GetJNIRange(env, jReplacementRange, replacement_range); CefRange selection_range{}; GetJNIRange(env, jSelectionRange, selection_range); browser->GetHost()->ImeSetComposition(text, underlines, replacement_range, selection_range); } void Java_org_cef_browser_CefBrowser_1N_N_1ImeCommitText( JNIEnv* env, jobject obj, jstring jText, jobject jReplacementRange, jint jRelativePos) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); CefString text = GetJNIString(env, jText); CefRange replacement_range; GetJNIRange(env, jReplacementRange, replacement_range); browser->GetHost()->ImeCommitText(text, replacement_range, jRelativePos); } void Java_org_cef_browser_CefBrowser_1N_N_1ImeFinishComposingText( JNIEnv* env, jobject obj, jboolean jKeepSelection) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->ImeFinishComposingText(jKeepSelection); } void Java_org_cef_browser_CefBrowser_1N_N_1ImeCancelComposing(JNIEnv* env, jobject obj) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, obj); browser->GetHost()->ImeCancelComposition(); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1SetWindowlessFrameRate(JNIEnv* env, jobject jbrowser, jint frameRate) { CefRefPtr<CefBrowser> browser = JNI_GET_BROWSER_OR_RETURN(env, jbrowser); CefRefPtr<CefBrowserHost> host = browser->GetHost(); host->SetWindowlessFrameRate(frameRate); } void getWindowlessFrameRate(CefRefPtr<CefBrowserHost> host, CefRefPtr<IntCallback> callback) { callback->onComplete((jint)host->GetWindowlessFrameRate()); } JNIEXPORT void JNICALL Java_org_cef_browser_CefBrowser_1N_N_1GetWindowlessFrameRate( JNIEnv* env, jobject jbrowser, jobject jintCallback) { CefRefPtr<IntCallback> callback = new IntCallback(env, jintCallback); CefRefPtr<CefBrowser> browser = GetJNIBrowser(env, jbrowser); if (!browser.get()) { callback->onComplete(0); return; } CefRefPtr<CefBrowserHost> host = browser->GetHost(); if (CefCurrentlyOn(TID_UI)) { getWindowlessFrameRate(host, callback); } else { CefPostTask(TID_UI, base::BindOnce(getWindowlessFrameRate, host, callback)); } }