launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java
branchNbHtml4J
changeset 1423 237dbcd482dc
parent 1418 b8ff900a542d
child 1429 66358a11c016
     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;