ChromiumBrowser: executution of native code from javascript and vice versa

git-svn-id: svn://ultimatepp.org/upp/trunk@8489 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
zbych 2015-05-30 17:04:23 +00:00
parent bbf1d2ac5f
commit 15044fed20
11 changed files with 140 additions and 36 deletions

View file

@ -30,11 +30,11 @@ public:
ChromiumBrowser();
~ChromiumBrowser();
Callback1<String> WhenUrlChange;
Callback1<String> WhenMessage;
Callback WhenTakeFocus;
Callback1<bool> WhenKeyboard;
Callback3<Upp::String, int, Upp::String> WhenConsoleMessage;
Callback1<String> WhenUrlChange;
Callback2<String, WithDeepCopy<Vector<Value> > > WhenMessage;
Callback WhenTakeFocus;
Callback1<bool> WhenKeyboard;
Callback3<Upp::String, int, Upp::String> WhenConsoleMessage;
static void ChildProcess();
static bool IsChildProcess();

View file

@ -1,10 +1,13 @@
#include "ClientApp.h"
static const char * const func_names[]={
"JSExample1"
};
ClientApp::ClientApp()
{
//Add our own JS functions to the list
functions.Add("JSExample1", Upp::callback(this, &ClientApp::JSExample1));
}
@ -20,9 +23,9 @@ void ClientApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFra
{
//Register our JS functions
CefRefPtr<CefV8Value> object = context->GetGlobal();
for(int f = 0; f < functions.GetCount(); f++){
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction(~functions.GetKey(f), this);
object->SetValue(~functions.GetKey(f), func, V8_PROPERTY_ATTRIBUTE_NONE);
for(int f = 0; f < __countof(func_names); f++){
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction(func_names[f], this);
object->SetValue(func_names[f], func, V8_PROPERTY_ATTRIBUTE_NONE);
}
}
@ -36,19 +39,26 @@ void ClientApp::OnFocusedNodeChanged(CefRefPtr<CefBrowser> browser, CefRefPtr<Ce
bool ClientApp::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception)
{
int f = functions.Find(name.ToString());
if (f >= 0){
functions[f].Execute(arguments, retval, exception);
return true;
}else{
RLOG(Upp::String("ERROR: Unknown native function: ") + name.ToString());
}
return false;
CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create(name);
CefRefPtr<CefListValue> par = message->GetArgumentList();
V8ValueListToCefListValue(arguments, par);
CefRefPtr<CefBrowser> browser = CefV8Context::GetCurrentContext()->GetBrowser();
if (browser) browser->SendProcessMessage(PID_BROWSER, message);
return true;
}
void ClientApp::JSExample1(const CefV8ValueList& args, CefRefPtr<CefV8Value>& retval, CefString& exc)
void ClientApp::V8ValueListToCefListValue(const CefV8ValueList& src, CefRefPtr<CefListValue> & dst)
{
retval = CefV8Value::CreateString("Function that returns some string");
for (unsigned i = 0; i < src.size(); i++)
{
if (!src[i]->IsValid()) { dst->SetString(dst->GetSize(),"Invalid V8Value"); continue;}
if (src[i]->IsUndefined() || src[i]->IsNull()) { dst->SetNull(dst->GetSize()); continue;}
if (src[i]->IsBool()) { dst->SetBool(dst->GetSize(), src[i]->GetBoolValue()); continue;}
if (src[i]->IsInt()) { dst->SetInt(dst->GetSize(), src[i]->GetIntValue()); continue;}
if (src[i]->IsDouble()) { dst->SetDouble(dst->GetSize(),src[i]->GetDoubleValue()); continue;}
if (src[i]->IsString()) { dst->SetString(dst->GetSize(),src[i]->GetStringValue()); continue;}
dst->SetString(dst->GetSize(), "Unimplemented V8Value conversion");
}
}

View file

@ -25,9 +25,7 @@ class ClientApp: public CefApp,
private:
CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() { return this; }
Upp::VectorMap<Upp::String, Upp::Callback3<const CefV8ValueList&, CefRefPtr<CefV8Value>&, CefString&> > functions;
void JSExample1(const CefV8ValueList&, CefRefPtr<CefV8Value>&, CefString&);
void V8ValueListToCefListValue(const CefV8ValueList& src, CefRefPtr<CefListValue> & dst);
public:
typedef ClientApp CLASSNAME;

View file

@ -66,11 +66,45 @@ void ClientHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
bool ClientHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser, CefProcessId source_process, CefRefPtr<CefProcessMessage> message)
{
if (message->GetName().ToString() == "show_keyboard"){
PostCallback(callback1(WhenKeyboard, true));
}else if (message->GetName().ToString() == "hide_keyboard"){
PostCallback(callback1(WhenKeyboard, false));
}else{
PostCallback(callback1(WhenMessage, message->GetName().ToString()));
CefRefPtr<CefListValue> args = message->GetArgumentList();
Upp::Vector<Upp::Value> par;
for (unsigned i = 0; i < args->GetSize(); i++){
CefValueType type = args->GetType(i);
switch(type){
case VTYPE_BOOL:
par.Add(args->GetBool(i));
break;
case VTYPE_DOUBLE:
par.Add(args->GetDouble(i));
break;
case VTYPE_INT:
par.Add(args->GetInt(i));
break;
case VTYPE_STRING:
par.Add(args->GetString(i).ToString().c_str());
break;
default:
par.Add("OnProcessMessageReceived: unsupported parameter type");
break;
}
}
PostCallback(callback2(WhenMessage, message->GetName().ToString(), par));
}
return true;
}
@ -87,8 +121,10 @@ void ClientHandler::OnBeforeContextMenu(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefContextMenuParams> params,
CefRefPtr<CefMenuModel> model)
{
#ifndef _DEBUG
//Empty context menu
model->Clear();
#endif
}

