#ifdef WITH_WEBVIEW #include "webview.h" #include #include WebViewManager& WebViewManager::instance() { static WebViewManager inst; return inst; } WebViewManager::~WebViewManager() { for (auto& [id, wv] : webviews) { if (wv->platformHandle) { platformDestroy(wv.get()); } } webviews.clear(); } int WebViewManager::create(v8::Isolate* isolate, v8::Local context, int parentWindow, int x, int y, int width, int height, bool transparent, const std::string& title) { auto wv = std::make_unique(); wv->id = nextId++; wv->parentWindow = parentWindow; wv->x = x; wv->y = y; wv->width = width; wv->height = height; wv->autoResize = (parentWindow >= 0 && (width == -1 || height == -1)); wv->transparent = transparent; wv->clickThrough = false; wv->visible = false; wv->title = title; wv->isolate = isolate; wv->context.Reset(isolate, context); if (wv->autoResize && parentWindow >= 0) { if (wv->width == -1) wv->width = kinc_window_width(parentWindow); if (wv->height == -1) wv->height = kinc_window_height(parentWindow); } int id = wv->id; int result = platformCreate(wv.get()); if (result < 0) { kinc_log(KINC_LOG_LEVEL_ERROR, "[WebView] Failed to create WebView (platform returned %d)", result); return -1; } webviews[id] = std::move(wv); kinc_log(KINC_LOG_LEVEL_INFO, "[WebView] Created WebView id=%d parent=%d %dx%d", id, parentWindow, width, height); if (activeDomId < 0) { setActiveDOM(id, isolate); } return id; } void WebViewManager::destroy(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; if (it->second->platformHandle) { platformDestroy(it->second.get()); } webviews.erase(it); kinc_log(KINC_LOG_LEVEL_INFO, "[WebView] Destroyed WebView id=%d", id); } bool WebViewManager::isValid(int id) { return webviews.find(id) != webviews.end(); } int WebViewManager::count() { return (int)webviews.size(); } void WebViewManager::loadHTML(int id, const std::string& html) { auto it = webviews.find(id); if (it == webviews.end()) return; platformLoadHTML(it->second.get(), html); } void WebViewManager::loadURL(int id, const std::string& url) { auto it = webviews.find(id); if (it == webviews.end()) return; platformLoadURL(it->second.get(), url); } void WebViewManager::evalJS(int id, const std::string& js) { auto it = webviews.find(id); if (it == webviews.end()) return; platformEvalJS(it->second.get(), js); } void WebViewManager::evalJSAsync(int id, v8::Isolate* isolate, v8::Local callback, const std::string& js) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->onEvalResult.Reset(isolate, callback); platformEvalJSAsync(it->second.get(), js); } void WebViewManager::setActiveDOM(int id, v8::Isolate* isolate) { if (id >= 0 && webviews.find(id) == webviews.end()) return; activeDomId = id; if (id < 0) return; auto it = webviews.find(id); if (it == webviews.end()) return; auto* wv = it->second.get(); v8::HandleScope handleScope(isolate); v8::Local ctx = wv->context.Get(isolate); v8::Context::Scope ctxScope(ctx); // This is the proxy interception to support the web apis. TODO replace std::string proxyJs = std::string("(function(){var _id=") + std::to_string(id) + ";" R"JS( var _r=0; function _eval(j){runt.webviewEvalJS(_id,j);} function _evalAsync(j,cb){runt.webviewEvalJSAsync(_id,j,cb);} function _arg(x){ if(x!==null&&(typeof x==='object'||typeof x==='function')&&x.__jsExpr)return x.__jsExpr; return JSON.stringify(x); } function _proxy(expr){ var fn=function(){}; var _loaded=false,_data=null,_fired=false; function _fire(){ if(_fired)return;_fired=true; _evalAsync(expr,function(r){_loaded=true;try{_data=JSON.parse(r);}catch(e){_data=r;}}); } return new Proxy(fn,{ get:function(t,p){ if(p==='__jsExpr')return expr; if(p==='loaded'){_fire();return _loaded;} if(p==='data'){_fire();return _data;} if(typeof p==='symbol'||p==='then')return undefined; return _proxy(expr+"."+p); }, apply:function(t,thisArg,args){ var r='__c'+(++_r); _eval("window['"+r+"']="+expr+"("+args.map(_arg).join(',')+")"); return _proxy("window['"+r+"']"); }, set:function(t,p,v){_eval(expr+"."+p+"="+_arg(v));return true;} }); } return [_proxy("window"),_proxy("window.document")]; })(); )JS"; v8::Local src = v8::String::NewFromUtf8(isolate, proxyJs.c_str(), v8::NewStringType::kNormal, (int)proxyJs.length()).ToLocalChecked(); v8::TryCatch tryCatch(isolate); v8::MaybeLocal compileResult = v8::Script::Compile(ctx, src); if (compileResult.IsEmpty()) { v8::Local msg = tryCatch.Message(); if (!msg.IsEmpty()) { v8::String::Utf8Value errorStr(isolate, msg->Get()); kinc_log(KINC_LOG_LEVEL_ERROR, "WebView proxy compile error: %s", *errorStr); } return; } v8::Local script = compileResult.ToLocalChecked(); v8::MaybeLocal result = script->Run(ctx); if (tryCatch.HasCaught()) { v8::Local msg = tryCatch.Message(); if (!msg.IsEmpty()) { v8::String::Utf8Value errorStr(isolate, msg->Get()); kinc_log(KINC_LOG_LEVEL_ERROR, "Webview proxy run error: %s", *errorStr); } else { kinc_log(KINC_LOG_LEVEL_ERROR, "Webview proxy: no message"); } return; } if (!result.IsEmpty()) { v8::Local val = result.ToLocalChecked(); if (val->IsArray()) { v8::Local arr = val.As(); v8::Local globalObj = ctx->Global(); globalObj->Set(ctx, v8::String::NewFromUtf8(isolate, "window").ToLocalChecked(), arr->Get(ctx, 0).ToLocalChecked()).Check(); globalObj->Set(ctx, v8::String::NewFromUtf8(isolate, "document").ToLocalChecked(), arr->Get(ctx, 1).ToLocalChecked()).Check(); kinc_log(KINC_LOG_LEVEL_INFO, "DOM proxy injected successfully for webview id=%d", id); } else { kinc_log(KINC_LOG_LEVEL_ERROR, "Proxy returned non array type"); } } } int WebViewManager::getActiveDOM() { return activeDomId; } void WebViewManager::show(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->visible = true; platformShow(it->second.get()); } void WebViewManager::hide(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->visible = false; platformHide(it->second.get()); } void WebViewManager::resize(int id, int width, int height) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->width = width; it->second->height = height; it->second->autoResize = false; platformResize(it->second.get(), width, height); } void WebViewManager::move(int id, int x, int y) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->x = x; it->second->y = y; platformMove(it->second.get(), x, y); } void WebViewManager::setBounds(int id, int x, int y, int width, int height) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->x = x; it->second->y = y; it->second->width = width; it->second->height = height; it->second->autoResize = false; platformResize(it->second.get(), width, height); platformMove(it->second.get(), x, y); } int WebViewManager::getX(int id) { auto it = webviews.find(id); if (it == webviews.end()) return 0; return it->second->x; } int WebViewManager::getY(int id) { auto it = webviews.find(id); if (it == webviews.end()) return 0; return it->second->y; } int WebViewManager::getWidth(int id) { auto it = webviews.find(id); if (it == webviews.end()) return 0; return it->second->width; } int WebViewManager::getHeight(int id) { auto it = webviews.find(id); if (it == webviews.end()) return 0; return it->second->height; } void WebViewManager::setTransparent(int id, bool transparent) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->transparent = transparent; platformSetTransparent(it->second.get(), transparent); } void WebViewManager::setClickThrough(int id, bool enabled) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->clickThrough = enabled; platformSetClickThrough(it->second.get(), enabled); } void WebViewManager::setTitle(int id, const std::string& title) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->title = title; platformSetTitle(it->second.get(), title); } void WebViewManager::send(int id, const std::string& message) { auto it = webviews.find(id); if (it == webviews.end()) return; platformSend(it->second.get(), message); } void WebViewManager::goBack(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; platformGoBack(it->second.get()); } void WebViewManager::goForward(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; platformGoForward(it->second.get()); } void WebViewManager::reload(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; platformReload(it->second.get()); } bool WebViewManager::canGoBack(int id) { auto it = webviews.find(id); if (it == webviews.end()) return false; return platformCanGoBack(it->second.get()); } bool WebViewManager::canGoForward(int id) { auto it = webviews.find(id); if (it == webviews.end()) return false; return platformCanGoForward(it->second.get()); } std::string WebViewManager::getURL(int id) { auto it = webviews.find(id); if (it == webviews.end()) return ""; return platformGetURL(it->second.get()); } std::string WebViewManager::getPageTitle(int id) { auto it = webviews.find(id); if (it == webviews.end()) return ""; return platformGetTitle(it->second.get()); } void WebViewManager::minimize(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; platformMinimize(it->second.get()); } void WebViewManager::maximize(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; platformMaximize(it->second.get()); } void WebViewManager::restore(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; platformRestore(it->second.get()); } void WebViewManager::setFullscreen(int id, bool fullscreen) { auto it = webviews.find(id); if (it == webviews.end()) return; platformSetFullscreen(it->second.get(), fullscreen); } bool WebViewManager::isFullscreen(int id) { auto it = webviews.find(id); if (it == webviews.end()) return false; return platformIsFullscreen(it->second.get()); } void WebViewManager::enableDevTools(int id, bool enabled) { auto it = webviews.find(id); if (it == webviews.end()) return; platformEnableDevTools(it->second.get(), enabled); } void WebViewManager::setContextMenuEnabled(int id, bool enabled) { auto it = webviews.find(id); if (it == webviews.end()) return; platformSetContextMenuEnabled(it->second.get(), enabled); } void WebViewManager::setOnMessage(int id, v8::Isolate* isolate, v8::Local cb) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->onMessage.Reset(isolate, cb); } void WebViewManager::setOnLoad(int id, v8::Isolate* isolate, v8::Local cb) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->onLoad.Reset(isolate, cb); } void WebViewManager::setOnError(int id, v8::Isolate* isolate, v8::Local cb) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->onError.Reset(isolate, cb); } void WebViewManager::setOnClose(int id, v8::Isolate* isolate, v8::Local cb) { auto it = webviews.find(id); if (it == webviews.end()) return; it->second->onClose.Reset(isolate, cb); } void WebViewManager::dispatchMessage(int id, const std::string& message) { auto it = webviews.find(id); if (it == webviews.end()) return; auto* wv = it->second.get(); if (wv->onMessage.IsEmpty()) return; v8::Isolate* isolate = wv->isolate; v8::Locker locker(isolate); v8::Isolate::Scope isolateScope(isolate); v8::HandleScope handleScope(isolate); v8::Local ctx = wv->context.Get(isolate); v8::Context::Scope ctxScope(ctx); v8::Local cb = wv->onMessage.Get(isolate); v8::Local arg = v8::String::NewFromUtf8(isolate, message.c_str(), v8::NewStringType::kNormal, (int)message.length()).ToLocalChecked(); cb->Call(ctx, v8::Undefined(isolate), 1, &arg).IsEmpty(); } void WebViewManager::dispatchLoad(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; auto* wv = it->second.get(); if (wv->onLoad.IsEmpty()) return; v8::Isolate* isolate = wv->isolate; v8::Locker locker(isolate); v8::Isolate::Scope isolateScope(isolate); v8::HandleScope handleScope(isolate); v8::Local ctx = wv->context.Get(isolate); v8::Context::Scope ctxScope(ctx); v8::Local cb = wv->onLoad.Get(isolate); v8::Local arg = v8::Undefined(isolate); cb->Call(ctx, v8::Undefined(isolate), 1, &arg).IsEmpty(); } void WebViewManager::dispatchError(int id, const std::string& error) { auto it = webviews.find(id); if (it == webviews.end()) return; auto* wv = it->second.get(); if (wv->onError.IsEmpty()) return; v8::Isolate* isolate = wv->isolate; v8::Locker locker(isolate); v8::Isolate::Scope isolateScope(isolate); v8::HandleScope handleScope(isolate); v8::Local ctx = wv->context.Get(isolate); v8::Context::Scope ctxScope(ctx); v8::Local cb = wv->onError.Get(isolate); v8::Local arg = v8::String::NewFromUtf8(isolate, error.c_str(), v8::NewStringType::kNormal, (int)error.length()).ToLocalChecked(); cb->Call(ctx, v8::Undefined(isolate), 1, &arg).IsEmpty(); } void WebViewManager::dispatchClose(int id) { auto it = webviews.find(id); if (it == webviews.end()) return; auto* wv = it->second.get(); if (wv->onClose.IsEmpty()) return; v8::Isolate* isolate = wv->isolate; v8::Locker locker(isolate); v8::Isolate::Scope isolateScope(isolate); v8::HandleScope handleScope(isolate); v8::Local ctx = wv->context.Get(isolate); v8::Context::Scope ctxScope(ctx); v8::Local cb = wv->onClose.Get(isolate); v8::Local arg = v8::Undefined(isolate); cb->Call(ctx, v8::Undefined(isolate), 1, &arg).IsEmpty(); } void WebViewManager::dispatchEvalResult(int id, const std::string& result) { auto it = webviews.find(id); if (it == webviews.end()) return; auto* wv = it->second.get(); if (wv->onEvalResult.IsEmpty()) return; v8::Isolate* isolate = wv->isolate; v8::Locker locker(isolate); v8::Isolate::Scope isolateScope(isolate); v8::HandleScope handleScope(isolate); v8::Local ctx = wv->context.Get(isolate); v8::Context::Scope ctxScope(ctx); v8::Local cb = wv->onEvalResult.Get(isolate); v8::Local arg = v8::String::NewFromUtf8(isolate, result.c_str(), v8::NewStringType::kNormal, (int)result.length()).ToLocalChecked(); cb->Call(ctx, v8::Undefined(isolate), 1, &arg).IsEmpty(); } void WebViewManager::tick() { platformTick(); } void WebViewManager::onWindowResize(int windowId, int width, int height) { for (auto& [id, wv] : webviews) { if (wv->parentWindow == windowId && wv->autoResize) { wv->width = width; wv->height = height; platformResize(wv.get(), width, height); } } } static int getIntOption(v8::Isolate* isolate, v8::Local ctx, v8::Local opts, const char* key, int defaultVal) { v8::Local val; v8::Local keyStr = v8::String::NewFromUtf8(isolate, key).ToLocalChecked(); if (opts->Get(ctx, keyStr).ToLocal(&val) && val->IsNumber()) { return val->Int32Value(ctx).FromJust(); } return defaultVal; } static bool getBoolOption(v8::Isolate* isolate, v8::Local ctx, v8::Local opts, const char* key, bool defaultVal) { v8::Local val; v8::Local keyStr = v8::String::NewFromUtf8(isolate, key).ToLocalChecked(); if (opts->Get(ctx, keyStr).ToLocal(&val) && val->IsBoolean()) { return val->BooleanValue(isolate); } return defaultVal; } static std::string getStringOption(v8::Isolate* isolate, v8::Local ctx, v8::Local opts, const char* key, const char* defaultVal) { v8::Local val; v8::Local keyStr = v8::String::NewFromUtf8(isolate, key).ToLocalChecked(); if (opts->Get(ctx, keyStr).ToLocal(&val) && val->IsString()) { v8::String::Utf8Value str(isolate, val); return std::string(*str); } return std::string(defaultVal); } void runt_webview_create(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); v8::Local ctx = isolate->GetCurrentContext(); if (args.Length() < 1 || !args[0]->IsObject()) { isolate->ThrowException(v8::Exception::Error( v8::String::NewFromUtf8(isolate, "Options object required").ToLocalChecked())); return; } v8::Local opts = args[0]->ToObject(ctx).ToLocalChecked(); int parentWindow = getIntOption(isolate, ctx, opts, "parentWindow", -1); int x = getIntOption(isolate, ctx, opts, "x", 0); int y = getIntOption(isolate, ctx, opts, "y", 0); int width = getIntOption(isolate, ctx, opts, "width", 800); int height = getIntOption(isolate, ctx, opts, "height", 600); bool transparent = getBoolOption(isolate, ctx, opts, "transparent", true); std::string title = getStringOption(isolate, ctx, opts, "title", "WebView"); int id = WebViewManager::instance().create(isolate, ctx, parentWindow, x, y, width, height, transparent, title); args.GetReturnValue().Set(v8::Number::New(isolate, id)); if (id < 0) return; v8::Local val; v8::Local htmlKey = v8::String::NewFromUtf8(isolate, "html").ToLocalChecked(); if (opts->Get(ctx, htmlKey).ToLocal(&val) && val->IsString()) { v8::String::Utf8Value str(isolate, val); WebViewManager::instance().loadHTML(id, *str); } v8::Local urlKey = v8::String::NewFromUtf8(isolate, "url").ToLocalChecked(); if (opts->Get(ctx, urlKey).ToLocal(&val) && val->IsString()) { v8::String::Utf8Value str(isolate, val); WebViewManager::instance().loadURL(id, *str); } } void runt_webview_load_html(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsString()) { isolate->ThrowException(v8::Exception::Error( v8::String::NewFromUtf8(isolate, "ID and HTML string required").ToLocalChecked())); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); v8::String::Utf8Value str(isolate, args[1]); WebViewManager::instance().loadHTML(id, *str); } void runt_webview_load_url(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsString()) { isolate->ThrowException(v8::Exception::Error( v8::String::NewFromUtf8(isolate, "ID and URL string required").ToLocalChecked())); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); v8::String::Utf8Value str(isolate, args[1]); WebViewManager::instance().loadURL(id, *str); } void runt_webview_eval_js(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsString()) { isolate->ThrowException(v8::Exception::Error( v8::String::NewFromUtf8(isolate, "ID and JS string required").ToLocalChecked())); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); v8::String::Utf8Value str(isolate, args[1]); WebViewManager::instance().evalJS(id, *str); } void runt_webview_show(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().show(id); } void runt_webview_hide(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().hide(id); } void runt_webview_destroy(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().destroy(id); } void runt_webview_resize(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 3 || !args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); int w = args[1]->Int32Value(isolate->GetCurrentContext()).FromJust(); int h = args[2]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().resize(id, w, h); } void runt_webview_move(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 3 || !args[0]->IsNumber() || !args[1]->IsNumber() || !args[2]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); int x = args[1]->Int32Value(isolate->GetCurrentContext()).FromJust(); int y = args[2]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().move(id, x, y); } void runt_webview_set_bounds(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 5) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); int x = args[1]->Int32Value(isolate->GetCurrentContext()).FromJust(); int y = args[2]->Int32Value(isolate->GetCurrentContext()).FromJust(); int w = args[3]->Int32Value(isolate->GetCurrentContext()).FromJust(); int h = args[4]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().setBounds(id, x, y, w, h); } void runt_webview_get_x(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); args.GetReturnValue().Set(v8::Int32::New(isolate, WebViewManager::instance().getX(id))); } void runt_webview_get_y(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); args.GetReturnValue().Set(v8::Int32::New(isolate, WebViewManager::instance().getY(id))); } void runt_webview_get_width(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); args.GetReturnValue().Set(v8::Int32::New(isolate, WebViewManager::instance().getWidth(id))); } void runt_webview_get_height(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); args.GetReturnValue().Set(v8::Int32::New(isolate, WebViewManager::instance().getHeight(id))); } void runt_webview_set_transparent(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsBoolean()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); bool val = args[1]->BooleanValue(isolate); WebViewManager::instance().setTransparent(id, val); } void runt_webview_set_click_through(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsBoolean()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); bool val = args[1]->BooleanValue(isolate); WebViewManager::instance().setClickThrough(id, val); } void runt_webview_set_title(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsString()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); v8::String::Utf8Value str(isolate, args[1]); WebViewManager::instance().setTitle(id, *str); } void runt_webview_send(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber()) { isolate->ThrowException(v8::Exception::Error( v8::String::NewFromUtf8(isolate, "ID and message required").ToLocalChecked())); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); std::string message; if (args[1]->IsString()) { v8::String::Utf8Value str(isolate, args[1]); message = *str; } else { v8::Local ctx = isolate->GetCurrentContext(); v8::Local json = v8::JSON::Stringify(ctx, args[1]).ToLocalChecked(); v8::String::Utf8Value str(isolate, json); message = *str; } WebViewManager::instance().send(id, message); } void runt_webview_set_on_message(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsFunction()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().setOnMessage(id, isolate, v8::Local::Cast(args[1])); } void runt_webview_set_on_load(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsFunction()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().setOnLoad(id, isolate, v8::Local::Cast(args[1])); } void runt_webview_set_on_error(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsFunction()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().setOnError(id, isolate, v8::Local::Cast(args[1])); } void runt_webview_set_on_close(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsFunction()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().setOnClose(id, isolate, v8::Local::Cast(args[1])); } void runt_webview_count(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); args.GetReturnValue().Set(v8::Int32::New(isolate, WebViewManager::instance().count())); } void runt_webview_is_valid(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) { args.GetReturnValue().Set(v8::Boolean::New(isolate, false)); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); args.GetReturnValue().Set(v8::Boolean::New(isolate, WebViewManager::instance().isValid(id))); } void runt_webview_set_active_dom(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().setActiveDOM(id, isolate); } void runt_webview_get_active_dom(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); args.GetReturnValue().Set(v8::Int32::New(isolate, WebViewManager::instance().getActiveDOM())); } void runt_webview_eval_js_async(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 3 || !args[0]->IsNumber() || !args[1]->IsString() || !args[2]->IsFunction()) { isolate->ThrowException(v8::Exception::Error( v8::String::NewFromUtf8(isolate, "ID, JS string, and callback required").ToLocalChecked())); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); v8::String::Utf8Value str(isolate, args[1]); v8::Local cb = v8::Local::Cast(args[2]); WebViewManager::instance().evalJSAsync(id, isolate, cb, *str); } void runt_webview_go_back(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().goBack(id); } void runt_webview_go_forward(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().goForward(id); } void runt_webview_reload(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().reload(id); } void runt_webview_can_go_back(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) { args.GetReturnValue().Set(v8::Boolean::New(isolate, false)); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); args.GetReturnValue().Set(v8::Boolean::New(isolate, WebViewManager::instance().canGoBack(id))); } void runt_webview_can_go_forward(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) { args.GetReturnValue().Set(v8::Boolean::New(isolate, false)); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); args.GetReturnValue().Set(v8::Boolean::New(isolate, WebViewManager::instance().canGoForward(id))); } void runt_webview_get_url(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) { args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "").ToLocalChecked()); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); std::string url = WebViewManager::instance().getURL(id); args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, url.c_str(), v8::NewStringType::kNormal, (int)url.length()).ToLocalChecked()); } void runt_webview_get_page_title(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) { args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, "").ToLocalChecked()); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); std::string title = WebViewManager::instance().getPageTitle(id); args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, title.c_str(), v8::NewStringType::kNormal, (int)title.length()).ToLocalChecked()); } void runt_webview_minimize(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().minimize(id); } void runt_webview_maximize(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().maximize(id); } void runt_webview_restore(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); WebViewManager::instance().restore(id); } void runt_webview_set_fullscreen(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsBoolean()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); bool fs = args[1]->BooleanValue(isolate); WebViewManager::instance().setFullscreen(id, fs); } void runt_webview_is_fullscreen(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 1 || !args[0]->IsNumber()) { args.GetReturnValue().Set(v8::Boolean::New(isolate, false)); return; } int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); args.GetReturnValue().Set(v8::Boolean::New(isolate, WebViewManager::instance().isFullscreen(id))); } void runt_webview_enable_devtools(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsBoolean()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); bool enabled = args[1]->BooleanValue(isolate); WebViewManager::instance().enableDevTools(id, enabled); } void runt_webview_set_context_menu(const v8::FunctionCallbackInfo& args) { v8::Isolate* isolate = args.GetIsolate(); v8::HandleScope scope(isolate); if (args.Length() < 2 || !args[0]->IsNumber() || !args[1]->IsBoolean()) return; int id = args[0]->Int32Value(isolate->GetCurrentContext()).FromJust(); bool enabled = args[1]->BooleanValue(isolate); WebViewManager::instance().setContextMenuEnabled(id, enabled); } #endif