1.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java Mon Jan 06 13:31:04 2014 +0100
1.2 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java Thu Jan 09 11:55:01 2014 +0100
1.3 @@ -25,6 +25,10 @@
1.4 import java.util.Collection;
1.5 import java.util.List;
1.6 import java.util.TooManyListenersException;
1.7 +import java.util.concurrent.Executor;
1.8 +import java.util.logging.Level;
1.9 +import java.util.logging.Logger;
1.10 +import javafx.application.Platform;
1.11 import javafx.beans.value.ChangeListener;
1.12 import javafx.scene.web.WebEngine;
1.13 import netscape.javascript.JSObject;
1.14 @@ -37,6 +41,8 @@
1.15 * @author Jaroslav Tulach <jtulach@netbeans.org>
1.16 */
1.17 public final class JVMBridge {
1.18 + static final Logger LOG = Logger.getLogger(JVMBridge.class.getName());
1.19 +
1.20 private final WebEngine engine;
1.21 private final ClassLoader cl;
1.22 private final WebPresenter presenter;
1.23 @@ -74,7 +80,8 @@
1.24 return Class.forName(name, true, cl);
1.25 }
1.26
1.27 - private final class WebPresenter implements FindResources, Fn.Presenter {
1.28 + private final class WebPresenter
1.29 + implements FindResources, Fn.Presenter, Fn.ToJavaScript, Executor {
1.30 @Override
1.31 public void findResources(String name, Collection<? super URL> results, boolean oneIsEnough) {
1.32 if (ldrs != null) for (ClassLoader l : ldrs) {
1.33 @@ -87,6 +94,9 @@
1.34
1.35 @Override
1.36 public Fn defineFn(String code, String... names) {
1.37 + return defineJSFn(code, names);
1.38 + }
1.39 + private JSFn defineJSFn(String code, String... names) {
1.40 StringBuilder sb = new StringBuilder();
1.41 sb.append("(function() {");
1.42 sb.append(" return function(");
1.43 @@ -122,6 +132,86 @@
1.44 }
1.45 engine.executeScript(sb.toString());
1.46 }
1.47 +
1.48 + @Override
1.49 + public Object toJavaScript(Object toReturn) {
1.50 + if (toReturn instanceof Object[]) {
1.51 + return convertArrays((Object[]) toReturn);
1.52 + }
1.53 + return toReturn;
1.54 + }
1.55 +
1.56 + @Override
1.57 + public void execute(Runnable command) {
1.58 + if (Platform.isFxApplicationThread()) {
1.59 + command.run();
1.60 + } else {
1.61 + Platform.runLater(command);
1.62 + }
1.63 + }
1.64 +
1.65 + final JSObject convertArrays(Object[] arr) {
1.66 + for (int i = 0; i < arr.length; i++) {
1.67 + if (arr[i] instanceof Object[]) {
1.68 + arr[i] = convertArrays((Object[]) arr[i]);
1.69 + }
1.70 + }
1.71 + final JSObject wrapArr = (JSObject) wrapArrFn().call("array", arr); // NOI18N
1.72 + return wrapArr;
1.73 + }
1.74 +
1.75 + private JSObject wrapArrImpl;
1.76 +
1.77 + private final JSObject wrapArrFn() {
1.78 + if (wrapArrImpl == null) {
1.79 + try {
1.80 + wrapArrImpl = (JSObject) defineJSFn(" var k = {};"
1.81 + + " k.array= function() {"
1.82 + + " return Array.prototype.slice.call(arguments);"
1.83 + + " };"
1.84 + + " return k;"
1.85 + ).invokeImpl(null, false);
1.86 + } catch (Exception ex) {
1.87 + throw new IllegalStateException(ex);
1.88 + }
1.89 + }
1.90 + return wrapArrImpl;
1.91 + }
1.92 +
1.93 + final Object checkArray(Object val) {
1.94 + int length = ((Number) arraySizeFn().call("array", val, null)).intValue();
1.95 + if (length == -1) {
1.96 + return val;
1.97 + }
1.98 + Object[] arr = new Object[length];
1.99 + arraySizeFn().call("array", val, arr);
1.100 + return arr;
1.101 + }
1.102 + private JSObject arraySize;
1.103 +
1.104 + private final JSObject arraySizeFn() {
1.105 + if (arraySize == null) {
1.106 + try {
1.107 + arraySize = (JSObject) defineJSFn(" var k = {};"
1.108 + + " k.array = function(arr, to) {"
1.109 + + " if (to === null) {"
1.110 + + " if (Object.prototype.toString.call(arr) === '[object Array]') return arr.length;"
1.111 + + " else return -1;"
1.112 + + " } else {"
1.113 + + " var l = arr.length;"
1.114 + + " for (var i = 0; i < l; i++) to[i] = arr[i];"
1.115 + + " return l;"
1.116 + + " }"
1.117 + + " };"
1.118 + + " return k;"
1.119 + ).invokeImpl(null, false);
1.120 + } catch (Exception ex) {
1.121 + throw new IllegalStateException(ex);
1.122 + }
1.123 + }
1.124 + return arraySize;
1.125 + }
1.126 +
1.127 }
1.128
1.129 private static final class JSFn extends Fn {
1.130 @@ -134,12 +224,29 @@
1.131
1.132 @Override
1.133 public Object invoke(Object thiz, Object... args) throws Exception {
1.134 + return invokeImpl(thiz, true, args);
1.135 + }
1.136 +
1.137 + final Object invokeImpl(Object thiz, boolean arrayChecks, Object... args) throws Exception {
1.138 try {
1.139 List<Object> all = new ArrayList<Object>(args.length + 1);
1.140 all.add(thiz == null ? fn : thiz);
1.141 - all.addAll(Arrays.asList(args));
1.142 + for (int i = 0; i < args.length; i++) {
1.143 + if (arrayChecks && args[i] instanceof Object[]) {
1.144 + Object[] arr = (Object[]) args[i];
1.145 + Object conv = ((WebPresenter) presenter()).convertArrays(arr);
1.146 + args[i] = conv;
1.147 + }
1.148 + all.add(args[i]);
1.149 + }
1.150 Object ret = fn.call("call", all.toArray()); // NOI18N
1.151 - return ret == fn ? null : ret;
1.152 + if (ret == fn) {
1.153 + return null;
1.154 + }
1.155 + if (!arrayChecks) {
1.156 + return ret;
1.157 + }
1.158 + return ((WebPresenter) presenter()).checkArray(ret);
1.159 } catch (Error t) {
1.160 t.printStackTrace();
1.161 throw t;