View file

@ -23,7 +23,7 @@ class ClientHandler : public CefClient, public CefLifeSpanHandler, public CefDis
public:
ClientHandler( Upp::Callback1<Upp::String> & wuc,
Upp::Callback1<Upp::String> & wm,
Upp::Callback2<Upp::String, Upp::WithDeepCopy<Upp::Vector<Upp::Value> > > & wm,
Upp::Callback & tf,
Upp::Callback1<bool> & wk,
Upp::Callback3<Upp::String, int, Upp::String> & wcm):
@ -33,7 +33,7 @@ public:
~ClientHandler() { }
Upp::Callback1<Upp::String> & WhenUrlChange;
Upp::Callback1<Upp::String> & WhenMessage;
Upp::Callback2<Upp::String, Upp::WithDeepCopy<Upp::Vector<Upp::Value> > > & WhenMessage;
Upp::Callback & WhenTakeFocus;
Upp::Callback1<bool> & WhenKeyboard;
Upp::Callback3<Upp::String, int, Upp::String> & WhenConsoleMessage;

View file

@ -14,11 +14,13 @@ class ChromiumBrowserExample : public WithChromiumBrowserExampleLayout<TopWindow
private:
void Close() { Upp::ShowKeyboard(false); TopWindow::Close(); }
void OnUrlChange(String url) { Url.SetData(url); Url.CancelSelection(); }
void OnTakeFocus() { Url.SetFocus(); }
void OnConsoleMessage(String url, int line, String msg) { RLOG(Format("Console message: url=%s, line=%d, msg=%s", url, line, msg)); }
void OnBrowse() { Browser.Browse(~Url); }
void Close() { Upp::ShowKeyboard(false); TopWindow::Close(); }
void OnUrlChange(String url) { Url.SetData(url); Url.CancelSelection(); }
void OnTakeFocus() { Url.SetFocus(); }
void OnConsoleMessage(String url, int line, String msg) { RLOG(Format("Console message: url=%s, line=%d, msg=%s", url, line, msg)); }
void OnBrowse() { Browser.Browse(~Url); }
void OnMessage(String name, WithDeepCopy<Vector<Value> > par);
void OnJSTests();
public:
typedef ChromiumBrowserExample CLASSNAME;

View file

