android: compat webviewexecutor to support arraybuffer
This commit is contained in:
parent
c67803b717
commit
8c57e5e500
@ -17,6 +17,7 @@ package pub.doric.engine;
|
|||||||
|
|
||||||
import com.github.pengfeizhou.jscore.ArchiveException;
|
import com.github.pengfeizhou.jscore.ArchiveException;
|
||||||
import com.github.pengfeizhou.jscore.JSArray;
|
import com.github.pengfeizhou.jscore.JSArray;
|
||||||
|
import com.github.pengfeizhou.jscore.JSArrayBuffer;
|
||||||
import com.github.pengfeizhou.jscore.JSBoolean;
|
import com.github.pengfeizhou.jscore.JSBoolean;
|
||||||
import com.github.pengfeizhou.jscore.JSDecoder;
|
import com.github.pengfeizhou.jscore.JSDecoder;
|
||||||
import com.github.pengfeizhou.jscore.JSNull;
|
import com.github.pengfeizhou.jscore.JSNull;
|
||||||
@ -127,6 +128,9 @@ public class DoricJSDecoder extends JSDecoder {
|
|||||||
}
|
}
|
||||||
return jsArray;
|
return jsArray;
|
||||||
}
|
}
|
||||||
|
if (this.value instanceof byte[]) {
|
||||||
|
return new JSArrayBuffer((byte[]) this.value);
|
||||||
|
}
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,14 +109,14 @@ public class DoricJSEngine implements Handler.Callback, DoricTimerExtension.Time
|
|||||||
e.printStackTrace(new PrintWriter(stringWriter));
|
e.printStackTrace(new PrintWriter(stringWriter));
|
||||||
mDoricRegistry.onLog(Log.ERROR, stringWriter.toString());
|
mDoricRegistry.onLog(Log.ERROR, stringWriter.toString());
|
||||||
//In case some unexpected errors happened
|
//In case some unexpected errors happened
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||||
mDoricRegistry.onLog(Log.WARN, "Use DoricWebViewJSExecutor");
|
// mDoricRegistry.onLog(Log.WARN, "Use DoricWebViewJSExecutor");
|
||||||
mDoricJSE = new DoricWebViewJSExecutor(Doric.application());
|
// mDoricJSE = new DoricWebViewJSExecutor(Doric.application());
|
||||||
loadBuiltinJS("doric-web.js");
|
// loadBuiltinJS("doric-web.js");
|
||||||
} else {
|
// } else {
|
||||||
mDoricRegistry.onLog(Log.WARN, "Use DoricWebShellJSExecutor");
|
mDoricRegistry.onLog(Log.WARN, "Use DoricWebShellJSExecutor");
|
||||||
mDoricJSE = new DoricWebShellJSExecutor(Doric.application());
|
mDoricJSE = new DoricWebShellJSExecutor(Doric.application());
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import android.os.Build;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Base64;
|
||||||
import android.webkit.ConsoleMessage;
|
import android.webkit.ConsoleMessage;
|
||||||
import android.webkit.JavascriptInterface;
|
import android.webkit.JavascriptInterface;
|
||||||
import android.webkit.JsResult;
|
import android.webkit.JsResult;
|
||||||
@ -43,6 +44,7 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.lang.ref.SoftReference;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -66,6 +68,8 @@ public class DoricWebShellJSExecutor implements IDoricJSE {
|
|||||||
private WebView webView;
|
private WebView webView;
|
||||||
private final Map<String, JavaFunction> globalFunctions = new HashMap<>();
|
private final Map<String, JavaFunction> globalFunctions = new HashMap<>();
|
||||||
private final Handler handler;
|
private final Handler handler;
|
||||||
|
private static final Map<String, SoftReference<byte[]>> arrayBuffers = new HashMap<>();
|
||||||
|
private static final AtomicInteger arrayBufferId = new AtomicInteger();
|
||||||
|
|
||||||
private static Object unwrapJSObject(JSONObject jsonObject) {
|
private static Object unwrapJSObject(JSONObject jsonObject) {
|
||||||
String type = jsonObject.optString("type");
|
String type = jsonObject.optString("type");
|
||||||
@ -90,6 +94,9 @@ public class DoricWebShellJSExecutor implements IDoricJSE {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return JSONObject.NULL;
|
return JSONObject.NULL;
|
||||||
}
|
}
|
||||||
|
case "arrayBuffer":
|
||||||
|
String base64 = jsonObject.optString("value");
|
||||||
|
return Base64.decode(base64, Base64.NO_WRAP);
|
||||||
default:
|
default:
|
||||||
return JSONObject.NULL;
|
return JSONObject.NULL;
|
||||||
}
|
}
|
||||||
@ -127,6 +134,12 @@ public class DoricWebShellJSExecutor implements IDoricJSE {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (javaValue.getType() == 6) {
|
||||||
|
byte[] data = javaValue.getByteData();
|
||||||
|
String id = String.valueOf(arrayBufferId.incrementAndGet());
|
||||||
|
arrayBuffers.put(id, new SoftReference<>(data));
|
||||||
|
return new JSONBuilder().put("type", "arrayBuffer").put("value", id).toJSONObject();
|
||||||
|
}
|
||||||
return WRAPPED_NULL;
|
return WRAPPED_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,6 +155,16 @@ public class DoricWebShellJSExecutor implements IDoricJSE {
|
|||||||
readyFuture.set(true);
|
readyFuture.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JavascriptInterface
|
||||||
|
public String fetchArrayBuffer(String arrayBufferId) {
|
||||||
|
SoftReference<byte[]> ref = arrayBuffers.remove(arrayBufferId);
|
||||||
|
if (ref != null && ref.get() != null) {
|
||||||
|
byte[] data = ref.get();
|
||||||
|
return Base64.encodeToString(data, Base64.NO_WRAP);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
public void log(String message) {
|
public void log(String message) {
|
||||||
DoricLog.d(message);
|
DoricLog.d(message);
|
||||||
|
@ -22,6 +22,7 @@ import android.os.Build;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
import android.util.Base64;
|
||||||
import android.webkit.ConsoleMessage;
|
import android.webkit.ConsoleMessage;
|
||||||
import android.webkit.JavascriptInterface;
|
import android.webkit.JavascriptInterface;
|
||||||
import android.webkit.JsResult;
|
import android.webkit.JsResult;
|
||||||
@ -39,8 +40,10 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.lang.ref.SoftReference;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import pub.doric.BuildConfig;
|
import pub.doric.BuildConfig;
|
||||||
import pub.doric.async.SettableFuture;
|
import pub.doric.async.SettableFuture;
|
||||||
@ -57,6 +60,8 @@ public class DoricWebViewJSExecutor implements IDoricJSE {
|
|||||||
private WebView webView;
|
private WebView webView;
|
||||||
private final Map<String, JavaFunction> globalFunctions = new HashMap<>();
|
private final Map<String, JavaFunction> globalFunctions = new HashMap<>();
|
||||||
private final Handler handler;
|
private final Handler handler;
|
||||||
|
private static final Map<String, SoftReference<byte[]>> arrayBuffers = new HashMap<>();
|
||||||
|
private static final AtomicInteger arrayBufferId = new AtomicInteger();
|
||||||
|
|
||||||
private static Object unwrapJSObject(JSONObject jsonObject) {
|
private static Object unwrapJSObject(JSONObject jsonObject) {
|
||||||
String type = jsonObject.optString("type");
|
String type = jsonObject.optString("type");
|
||||||
@ -81,6 +86,9 @@ public class DoricWebViewJSExecutor implements IDoricJSE {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return JSONObject.NULL;
|
return JSONObject.NULL;
|
||||||
}
|
}
|
||||||
|
case "arrayBuffer":
|
||||||
|
String base64 = jsonObject.optString("value");
|
||||||
|
return Base64.decode(base64, Base64.NO_WRAP);
|
||||||
default:
|
default:
|
||||||
return JSONObject.NULL;
|
return JSONObject.NULL;
|
||||||
}
|
}
|
||||||
@ -118,6 +126,12 @@ public class DoricWebViewJSExecutor implements IDoricJSE {
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (javaValue.getType() == 6) {
|
||||||
|
byte[] data = javaValue.getByteData();
|
||||||
|
String id = String.valueOf(arrayBufferId.incrementAndGet());
|
||||||
|
arrayBuffers.put(id, new SoftReference<>(data));
|
||||||
|
return new JSONBuilder().put("type", "arrayBuffer").put("value", id).toJSONObject();
|
||||||
|
}
|
||||||
return WRAPPED_NULL;
|
return WRAPPED_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,9 +146,19 @@ public class DoricWebViewJSExecutor implements IDoricJSE {
|
|||||||
DoricLog.d(message);
|
DoricLog.d(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JavascriptInterface
|
||||||
|
public String fetchArrayBuffer(String arrayBufferId) {
|
||||||
|
SoftReference<byte[]> ref = arrayBuffers.remove(arrayBufferId);
|
||||||
|
if (ref != null && ref.get() != null) {
|
||||||
|
byte[] data = ref.get();
|
||||||
|
return Base64.encodeToString(data, Base64.NO_WRAP);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
public void returnNative(String result) {
|
public void returnNative(String result) {
|
||||||
DoricLog.d("return Native" + result);
|
DoricLog.d("return Native " + result);
|
||||||
if (returnFuture != null) {
|
if (returnFuture != null) {
|
||||||
returnFuture.set(result);
|
returnFuture.set(result);
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,8 @@ import com.bumptech.glide.request.target.DrawableImageViewTarget;
|
|||||||
import com.bumptech.glide.request.target.SizeReadyCallback;
|
import com.bumptech.glide.request.target.SizeReadyCallback;
|
||||||
import com.bumptech.glide.request.target.Target;
|
import com.bumptech.glide.request.target.Target;
|
||||||
import com.facebook.yoga.YogaNode;
|
import com.facebook.yoga.YogaNode;
|
||||||
|
import com.github.pengfeizhou.jscore.ArchiveException;
|
||||||
|
import com.github.pengfeizhou.jscore.JSDecoder;
|
||||||
import com.github.pengfeizhou.jscore.JSONBuilder;
|
import com.github.pengfeizhou.jscore.JSONBuilder;
|
||||||
import com.github.pengfeizhou.jscore.JSObject;
|
import com.github.pengfeizhou.jscore.JSObject;
|
||||||
import com.github.pengfeizhou.jscore.JSValue;
|
import com.github.pengfeizhou.jscore.JSValue;
|
||||||
@ -394,7 +396,7 @@ public class ImageNode extends ViewNode<ImageView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void blend(ImageView view, String name, JSValue prop) {
|
protected void blend(final ImageView view, String name, JSValue prop) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "image":
|
case "image":
|
||||||
if (!prop.isObject()) {
|
if (!prop.isObject()) {
|
||||||
@ -522,13 +524,46 @@ public class ImageNode extends ViewNode<ImageView> {
|
|||||||
if (!prop.isObject()) {
|
if (!prop.isObject()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int width = prop.asObject().getProperty("width").asNumber().toInt();
|
final int width = prop.asObject().getProperty("width").asNumber().toInt();
|
||||||
int height = prop.asObject().getProperty("height").asNumber().toInt();
|
final int height = prop.asObject().getProperty("height").asNumber().toInt();
|
||||||
byte[] pixels = prop.asObject().getProperty("pixels").asArrayBuffer().value();
|
JSValue pixelsValue = prop.asObject().getProperty("pixels");
|
||||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
if (pixelsValue.isArrayBuffer()) {
|
||||||
ByteBuffer byteBuffer = ByteBuffer.wrap(pixels);
|
byte[] pixels = prop.asObject().getProperty("pixels").asArrayBuffer().value();
|
||||||
bitmap.copyPixelsFromBuffer(byteBuffer);
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
view.setImageBitmap(bitmap);
|
ByteBuffer byteBuffer = ByteBuffer.wrap(pixels);
|
||||||
|
bitmap.copyPixelsFromBuffer(byteBuffer);
|
||||||
|
view.setImageBitmap(bitmap);
|
||||||
|
} else if (pixelsValue.isString()) {
|
||||||
|
String pixelsCallbackId = pixelsValue.asString().value();
|
||||||
|
callJSResponse(pixelsCallbackId).setCallback(new AsyncResult.Callback<JSDecoder>() {
|
||||||
|
@Override
|
||||||
|
public void onResult(JSDecoder result) {
|
||||||
|
try {
|
||||||
|
JSValue value = result.decode();
|
||||||
|
if (value.isArrayBuffer()) {
|
||||||
|
byte[] pixels = value.asArrayBuffer().value();
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.wrap(pixels);
|
||||||
|
bitmap.copyPixelsFromBuffer(byteBuffer);
|
||||||
|
view.setImageBitmap(bitmap);
|
||||||
|
}
|
||||||
|
} catch (ArchiveException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFinish() {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
super.blend(view, name, prop);
|
super.blend(view, name, prop);
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package com.github.pengfeizhou.jscore;
|
||||||
|
|
||||||
|
public class JSArrayBuffer extends JSValue {
|
||||||
|
private final byte[] mVal;
|
||||||
|
|
||||||
|
public JSArrayBuffer(byte[] val) {
|
||||||
|
this.mVal = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getByteLength() {
|
||||||
|
return mVal.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JSType getJSType() {
|
||||||
|
return JSType.ArrayBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] value() {
|
||||||
|
return mVal;
|
||||||
|
}
|
||||||
|
}
|
@ -25,6 +25,7 @@ public abstract class JSValue {
|
|||||||
String,
|
String,
|
||||||
Object,
|
Object,
|
||||||
Array,
|
Array,
|
||||||
|
ArrayBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract JSType getJSType();
|
public abstract JSType getJSType();
|
||||||
@ -55,6 +56,10 @@ public abstract class JSValue {
|
|||||||
return getJSType() == JSType.Array;
|
return getJSType() == JSType.Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isArrayBuffer() {
|
||||||
|
return getJSType() == JSType.ArrayBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
public JSNull asNull() {
|
public JSNull asNull() {
|
||||||
return (JSNull) this;
|
return (JSNull) this;
|
||||||
}
|
}
|
||||||
@ -79,6 +84,10 @@ public abstract class JSValue {
|
|||||||
return (JSArray) this;
|
return (JSArray) this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JSArrayBuffer asArrayBuffer() {
|
||||||
|
return (JSArrayBuffer) this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.valueOf(value());
|
return String.valueOf(value());
|
||||||
|
@ -25,10 +25,14 @@ public class JavaValue {
|
|||||||
protected static final int TYPE_STRING = 3;
|
protected static final int TYPE_STRING = 3;
|
||||||
protected static final int TYPE_OBJECT = 4;
|
protected static final int TYPE_OBJECT = 4;
|
||||||
protected static final int TYPE_ARRAY = 5;
|
protected static final int TYPE_ARRAY = 5;
|
||||||
|
protected static final int TYPE_ARRAYBUFFER = 6;
|
||||||
|
|
||||||
protected JavaFunction[] functions = null;
|
protected JavaFunction[] functions = null;
|
||||||
protected String[] functionNames = null;
|
protected String[] functionNames = null;
|
||||||
protected int type;
|
protected int type;
|
||||||
protected String value = "";
|
protected String value = "";
|
||||||
|
protected byte[] data = null;
|
||||||
|
protected MemoryReleaser memoryReleaser = null;
|
||||||
|
|
||||||
public JavaValue() {
|
public JavaValue() {
|
||||||
this.type = TYPE_NULL;
|
this.type = TYPE_NULL;
|
||||||
@ -75,6 +79,17 @@ public class JavaValue {
|
|||||||
this.value = jsonArray.toString();
|
this.value = jsonArray.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JavaValue(byte[] data) {
|
||||||
|
this.type = TYPE_ARRAYBUFFER;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JavaValue(byte[] data, MemoryReleaser memoryReleaser) {
|
||||||
|
this.type = TYPE_ARRAYBUFFER;
|
||||||
|
this.data = data;
|
||||||
|
this.memoryReleaser = memoryReleaser;
|
||||||
|
}
|
||||||
|
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@ -82,4 +97,24 @@ public class JavaValue {
|
|||||||
public String getValue() {
|
public String getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] getByteData() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MemoryReleaser {
|
||||||
|
/**
|
||||||
|
* Called when JS deallocated the arraybuffer
|
||||||
|
*/
|
||||||
|
void deallocate(byte[] data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by JNI
|
||||||
|
*/
|
||||||
|
private void onDeallocated() {
|
||||||
|
if (this.memoryReleaser != null) {
|
||||||
|
this.memoryReleaser.deallocate(this.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -2314,12 +2314,10 @@ var Image = /** @class */ (function (_super) {
|
|||||||
};
|
};
|
||||||
Image.prototype.toModel = function () {
|
Image.prototype.toModel = function () {
|
||||||
var ret = _super.prototype.toModel.call(this);
|
var ret = _super.prototype.toModel.call(this);
|
||||||
if (Environment.platform === 'iOS') {
|
if (Reflect.has(ret.props, "imagePixels")) {
|
||||||
if (Reflect.has(ret.props, "imagePixels")) {
|
var imagePixels = Reflect.get(ret.props, "imagePixels");
|
||||||
var imagePixels = Reflect.get(ret.props, "imagePixels");
|
var pixels_1 = imagePixels.pixels;
|
||||||
var pixels_1 = imagePixels.pixels;
|
imagePixels.pixels = this.callback2Id(function () { return pixels_1; });
|
||||||
imagePixels.pixels = this.callback2Id(function () { return pixels_1; });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
@ -1728,12 +1728,10 @@ class Image extends View {
|
|||||||
}
|
}
|
||||||
toModel() {
|
toModel() {
|
||||||
const ret = super.toModel();
|
const ret = super.toModel();
|
||||||
if (Environment.platform === 'iOS') {
|
if (Reflect.has(ret.props, "imagePixels")) {
|
||||||
if (Reflect.has(ret.props, "imagePixels")) {
|
const imagePixels = Reflect.get(ret.props, "imagePixels");
|
||||||
const imagePixels = Reflect.get(ret.props, "imagePixels");
|
const pixels = imagePixels.pixels;
|
||||||
const pixels = imagePixels.pixels;
|
imagePixels.pixels = this.callback2Id(() => pixels);
|
||||||
imagePixels.pixels = this.callback2Id(() => pixels);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -3256,12 +3256,10 @@ class Image extends View {
|
|||||||
}
|
}
|
||||||
toModel() {
|
toModel() {
|
||||||
const ret = super.toModel();
|
const ret = super.toModel();
|
||||||
if (Environment.platform === 'iOS') {
|
if (Reflect.has(ret.props, "imagePixels")) {
|
||||||
if (Reflect.has(ret.props, "imagePixels")) {
|
const imagePixels = Reflect.get(ret.props, "imagePixels");
|
||||||
const imagePixels = Reflect.get(ret.props, "imagePixels");
|
const pixels = imagePixels.pixels;
|
||||||
const pixels = imagePixels.pixels;
|
imagePixels.pixels = this.callback2Id(() => pixels);
|
||||||
imagePixels.pixels = this.callback2Id(() => pixels);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1,42 +1,53 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
function _binaryValue(v) {
|
function _arrayBufferToBase64(arrayBuffer) {
|
||||||
switch (typeof v) {
|
let base64 = '';
|
||||||
case "number":
|
const encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||||
return {
|
const bytes = new Uint8Array(arrayBuffer);
|
||||||
type: "number",
|
const byteLength = bytes.byteLength;
|
||||||
value: v
|
const byteRemainder = byteLength % 3;
|
||||||
};
|
const mainLength = byteLength - byteRemainder;
|
||||||
case "string":
|
let a, b, c, d;
|
||||||
return {
|
let chunk;
|
||||||
type: "string",
|
// Main loop deals with bytes in chunks of 3
|
||||||
value: v
|
for (var i = 0; i < mainLength; i = i + 3) {
|
||||||
};
|
// Combine the three bytes into a single integer
|
||||||
case "boolean":
|
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
||||||
return {
|
// Use bitmasks to extract 6-bit segments from the triplet
|
||||||
type: "boolean",
|
a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
|
||||||
value: v
|
b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12
|
||||||
};
|
c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6
|
||||||
case "object":
|
d = chunk & 63; // 63 = 2^6 - 1
|
||||||
if (v instanceof Array) {
|
// Convert the raw binary segments to the appropriate ASCII encoding
|
||||||
return {
|
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
|
||||||
type: "array",
|
|
||||||
value: JSON.stringify(v)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return {
|
|
||||||
type: "object",
|
|
||||||
value: JSON.stringify(v)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
type: "null",
|
|
||||||
value: undefined
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
// Deal with the remaining bytes and padding
|
||||||
|
if (byteRemainder == 1) {
|
||||||
|
chunk = bytes[mainLength];
|
||||||
|
a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
|
||||||
|
// Set the 4 least significant bits to zero
|
||||||
|
b = (chunk & 3) << 4; // 3 = 2^2 - 1
|
||||||
|
base64 += encodings[a] + encodings[b] + '==';
|
||||||
|
}
|
||||||
|
else if (byteRemainder == 2) {
|
||||||
|
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1];
|
||||||
|
a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
|
||||||
|
b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4
|
||||||
|
// Set the 2 least significant bits to zero
|
||||||
|
c = (chunk & 15) << 2; // 15 = 2^4 - 1
|
||||||
|
base64 += encodings[a] + encodings[b] + encodings[c] + '=';
|
||||||
|
}
|
||||||
|
return base64;
|
||||||
|
}
|
||||||
|
function _base64ToArrayBuffer(v) {
|
||||||
|
const binary_string = window.atob(v);
|
||||||
|
const len = binary_string.length;
|
||||||
|
const bytes = new Uint8Array(len);
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
bytes[i] = binary_string.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return bytes.buffer;
|
||||||
}
|
}
|
||||||
function _wrappedValue(v) {
|
function _wrappedValue(v) {
|
||||||
switch (typeof v) {
|
switch (typeof v) {
|
||||||
@ -56,7 +67,13 @@ function _wrappedValue(v) {
|
|||||||
value: v
|
value: v
|
||||||
};
|
};
|
||||||
case "object":
|
case "object":
|
||||||
if (v instanceof Array) {
|
if (v instanceof ArrayBuffer) {
|
||||||
|
return {
|
||||||
|
type: "arrayBuffer",
|
||||||
|
value: _arrayBufferToBase64(v)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (v instanceof Array) {
|
||||||
return {
|
return {
|
||||||
type: "array",
|
type: "array",
|
||||||
value: JSON.stringify(v)
|
value: JSON.stringify(v)
|
||||||
@ -89,6 +106,10 @@ function _rawValue(v) {
|
|||||||
return JSON.parse(v.value);
|
return JSON.parse(v.value);
|
||||||
}
|
}
|
||||||
return v.value;
|
return v.value;
|
||||||
|
case "arrayBuffer":
|
||||||
|
const data = NativeClient.fetchArrayBuffer(v.value);
|
||||||
|
return _base64ToArrayBuffer(data);
|
||||||
|
;
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -2,51 +2,74 @@ declare module NativeClient {
|
|||||||
function log(message: string): void
|
function log(message: string): void
|
||||||
function returnNative(ret: string): void
|
function returnNative(ret: string): void
|
||||||
function callNative(name: string, args: string): string
|
function callNative(name: string, args: string): string
|
||||||
|
function fetchArrayBuffer(id: string): string
|
||||||
}
|
}
|
||||||
|
|
||||||
type RawValue = number | string | boolean | object | undefined
|
type RawValue = number | string | boolean | object | undefined | ArrayBuffer
|
||||||
|
|
||||||
type WrappedValue = {
|
type WrappedValue = {
|
||||||
type: "number" | "string" | "boolean" | "object" | "array" | "null",
|
type: "number" | "string" | "boolean" | "object" | "array" | "null" | "arrayBuffer",
|
||||||
value: RawValue,
|
value: RawValue,
|
||||||
}
|
}
|
||||||
function _binaryValue(v: RawValue) {
|
|
||||||
switch (typeof v) {
|
function _arrayBufferToBase64(arrayBuffer: ArrayBuffer) {
|
||||||
case "number":
|
let base64 = ''
|
||||||
return {
|
const encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||||||
type: "number",
|
|
||||||
value: v
|
const bytes = new Uint8Array(arrayBuffer)
|
||||||
};
|
const byteLength = bytes.byteLength
|
||||||
case "string":
|
const byteRemainder = byteLength % 3
|
||||||
return {
|
const mainLength = byteLength - byteRemainder
|
||||||
type: "string",
|
|
||||||
value: v
|
let a, b, c, d
|
||||||
};
|
let chunk
|
||||||
case "boolean":
|
|
||||||
return {
|
// Main loop deals with bytes in chunks of 3
|
||||||
type: "boolean",
|
for (var i = 0; i < mainLength; i = i + 3) {
|
||||||
value: v
|
// Combine the three bytes into a single integer
|
||||||
};
|
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2]
|
||||||
case "object":
|
// Use bitmasks to extract 6-bit segments from the triplet
|
||||||
if (v instanceof Array) {
|
a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
|
||||||
return {
|
b = (chunk & 258048) >> 12 // 258048 = (2^6 - 1) << 12
|
||||||
type: "array",
|
c = (chunk & 4032) >> 6 // 4032 = (2^6 - 1) << 6
|
||||||
value: JSON.stringify(v)
|
d = chunk & 63 // 63 = 2^6 - 1
|
||||||
};
|
// Convert the raw binary segments to the appropriate ASCII encoding
|
||||||
} else {
|
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d]
|
||||||
return {
|
|
||||||
type: "object",
|
|
||||||
value: JSON.stringify(v)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
type: "null",
|
|
||||||
value: undefined
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deal with the remaining bytes and padding
|
||||||
|
if (byteRemainder == 1) {
|
||||||
|
chunk = bytes[mainLength]
|
||||||
|
|
||||||
|
a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
|
||||||
|
|
||||||
|
// Set the 4 least significant bits to zero
|
||||||
|
b = (chunk & 3) << 4 // 3 = 2^2 - 1
|
||||||
|
|
||||||
|
base64 += encodings[a] + encodings[b] + '=='
|
||||||
|
} else if (byteRemainder == 2) {
|
||||||
|
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1]
|
||||||
|
|
||||||
|
a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
|
||||||
|
b = (chunk & 1008) >> 4 // 1008 = (2^6 - 1) << 4
|
||||||
|
|
||||||
|
// Set the 2 least significant bits to zero
|
||||||
|
c = (chunk & 15) << 2 // 15 = 2^4 - 1
|
||||||
|
|
||||||
|
base64 += encodings[a] + encodings[b] + encodings[c] + '='
|
||||||
|
}
|
||||||
|
return base64
|
||||||
}
|
}
|
||||||
|
function _base64ToArrayBuffer(v: string) {
|
||||||
|
const binary_string = window.atob(v);
|
||||||
|
const len = binary_string.length;
|
||||||
|
const bytes = new Uint8Array(len);
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
bytes[i] = binary_string.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return bytes.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
function _wrappedValue(v: RawValue): WrappedValue {
|
function _wrappedValue(v: RawValue): WrappedValue {
|
||||||
switch (typeof v) {
|
switch (typeof v) {
|
||||||
case "number":
|
case "number":
|
||||||
@ -65,7 +88,12 @@ function _wrappedValue(v: RawValue): WrappedValue {
|
|||||||
value: v
|
value: v
|
||||||
};
|
};
|
||||||
case "object":
|
case "object":
|
||||||
if (v instanceof Array) {
|
if (v instanceof ArrayBuffer) {
|
||||||
|
return {
|
||||||
|
type: "arrayBuffer",
|
||||||
|
value: _arrayBufferToBase64(v)
|
||||||
|
};
|
||||||
|
} else if (v instanceof Array) {
|
||||||
return {
|
return {
|
||||||
type: "array",
|
type: "array",
|
||||||
value: JSON.stringify(v)
|
value: JSON.stringify(v)
|
||||||
@ -98,6 +126,9 @@ function _rawValue(v: WrappedValue): RawValue {
|
|||||||
return JSON.parse(v.value)
|
return JSON.parse(v.value)
|
||||||
}
|
}
|
||||||
return v.value;
|
return v.value;
|
||||||
|
case "arrayBuffer":
|
||||||
|
const data = NativeClient.fetchArrayBuffer(v.value as string);
|
||||||
|
return _base64ToArrayBuffer(data);;
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
20
doric-js/lib/index.web.d.ts
vendored
20
doric-js/lib/index.web.d.ts
vendored
@ -2,25 +2,15 @@ declare module NativeClient {
|
|||||||
function log(message: string): void;
|
function log(message: string): void;
|
||||||
function returnNative(ret: string): void;
|
function returnNative(ret: string): void;
|
||||||
function callNative(name: string, args: string): string;
|
function callNative(name: string, args: string): string;
|
||||||
|
function fetchArrayBuffer(id: string): string;
|
||||||
}
|
}
|
||||||
declare type RawValue = number | string | boolean | object | undefined;
|
declare type RawValue = number | string | boolean | object | undefined | ArrayBuffer;
|
||||||
declare type WrappedValue = {
|
declare type WrappedValue = {
|
||||||
type: "number" | "string" | "boolean" | "object" | "array" | "null";
|
type: "number" | "string" | "boolean" | "object" | "array" | "null" | "arrayBuffer";
|
||||||
value: RawValue;
|
value: RawValue;
|
||||||
};
|
};
|
||||||
declare function _binaryValue(v: RawValue): {
|
declare function _arrayBufferToBase64(arrayBuffer: ArrayBuffer): string;
|
||||||
type: string;
|
declare function _base64ToArrayBuffer(v: string): ArrayBufferLike;
|
||||||
value: number;
|
|
||||||
} | {
|
|
||||||
type: string;
|
|
||||||
value: string;
|
|
||||||
} | {
|
|
||||||
type: string;
|
|
||||||
value: boolean;
|
|
||||||
} | {
|
|
||||||
type: string;
|
|
||||||
value: undefined;
|
|
||||||
};
|
|
||||||
declare function _wrappedValue(v: RawValue): WrappedValue;
|
declare function _wrappedValue(v: RawValue): WrappedValue;
|
||||||
declare function _rawValue(v: WrappedValue): RawValue;
|
declare function _rawValue(v: WrappedValue): RawValue;
|
||||||
declare function __injectGlobalObject(name: string, args: string): void;
|
declare function __injectGlobalObject(name: string, args: string): void;
|
||||||
|
@ -1,40 +1,51 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
function _binaryValue(v) {
|
function _arrayBufferToBase64(arrayBuffer) {
|
||||||
switch (typeof v) {
|
let base64 = '';
|
||||||
case "number":
|
const encodings = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||||
return {
|
const bytes = new Uint8Array(arrayBuffer);
|
||||||
type: "number",
|
const byteLength = bytes.byteLength;
|
||||||
value: v
|
const byteRemainder = byteLength % 3;
|
||||||
};
|
const mainLength = byteLength - byteRemainder;
|
||||||
case "string":
|
let a, b, c, d;
|
||||||
return {
|
let chunk;
|
||||||
type: "string",
|
// Main loop deals with bytes in chunks of 3
|
||||||
value: v
|
for (var i = 0; i < mainLength; i = i + 3) {
|
||||||
};
|
// Combine the three bytes into a single integer
|
||||||
case "boolean":
|
chunk = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];
|
||||||
return {
|
// Use bitmasks to extract 6-bit segments from the triplet
|
||||||
type: "boolean",
|
a = (chunk & 16515072) >> 18; // 16515072 = (2^6 - 1) << 18
|
||||||
value: v
|
b = (chunk & 258048) >> 12; // 258048 = (2^6 - 1) << 12
|
||||||
};
|
c = (chunk & 4032) >> 6; // 4032 = (2^6 - 1) << 6
|
||||||
case "object":
|
d = chunk & 63; // 63 = 2^6 - 1
|
||||||
if (v instanceof Array) {
|
// Convert the raw binary segments to the appropriate ASCII encoding
|
||||||
return {
|
base64 += encodings[a] + encodings[b] + encodings[c] + encodings[d];
|
||||||
type: "array",
|
|
||||||
value: JSON.stringify(v)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return {
|
|
||||||
type: "object",
|
|
||||||
value: JSON.stringify(v)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
type: "null",
|
|
||||||
value: undefined
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
// Deal with the remaining bytes and padding
|
||||||
|
if (byteRemainder == 1) {
|
||||||
|
chunk = bytes[mainLength];
|
||||||
|
a = (chunk & 252) >> 2; // 252 = (2^6 - 1) << 2
|
||||||
|
// Set the 4 least significant bits to zero
|
||||||
|
b = (chunk & 3) << 4; // 3 = 2^2 - 1
|
||||||
|
base64 += encodings[a] + encodings[b] + '==';
|
||||||
|
}
|
||||||
|
else if (byteRemainder == 2) {
|
||||||
|
chunk = (bytes[mainLength] << 8) | bytes[mainLength + 1];
|
||||||
|
a = (chunk & 64512) >> 10; // 64512 = (2^6 - 1) << 10
|
||||||
|
b = (chunk & 1008) >> 4; // 1008 = (2^6 - 1) << 4
|
||||||
|
// Set the 2 least significant bits to zero
|
||||||
|
c = (chunk & 15) << 2; // 15 = 2^4 - 1
|
||||||
|
base64 += encodings[a] + encodings[b] + encodings[c] + '=';
|
||||||
|
}
|
||||||
|
return base64;
|
||||||
|
}
|
||||||
|
function _base64ToArrayBuffer(v) {
|
||||||
|
const binary_string = window.atob(v);
|
||||||
|
const len = binary_string.length;
|
||||||
|
const bytes = new Uint8Array(len);
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
bytes[i] = binary_string.charCodeAt(i);
|
||||||
|
}
|
||||||
|
return bytes.buffer;
|
||||||
}
|
}
|
||||||
function _wrappedValue(v) {
|
function _wrappedValue(v) {
|
||||||
switch (typeof v) {
|
switch (typeof v) {
|
||||||
@ -54,7 +65,13 @@ function _wrappedValue(v) {
|
|||||||
value: v
|
value: v
|
||||||
};
|
};
|
||||||
case "object":
|
case "object":
|
||||||
if (v instanceof Array) {
|
if (v instanceof ArrayBuffer) {
|
||||||
|
return {
|
||||||
|
type: "arrayBuffer",
|
||||||
|
value: _arrayBufferToBase64(v)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (v instanceof Array) {
|
||||||
return {
|
return {
|
||||||
type: "array",
|
type: "array",
|
||||||
value: JSON.stringify(v)
|
value: JSON.stringify(v)
|
||||||
@ -87,6 +104,10 @@ function _rawValue(v) {
|
|||||||
return JSON.parse(v.value);
|
return JSON.parse(v.value);
|
||||||
}
|
}
|
||||||
return v.value;
|
return v.value;
|
||||||
|
case "arrayBuffer":
|
||||||
|
const data = NativeClient.fetchArrayBuffer(v.value);
|
||||||
|
return _base64ToArrayBuffer(data);
|
||||||
|
;
|
||||||
default:
|
default:
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
@ -50,12 +50,10 @@ export class Image extends View {
|
|||||||
}
|
}
|
||||||
toModel() {
|
toModel() {
|
||||||
const ret = super.toModel();
|
const ret = super.toModel();
|
||||||
if (Environment.platform === 'iOS') {
|
if (Reflect.has(ret.props, "imagePixels")) {
|
||||||
if (Reflect.has(ret.props, "imagePixels")) {
|
const imagePixels = Reflect.get(ret.props, "imagePixels");
|
||||||
const imagePixels = Reflect.get(ret.props, "imagePixels");
|
const pixels = imagePixels.pixels;
|
||||||
const pixels = imagePixels.pixels;
|
imagePixels.pixels = this.callback2Id(() => pixels);
|
||||||
imagePixels.pixels = this.callback2Id(() => pixels);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -150,14 +150,12 @@ export class Image extends View {
|
|||||||
return this.nativeChannel(context, "getImagePixels")()
|
return this.nativeChannel(context, "getImagePixels")()
|
||||||
}
|
}
|
||||||
|
|
||||||
toModel() {
|
toModel(): NativeViewModel {
|
||||||
const ret = super.toModel()
|
const ret = super.toModel()
|
||||||
if (Environment.platform === 'iOS') {
|
if (Reflect.has(ret.props, "imagePixels")) {
|
||||||
if (Reflect.has(ret.props, "imagePixels")) {
|
const imagePixels = Reflect.get(ret.props, "imagePixels")
|
||||||
const imagePixels = Reflect.get(ret.props, "imagePixels")
|
const pixels = imagePixels.pixels
|
||||||
const pixels = imagePixels.pixels
|
imagePixels.pixels = this.callback2Id(() => pixels)
|
||||||
imagePixels.pixels = this.callback2Id(() => pixels)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
}
|
}
|
||||||
|
10
doric-web/dist/index.js
vendored
10
doric-web/dist/index.js
vendored
@ -3330,12 +3330,10 @@ class Image extends View {
|
|||||||
}
|
}
|
||||||
toModel() {
|
toModel() {
|
||||||
const ret = super.toModel();
|
const ret = super.toModel();
|
||||||
if (Environment.platform === 'iOS') {
|
if (Reflect.has(ret.props, "imagePixels")) {
|
||||||
if (Reflect.has(ret.props, "imagePixels")) {
|
const imagePixels = Reflect.get(ret.props, "imagePixels");
|
||||||
const imagePixels = Reflect.get(ret.props, "imagePixels");
|
const pixels = imagePixels.pixels;
|
||||||
const pixels = imagePixels.pixels;
|
imagePixels.pixels = this.callback2Id(() => pixels);
|
||||||
imagePixels.pixels = this.callback2Id(() => pixels);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
2
doric-web/dist/index.js.map
vendored
2
doric-web/dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user