@ -1,10 +1,11 @@
LAYOUT(ChromiumBrowserExampleLayout, 388, 260)
LAYOUT(ChromiumBrowserExampleLayout, 504, 260)
ITEM(Button, Back, Tip(t_("Go back")).LeftPosZ(4, 48).TopPosZ(4, 44))
ITEM(Button, Forward, Tip(t_("Go forward")).LeftPosZ(56, 48).TopPosZ(4, 44))
ITEM(Button, Refresh, Tip(t_("Refresh current page")).LeftPosZ(108, 48).TopPosZ(4, 44))
ITEM(EditString, Url, SetFont(StdFontZ(32)).HSizePosZ(160, 108).TopPosZ(4, 44))
ITEM(Button, Go, Tip(t_("Go")).RightPosZ(56, 48).TopPosZ(4, 44))
ITEM(Button, Stop, Tip(t_("Stop")).RightPosZ(4, 48).TopPosZ(4, 44))
ITEM(EditString, Url, SetFont(StdFontZ(32)).HSizePosZ(160, 160).TopPosZ(4, 44))
ITEM(Button, Go, Tip(t_("Go")).RightPosZ(108, 48).TopPosZ(4, 44))
ITEM(Button, JSTests, SetLabel(t_("JS Test")).Tip(t_("Stop")).RightPosZ(4, 48).TopPosZ(4, 44))
ITEM(ChromiumBrowser, Browser, StartPage("http://ultimatepp.org").HSizePosZ(0, 0).VSizePosZ(52, 0))
ITEM(Button, Stop, Tip(t_("Stop")).RightPosZ(56, 48).TopPosZ(4, 44))
END_LAYOUT

View file

@ -13,6 +13,8 @@ options(GCC) -std=c++11;
link(GCC) "-Wl,-rpath .";
file
html/test_page.html,
files.brc,
Utils readonly separator,
Utils.h,
Utils.cpp,

View file

@ -0,0 +1,2 @@
BINARY(test_page, "html/test_page.html")

View file

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {background-color: #EFEFEF}
canvas, label, button {
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
}
</style>
</head>
<body>
<p><label style="font-size:30px" id="some_label">Waiting for some action...</label></p>
<p><button style="font-size:30px" onclick="JSExample1('some string', true, 777);">Press me to execute native function from JS!</button></p>
<script>
function CallbackExample(r)
{
document.getElementById('some_label').innerHTML = 'Javascript function executed by native code: ' + r;
}
</script>
</body>
</html>

View file

@ -6,6 +6,7 @@ using namespace Upp;
#define IMAGEFILE <ChromiumBrowserExample/ChromiumBrowserExample.iml>
#include <Draw/iml.h>
#include "files.brc"
ChromiumBrowserExample::ChromiumBrowserExample()
{
@ -23,6 +24,7 @@ ChromiumBrowserExample::ChromiumBrowserExample()
Browser.WhenTakeFocus = THISBACK(OnTakeFocus);
Browser.WhenKeyboard = STDBACK(::ShowKeyboard);
Browser.WhenConsoleMessage = THISBACK(OnConsoleMessage);
Browser.WhenMessage = THISBACK(OnMessage);
Back.WhenAction = callback(&Browser, &ChromiumBrowser::GoBack);
Forward.WhenAction = callback(&Browser, &ChromiumBrowser::GoForward);
@ -30,6 +32,7 @@ ChromiumBrowserExample::ChromiumBrowserExample()
Url.WhenEnter = THISBACK(OnBrowse);
Go.WhenAction = THISBACK(OnBrowse);
Stop.WhenAction = callback(&Browser, &ChromiumBrowser::Stop);
JSTests.WhenAction = THISBACK(OnJSTests);
#ifdef PLATFORM_WIN32
Maximize();
@ -40,6 +43,27 @@ ChromiumBrowserExample::ChromiumBrowserExample()
}
void ChromiumBrowserExample::OnJSTests()
{
Browser.ShowHTML(String(test_page, test_page_length));
}
void ChromiumBrowserExample::OnMessage(String name, WithDeepCopy<Vector<Value> > par)
{
String tmp = "Native function executed by JS:&[* " + name + "(";
for (int i = 0; i < par.GetCount(); i++){
if (i > 0) tmp += ',';
tmp += DeQtfLf(par[i].ToString());
}
tmp += ") ]&&After you press OK javascript function will be executed by native code";
PromptOK(tmp);
Browser.ExecuteJavaScript(Format("CallbackExample(%d);", (int)Random()));
}
GUI_APP_MAIN
{
StdLogSetup(LOG_FILE | LOG_CERR | LOG_TIMESTAMP | LOG_APPEND);