From 02983ef39a34cd8dfbc940fb00cb209fd9a1c6b2 Mon Sep 17 00:00:00 2001 From: Paul Rouget Date: Wed, 1 Aug 2018 16:33:46 +0800 Subject: [PATCH 1/2] Add make_current to libsimpleservo --- ports/libsimpleservo/src/api.rs | 4 ++++ ports/libsimpleservo/src/capi.rs | 6 ++++++ ports/libsimpleservo/src/jniapi.rs | 7 +++++++ 3 files changed, 17 insertions(+) diff --git a/ports/libsimpleservo/src/api.rs b/ports/libsimpleservo/src/api.rs index a271dda59e45..57c6d644500a 100644 --- a/ports/libsimpleservo/src/api.rs +++ b/ports/libsimpleservo/src/api.rs @@ -39,6 +39,9 @@ pub trait HostTrait { /// Will be called from the thread used for the init call. /// Will be called when the GL buffer has been updated. fn flush(&self); + /// Will be called before drawing. + /// Time to make the targetted GL context current. + fn make_current(&self); /// Page starts loading. /// "Reload button" should be disabled. /// "Stop button" should be enabled. @@ -353,6 +356,7 @@ impl WindowMethods for ServoCallbacks { _height: Length, ) -> bool { debug!("WindowMethods::prepare_for_composite"); + self.host_callbacks.make_current(); true } diff --git a/ports/libsimpleservo/src/capi.rs b/ports/libsimpleservo/src/capi.rs index cbd4f36108c2..89ffe408759e 100644 --- a/ports/libsimpleservo/src/capi.rs +++ b/ports/libsimpleservo/src/capi.rs @@ -28,6 +28,7 @@ fn call(f: F) where F: Fn(&mut ServoGlue) -> Result<(), &'static str> { #[repr(C)] pub struct CHostCallbacks { pub flush: extern fn(), + pub make_current: extern fn(), pub on_load_started: extern fn(), pub on_load_ended: extern fn(), pub on_title_changed: extern fn(title: *const c_char), @@ -223,6 +224,11 @@ impl HostTrait for HostCallbacks { (self.0.flush)(); } + fn make_current(&self) { + debug!("make_current"); + (self.0.make_current)(); + } + fn on_load_started(&self) { debug!("on_load_ended"); (self.0.on_load_started)(); diff --git a/ports/libsimpleservo/src/jniapi.rs b/ports/libsimpleservo/src/jniapi.rs index 84649659e81a..1e338eb8569e 100644 --- a/ports/libsimpleservo/src/jniapi.rs +++ b/ports/libsimpleservo/src/jniapi.rs @@ -277,6 +277,13 @@ impl HostTrait for HostCallbacks { .unwrap(); } + fn make_current(&self) { + debug!("make_current"); + let env = self.jvm.get_env().unwrap(); + env.call_method(self.callbacks.as_obj(), "makeCurrent", "()V", &[]) + .unwrap(); + } + fn on_load_started(&self) { debug!("on_load_started"); let env = self.jvm.get_env().unwrap(); From c36b16546e21fb6b8173c1008e6081ac86c07737 Mon Sep 17 00:00:00 2001 From: Paul Rouget Date: Wed, 1 Aug 2018 16:35:22 +0800 Subject: [PATCH 2/2] Introduce ServoSurface --- ports/libsimpleservo/src/jniapi.rs | 54 +++-- .../java/com/mozilla/servo/MainActivity.java | 13 +- .../{NativeServo.java => JNIServo.java} | 51 +++-- .../java/com/mozilla/servoview/Servo.java | 173 ++++++++++++++++ .../mozilla/servoview/ServoGLRenderer.java | 32 --- .../com/mozilla/servoview/ServoSurface.java | 186 +++++++++++++++++ .../java/com/mozilla/servoview/ServoView.java | 188 ++++++++---------- 7 files changed, 506 insertions(+), 191 deletions(-) rename support/android/apk/servoview/src/main/java/com/mozilla/servoview/{NativeServo.java => JNIServo.java} (82%) create mode 100644 support/android/apk/servoview/src/main/java/com/mozilla/servoview/Servo.java delete mode 100644 support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoGLRenderer.java create mode 100644 support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoSurface.java diff --git a/ports/libsimpleservo/src/jniapi.rs b/ports/libsimpleservo/src/jniapi.rs index 1e338eb8569e..6f8653f774ed 100644 --- a/ports/libsimpleservo/src/jniapi.rs +++ b/ports/libsimpleservo/src/jniapi.rs @@ -36,21 +36,19 @@ where } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_version(env: JNIEnv, _class: JClass) -> jstring { +pub fn Java_com_mozilla_servoview_JNIServo_version(env: JNIEnv, _class: JClass) -> jstring { let v = api::servo_version(); let output = env.new_string(v).expect("Couldn't create java string"); output.into_inner() } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_init( +pub fn Java_com_mozilla_servoview_JNIServo_init( env: JNIEnv, _: JClass, activity: JObject, args: JString, url: JString, - wakeup_obj: JObject, - readfile_obj: JObject, callbacks_obj: JObject, width: jint, height: jint, @@ -80,9 +78,11 @@ pub fn Java_com_mozilla_servoview_NativeServo_init( Some(env.get_string(url).expect("Couldn't get java string").into()) }; - let wakeup = Box::new(WakeupCallback::new(wakeup_obj, &env)); - let readfile = Box::new(ReadFileCallback::new(readfile_obj, &env)); - let callbacks = Box::new(HostCallbacks::new(callbacks_obj, &env)); + let callbacks_ref = env.new_global_ref(callbacks_obj).unwrap(); + + let wakeup = Box::new(WakeupCallback::new(callbacks_ref.clone(), &env)); + let readfile = Box::new(ReadFileCallback::new(callbacks_ref.clone(), &env)); + let callbacks = Box::new(HostCallbacks::new(callbacks_ref, &env)); gl_glue::egl::init().and_then(|gl| { api::init( @@ -100,7 +100,7 @@ pub fn Java_com_mozilla_servoview_NativeServo_init( } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_setBatchMode( +pub fn Java_com_mozilla_servoview_JNIServo_setBatchMode( env: JNIEnv, _: JClass, batch: jboolean, @@ -110,7 +110,7 @@ pub fn Java_com_mozilla_servoview_NativeServo_setBatchMode( } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_resize( +pub fn Java_com_mozilla_servoview_JNIServo_resize( env: JNIEnv, _: JClass, width: jint, @@ -121,38 +121,38 @@ pub fn Java_com_mozilla_servoview_NativeServo_resize( } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_performUpdates(env: JNIEnv, _class: JClass) { +pub fn Java_com_mozilla_servoview_JNIServo_performUpdates(env: JNIEnv, _class: JClass) { debug!("performUpdates"); call(env, |s| s.perform_updates()); } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_loadUri(env: JNIEnv, _class: JClass, url: JString) { +pub fn Java_com_mozilla_servoview_JNIServo_loadUri(env: JNIEnv, _class: JClass, url: JString) { debug!("loadUri"); let url: String = env.get_string(url).unwrap().into(); call(env, |s| s.load_uri(&url)); } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_reload(env: JNIEnv, _class: JClass) { +pub fn Java_com_mozilla_servoview_JNIServo_reload(env: JNIEnv, _class: JClass) { debug!("reload"); call(env, |s| s.reload()); } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_goBack(env: JNIEnv, _class: JClass) { +pub fn Java_com_mozilla_servoview_JNIServo_goBack(env: JNIEnv, _class: JClass) { debug!("goBack"); call(env, |s| s.go_back()); } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_goForward(env: JNIEnv, _class: JClass) { +pub fn Java_com_mozilla_servoview_JNIServo_goForward(env: JNIEnv, _class: JClass) { debug!("goForward"); call(env, |s| s.go_forward()); } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_scrollStart( +pub fn Java_com_mozilla_servoview_JNIServo_scrollStart( env: JNIEnv, _: JClass, dx: jint, @@ -165,7 +165,7 @@ pub fn Java_com_mozilla_servoview_NativeServo_scrollStart( } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_scrollEnd( +pub fn Java_com_mozilla_servoview_JNIServo_scrollEnd( env: JNIEnv, _: JClass, dx: jint, @@ -179,7 +179,7 @@ pub fn Java_com_mozilla_servoview_NativeServo_scrollEnd( #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_scroll( +pub fn Java_com_mozilla_servoview_JNIServo_scroll( env: JNIEnv, _: JClass, dx: jint, @@ -192,7 +192,7 @@ pub fn Java_com_mozilla_servoview_NativeServo_scroll( } #[no_mangle] -pub fn Java_com_mozilla_servoview_NativeServo_click(env: JNIEnv, _: JClass, x: jint, y: jint) { +pub fn Java_com_mozilla_servoview_JNIServo_click(env: JNIEnv, _: JClass, x: jint, y: jint) { debug!("click"); call(env, |s| s.click(x as u32, y as u32)); } @@ -203,12 +203,9 @@ pub struct WakeupCallback { } impl WakeupCallback { - pub fn new(jobject: JObject, env: &JNIEnv) -> WakeupCallback { + pub fn new(callback: GlobalRef, env: &JNIEnv) -> WakeupCallback { let jvm = Arc::new(env.get_java_vm().unwrap()); - WakeupCallback { - callback: env.new_global_ref(jobject).unwrap(), - jvm, - } + WakeupCallback { callback, jvm } } } @@ -233,9 +230,9 @@ pub struct ReadFileCallback { } impl ReadFileCallback { - pub fn new(jobject: JObject, env: &JNIEnv) -> ReadFileCallback { + pub fn new(callback: GlobalRef, env: &JNIEnv) -> ReadFileCallback { let jvm = env.get_java_vm().unwrap(); - let callback = Mutex::new(env.new_global_ref(jobject).unwrap()); + let callback = Mutex::new(callback); ReadFileCallback { callback, jvm } } } @@ -260,12 +257,9 @@ impl ReadFileTrait for ReadFileCallback { } impl HostCallbacks { - pub fn new(jobject: JObject, env: &JNIEnv) -> HostCallbacks { + pub fn new(callbacks: GlobalRef, env: &JNIEnv) -> HostCallbacks { let jvm = env.get_java_vm().unwrap(); - HostCallbacks { - callbacks: env.new_global_ref(jobject).unwrap(), - jvm, - } + HostCallbacks { callbacks, jvm } } } diff --git a/support/android/apk/servoapp/src/main/java/com/mozilla/servo/MainActivity.java b/support/android/apk/servoapp/src/main/java/com/mozilla/servo/MainActivity.java index addad7873d5b..1d042151a3a2 100644 --- a/support/android/apk/servoapp/src/main/java/com/mozilla/servo/MainActivity.java +++ b/support/android/apk/servoapp/src/main/java/com/mozilla/servo/MainActivity.java @@ -20,10 +20,11 @@ import android.widget.ProgressBar; import com.mozilla.servoview.ServoView; +import com.mozilla.servoview.Servo; import java.io.File; -public class MainActivity extends Activity implements ServoView.Client { +public class MainActivity extends Activity implements Servo.Client { private static final String LOGTAG = "MainActivity"; @@ -49,10 +50,10 @@ protected void onCreate(Bundle savedInstanceState) { mUrlField = findViewById(R.id.urlfield); mProgressBar = findViewById(R.id.progressbar); - mServoView.setClient(this); mBackButton.setEnabled(false); mFwdButton.setEnabled(false); + mServoView.setClient(this); mServoView.requestFocus(); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { @@ -66,9 +67,7 @@ protected void onCreate(Bundle savedInstanceState) { } String args = getIntent().getStringExtra("servoargs"); - if (args != null) { - mServoView.setServoArgs(args); - } + mServoView.setServoArgs(args); setupUrlField(); } @@ -105,18 +104,16 @@ private void loadUrlFromField() { mServoView.loadUri(Uri.parse(uri)); } + // From activity_main.xml: public void onReloadClicked(View v) { mServoView.reload(); } - public void onBackClicked(View v) { mServoView.goBack(); } - public void onForwardClicked(View v) { mServoView.goForward(); } - public void onStopClicked(View v) { mServoView.stop(); } diff --git a/support/android/apk/servoview/src/main/java/com/mozilla/servoview/NativeServo.java b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/JNIServo.java similarity index 82% rename from support/android/apk/servoview/src/main/java/com/mozilla/servoview/NativeServo.java rename to support/android/apk/servoview/src/main/java/com/mozilla/servoview/JNIServo.java index 51f27b24d6f7..13c62fe93729 100644 --- a/support/android/apk/servoview/src/main/java/com/mozilla/servoview/NativeServo.java +++ b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/JNIServo.java @@ -10,48 +10,65 @@ /** * Maps /ports/libsimpleservo API */ -public class NativeServo { +@SuppressWarnings("JniMissingFunction") +public class JNIServo { + JNIServo() { + System.loadLibrary("c++_shared"); + System.loadLibrary("simpleservo"); + } + public native String version(); + public native void init(Activity activity, String args, String url, - WakeupCallback wakeup, - ReadFileCallback readfile, - ServoCallbacks callbacks, + Callbacks callbacks, int width, int height, boolean log); + public native void setBatchMode(boolean mode); + public native void performUpdates(); + public native void resize(int width, int height); + public native void reload(); + public native void stop(); + public native void goBack(); + public native void goForward(); + public native void loadUri(String uri); + public native void scrollStart(int dx, int dy, int x, int y); + public native void scroll(int dx, int dy, int x, int y); - public native void scrollEnd(int dx, int dy, int x, int y); - public native void click(int x, int y); - NativeServo() { - System.loadLibrary("c++_shared"); - System.loadLibrary("simpleservo"); - } + public native void scrollEnd(int dx, int dy, int x, int y); - public interface ReadFileCallback { - byte[] readfile(String file); - } + public native void click(int x, int y); - public interface WakeupCallback { + public interface Callbacks { void wakeup(); - } - public interface ServoCallbacks { void flush(); + + void makeCurrent(); + + void onAnimatingChanged(boolean animating); + void onLoadStarted(); + void onLoadEnded(); + void onTitleChanged(String title); + void onUrlChanged(String url); + void onHistoryChanged(boolean canGoBack, boolean canGoForward); - void onAnimatingChanged(boolean animating); + + byte[] readfile(String file); } } + diff --git a/support/android/apk/servoview/src/main/java/com/mozilla/servoview/Servo.java b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/Servo.java new file mode 100644 index 000000000000..3f07dbb50ac8 --- /dev/null +++ b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/Servo.java @@ -0,0 +1,173 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package com.mozilla.servoview; + +import android.app.Activity; +import android.content.res.AssetManager; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; + +public class Servo { + private static final String LOGTAG = "Servo"; + private AssetManager mAssetMgr; + private JNIServo mJNI = new JNIServo(); + private RunCallback mRunCallback; + + public Servo( + RunCallback runCallback, + GfxCallbacks gfxcb, + Client client, + Activity activity, + String args, String url, + int width, int height, boolean log) { + + mRunCallback = runCallback; + + mAssetMgr = activity.getResources().getAssets(); + + Callbacks cbs = new Callbacks(client, gfxcb); + + mRunCallback.inGLThread(() -> { + mJNI.init(activity, args, url, cbs, width, height, log); + }); + } + + public String version() { + return mJNI.version(); + } + + public void setBatchMode(boolean mode) { + mRunCallback.inGLThread(() -> mJNI.setBatchMode(mode)); + } + + public void resize(int width, int height) { + mRunCallback.inGLThread(() -> mJNI.resize(width, height)); + } + + public void reload() { + mRunCallback.inGLThread(() -> mJNI.reload()); + } + + public void stop() { + mRunCallback.inGLThread(() -> mJNI.stop()); + } + + public void goBack() { + mRunCallback.inGLThread(() -> mJNI.goBack()); + } + + public void goForward() { + mRunCallback.inGLThread(() -> mJNI.goForward()); + } + + public void loadUri(String uri) { + mRunCallback.inGLThread(() -> mJNI.loadUri(uri)); + } + + public void scrollStart(int dx, int dy, int x, int y) { + mRunCallback.inGLThread(() -> mJNI.scrollStart(dx, dy, x, y)); + } + + public void scroll(int dx, int dy, int x, int y) { + mRunCallback.inGLThread(() -> mJNI.scroll(dx, dy, x, y)); + } + + public void scrollEnd(int dx, int dy, int x, int y) { + mRunCallback.inGLThread(() -> mJNI.scrollEnd(dx, dy, x, y)); + } + + public void click(int x, int y) { + mRunCallback.inGLThread(() -> mJNI.click(x, y)); + } + + public interface Client { + void onLoadStarted(); + + void onLoadEnded(); + + void onTitleChanged(String title); + + void onUrlChanged(String url); + + void onHistoryChanged(boolean canGoBack, boolean canGoForward); + } + + public interface RunCallback { + void inGLThread(Runnable f); + + void inUIThread(Runnable f); + } + + public interface GfxCallbacks { + void flushGLBuffers(); + + void animationStateChanged(boolean animating); + + void makeCurrent(); + } + + private class Callbacks implements JNIServo.Callbacks, Client { + + private final GfxCallbacks mGfxCb; + Client mClient; + + Callbacks(Client client, GfxCallbacks gfxcb) { + mClient = client; + mGfxCb = gfxcb; + } + + public void wakeup() { + mRunCallback.inGLThread(() -> mJNI.performUpdates()); + } + + public void flush() { + mRunCallback.inUIThread(() -> mGfxCb.flushGLBuffers()); + } + + public void makeCurrent() { + mRunCallback.inUIThread(() -> mGfxCb.makeCurrent()); + } + + public void onAnimatingChanged(boolean animating) { + mRunCallback.inUIThread(() -> mGfxCb.animationStateChanged(animating)); + } + + public void onLoadStarted() { + mRunCallback.inUIThread(() -> mClient.onLoadStarted()); + } + + public void onLoadEnded() { + mRunCallback.inUIThread(() -> mClient.onLoadEnded()); + } + + public void onTitleChanged(String title) { + mRunCallback.inUIThread(() -> mClient.onTitleChanged(title)); + } + + public void onUrlChanged(String url) { + mRunCallback.inUIThread(() -> mClient.onUrlChanged(url)); + } + + public void onHistoryChanged(boolean canGoBack, boolean canGoForward) { + mRunCallback.inUIThread(() -> mClient.onHistoryChanged(canGoBack, canGoForward)); + } + + public byte[] readfile(String file) { + try { + InputStream stream = mAssetMgr.open(file); + byte[] bytes = new byte[stream.available()]; + stream.read(bytes); + stream.close(); + return bytes; + } catch (IOException e) { + Log.e(LOGTAG, e.getMessage()); + return null; + } + } + } +} diff --git a/support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoGLRenderer.java b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoGLRenderer.java deleted file mode 100644 index dc06c14e512a..000000000000 --- a/support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoGLRenderer.java +++ /dev/null @@ -1,32 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package com.mozilla.servoview; - -import android.opengl.GLES31; -import android.opengl.GLSurfaceView; -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; - -public class ServoGLRenderer implements GLSurfaceView.Renderer { - - private final ServoView mView; - - ServoGLRenderer(ServoView view) { - mView = view; - } - - public void onSurfaceCreated(GL10 unused, EGLConfig config) { - mView.onGLReady(); - } - - public void onDrawFrame(GL10 unused) { - } - - public void onSurfaceChanged(GL10 unused, int width, int height) { - GLES31.glViewport(0, 0, width, height); - mView.onSurfaceResized(width, height); - } -} diff --git a/support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoSurface.java b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoSurface.java new file mode 100644 index 000000000000..13547d43a939 --- /dev/null +++ b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoSurface.java @@ -0,0 +1,186 @@ +package com.mozilla.servoview; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.net.Uri; +import android.opengl.EGL14; +import android.opengl.EGLConfig; +import android.opengl.EGLContext; +import android.opengl.EGLDisplay; +import android.opengl.EGLSurface; +import android.opengl.GLUtils; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.Log; + +import com.mozilla.servoview.Servo.Client; +import com.mozilla.servoview.Servo.GfxCallbacks; +import com.mozilla.servoview.Servo.RunCallback; + +import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION; +import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT; + +public class ServoSurface { + private final GLThread mGLThread; + private final Handler mMainLooperHandler; + private Handler mGLLooperHandler; + private Surface mASurface; + private int mWidth; + private int mHeight; + private Servo mServo; + private Client mClient = null; + private String mServoArgs = ""; + private Uri mInitialUri = null; + private Activity mActivity; + + public ServoSurface(Surface surface, int width, int height) { + mWidth = width; + mHeight = height; + mASurface = surface; + mMainLooperHandler = new Handler(Looper.getMainLooper()); + mGLThread = new GLThread(); + } + + public void setClient(Client client) { + mClient = client; + } + + public void setServoArgs(String args) { + mServoArgs = args != null ? args : ""; + } + + public void setActivity(Activity activity) { + mActivity = activity; + } + + public void runLoop() { + mGLThread.start(); + } + + public void reload() { + mServo.reload(); + } + + public void goBack() { + mServo.goBack(); + } + + public void goForward() { + mServo.goForward(); + } + + public void stop() { + mServo.stop(); + } + + public void onSurfaceResized(int width, int height) { + mServo.resize(width, height); + } + + public void loadUri(Uri uri) { + if (mServo != null) { + mServo.loadUri(uri.toString()); + } else { + mInitialUri = uri; + } + } + + static class Surface implements GfxCallbacks { + private static final String LOGTAG = "ServoSurface"; + + private EGLConfig[] mEGLConfigs; + private EGLDisplay mEglDisplay; + private EGLContext mEglContext; + private EGLSurface mEglSurface; + + Surface(Surface surface) { + mEglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + int[] version = new int[2]; + if (!EGL14.eglInitialize(mEglDisplay, version, 0, version, 1)) { + throw new RuntimeException("Error: eglInitialize() Failed " + GLUtils.getEGLErrorString(EGL14.eglGetError())); + } + mEGLConfigs = new EGLConfig[1]; + int[] configsCount = new int[1]; + int[] configSpec = new int[]{ + EGL14.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL14.EGL_RED_SIZE, 8, + EGL14.EGL_GREEN_SIZE, 8, + EGL14.EGL_BLUE_SIZE, 8, + EGL14.EGL_ALPHA_SIZE, 8, + EGL14.EGL_DEPTH_SIZE, 0, + EGL14.EGL_STENCIL_SIZE, 0, + EGL14.EGL_NONE + }; + if ((!EGL14.eglChooseConfig(mEglDisplay, configSpec, 0, mEGLConfigs, 0, 1, configsCount, 0)) || (configsCount[0] == 0)) { + throw new IllegalArgumentException("Error: eglChooseConfig() Failed " + GLUtils.getEGLErrorString(EGL14.eglGetError())); + } + if (mEGLConfigs[0] == null) { + throw new RuntimeException("Error: eglConfig() not Initialized"); + } + int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL14.EGL_NONE}; + mEglContext = EGL14.eglCreateContext(mEglDisplay, mEGLConfigs[0], EGL14.EGL_NO_CONTEXT, attrib_list, 0); + int glError = EGL14.eglGetError(); + if (glError != EGL14.EGL_SUCCESS) { + throw new RuntimeException("Error: eglCreateContext() Failed " + GLUtils.getEGLErrorString(glError)); + } + mEglSurface = EGL14.eglCreateWindowSurface(mEglDisplay, mEGLConfigs[0], surface, new int[]{EGL14.EGL_NONE}, 0); + if (mEglSurface == null || mEglSurface == EGL14.EGL_NO_SURFACE) { + glError = EGL14.eglGetError(); + if (glError == EGL14.EGL_BAD_NATIVE_WINDOW) { + Log.e(LOGTAG, "Error: createWindowSurface() Returned EGL_BAD_NATIVE_WINDOW."); + return; + } + throw new RuntimeException("Error: createWindowSurface() Failed " + GLUtils.getEGLErrorString(glError)); + } + + flushGLBuffers(); + } + + + public void makeCurrent() { + if (!EGL14.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) { + throw new RuntimeException("Error: eglMakeCurrent() Failed " + GLUtils.getEGLErrorString(EGL14.eglGetError())); + } + } + + public void flushGLBuffers() { + EGL14.eglSwapBuffers(mEglDisplay, mEglSurface); + } + + public void animationStateChanged(boolean animating) { + // FIXME + } + + } + + class GLThread extends Thread implements RunCallback { + + public void inGLThread(Runnable r) { + mGLLooperHandler.post(r); + } + + public void inUIThread(Runnable r) { + mMainLooperHandler.post(r); + } + + // FIXME: HandlerLeak + @SuppressLint("HandlerLeak") + public void run() { + Looper.prepare(); + + Surface surface = new Surface(mASurface); + + final boolean showLogs = true; + String uri = mInitialUri == null ? null : mInitialUri.toString(); + mServo = new Servo(this, surface, mClient, mActivity, mServoArgs, uri, mWidth, mHeight, showLogs); + + mGLLooperHandler = new Handler() { + public void handleMessage(Message msg) { + } + }; + + Looper.loop(); + } + } +} diff --git a/support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoView.java b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoView.java index 1dbc76e28aeb..9999568a2a39 100644 --- a/support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoView.java +++ b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/ServoView.java @@ -7,28 +7,44 @@ import android.app.Activity; import android.content.Context; -import android.content.res.AssetManager; import android.net.Uri; +import android.opengl.GLES31; import android.opengl.GLSurfaceView; import android.util.AttributeSet; -import android.util.Log; import android.view.Choreographer; import android.view.GestureDetector; import android.view.MotionEvent; import android.widget.OverScroller; -import java.io.IOException; -import java.io.InputStream; -public class ServoView extends GLSurfaceView implements GestureDetector.OnGestureListener, Choreographer.FrameCallback { +import com.mozilla.servoview.Servo.Client; +import com.mozilla.servoview.Servo.GfxCallbacks; +import com.mozilla.servoview.Servo.RunCallback; + +import javax.microedition.khronos.egl.EGLConfig; +import javax.microedition.khronos.opengles.GL10; + +public class ServoView extends GLSurfaceView + implements + GestureDetector.OnGestureListener, + Choreographer.FrameCallback, + GfxCallbacks, + RunCallback { private static final String LOGTAG = "ServoView"; private Activity mActivity; - private NativeServo mServo; + private Servo mServo; private Client mClient = null; private Uri mInitialUri = null; private boolean mAnimating; private String mServoArgs = ""; + private GestureDetector mGestureDetector; + private OverScroller mScroller; + private int mLastX = 0; + private int mCurX = 0; + private int mLastY = 0; + private int mCurY = 0; + private boolean mFlinging; public ServoView(Context context, AttributeSet attrs) { super(context, attrs); @@ -40,149 +56,87 @@ public ServoView(Context context, AttributeSet attrs) { setEGLConfigChooser(8, 8, 8, 8, 24, 0); ServoGLRenderer mRenderer = new ServoGLRenderer(this); setRenderer(mRenderer); - mServo = new NativeServo(); setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); initGestures(context); } public void setServoArgs(String args) { - mServoArgs = args; + mServoArgs = args != null ? args : ""; } public void reload() { - queueEvent(() -> mServo.reload()); + mServo.reload(); } public void goBack() { - queueEvent(() -> mServo.goBack()); + mServo.goBack(); } public void goForward() { - queueEvent(() -> mServo.goForward()); + mServo.goForward(); } public void stop() { - queueEvent(() -> mServo.stop()); + mServo.stop(); } public void onSurfaceResized(int width, int height) { - queueEvent(() -> mServo.resize(width, height)); + if (mServo != null) { + mServo.resize(width, height); + } } public void loadUri(Uri uri) { if (mServo != null) { - queueEvent(() -> mServo.loadUri(uri.toString())); + mServo.loadUri(uri.toString()); } else { mInitialUri = uri; } } - class WakeupCallback implements NativeServo.WakeupCallback { - public void wakeup() { - queueEvent(() -> mServo.performUpdates()); - }; - } - - class ReadFileCallback implements NativeServo.ReadFileCallback { - public byte[] readfile(String file) { - try { - AssetManager assetMgr = getContext().getResources().getAssets(); - InputStream stream = assetMgr.open(file); - byte[] bytes = new byte[stream.available()]; - stream.read(bytes); - stream.close(); - return bytes; - } catch (IOException e) { - Log.e(LOGTAG, e.getMessage()); - return null; - } - } + public void flushGLBuffers() { + requestRender(); } - class ServoCallbacks implements NativeServo.ServoCallbacks { - public void flush() { - requestRender(); - } - - public void onLoadStarted() { - if (mClient != null) { - post(() -> mClient.onLoadStarted()); - } - } - - public void onLoadEnded() { - if (mClient != null) { - post(() -> mClient.onLoadEnded()); - } - } + // Scroll and click - public void onTitleChanged(final String title) { - if (mClient != null) { - post(() -> mClient.onTitleChanged(title)); - } + public void animationStateChanged(boolean animating) { + if (!mAnimating && animating) { + post(() -> Choreographer.getInstance().postFrameCallback(ServoView.this)); } + mAnimating = animating; + } - public void onUrlChanged(final String url) { - if (mClient != null) { - post(() -> mClient.onUrlChanged(url)); - } - } + public void makeCurrent() { + } - public void onHistoryChanged(final boolean canGoBack, final boolean canGoForward) { - if (mClient != null) { - post(() -> mClient.onHistoryChanged(canGoBack, canGoForward)); - } - } + public void inGLThread(Runnable f) { + queueEvent(f); + } - public void onAnimatingChanged(final boolean animating) { - if (!mAnimating && animating) { - post(() -> Choreographer.getInstance().postFrameCallback(ServoView.this)); - } - mAnimating = animating; - } + public void inUIThread(Runnable f) { + post(f); } public void onGLReady() { - final WakeupCallback c1 = new WakeupCallback(); - final ReadFileCallback c2 = new ReadFileCallback(); - final ServoCallbacks c3 = new ServoCallbacks(); final boolean showLogs = true; int width = getWidth(); int height = getHeight(); - queueEvent(() -> { + inGLThread(() -> { String uri = mInitialUri == null ? null : mInitialUri.toString(); - mServo.init(mActivity, mServoArgs, uri, c1, c2, c3, width, height, showLogs); + mServo = new Servo(this, this, mClient, mActivity, mServoArgs, uri, width, height, showLogs); }); } - public interface Client { - void onLoadStarted(); - void onLoadEnded(); - void onTitleChanged(String title); - void onUrlChanged(String url); - void onHistoryChanged(boolean canGoBack, boolean canGoForward); - } - public void setClient(Client client) { mClient = client; } - // Scroll and click - - private GestureDetector mGestureDetector; - private OverScroller mScroller; - private int mLastX = 0; - private int mCurX = 0; - private int mLastY = 0; - private int mCurY = 0; - private boolean mFlinging; - private void initGestures(Context context) { mGestureDetector = new GestureDetector(context, this); mScroller = new OverScroller(context); } - @Override public void doFrame(long frameTimeNanos) { if (mScroller.isFinished() && mFlinging) { @@ -229,7 +183,7 @@ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float ve mLastX = mCurX; mCurY = velocityY < 0 ? mPageHeight : 0; mLastY = mCurY; - mScroller.fling(mCurX, mCurY, (int)velocityX, (int)velocityY, 0, mPageWidth, 0, mPageHeight); + mScroller.fling(mCurX, mCurY, (int) velocityX, (int) velocityY, 0, mPageWidth, 0, mPageHeight); return true; } @@ -242,19 +196,19 @@ public boolean onTouchEvent(final MotionEvent e) { mGestureDetector.onTouchEvent(e); int action = e.getActionMasked(); - switch(action) { + switch (action) { case (MotionEvent.ACTION_DOWN): - mCurX = (int)e.getX(); + mCurX = (int) e.getX(); mLastX = mCurX; - mCurY = (int)e.getY(); + mCurY = (int) e.getY(); mLastY = mCurY; mScroller.forceFinished(true); queueEvent(() -> mServo.scrollStart(0, 0, mCurX, mCurY)); Choreographer.getInstance().postFrameCallback(this); return true; case (MotionEvent.ACTION_MOVE): - mCurX = (int)e.getX(); - mCurY = (int)e.getY(); + mCurX = (int) e.getX(); + mCurY = (int) e.getY(); return true; case (MotionEvent.ACTION_UP): case (MotionEvent.ACTION_CANCEL): @@ -269,12 +223,38 @@ public boolean onTouchEvent(final MotionEvent e) { } public boolean onSingleTapUp(MotionEvent e) { - queueEvent(() -> mServo.click((int)e.getX(), (int)e.getY())); + queueEvent(() -> mServo.click((int) e.getX(), (int) e.getY())); return false; } - public void onLongPress(MotionEvent e) { } - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return true; } - public void onShowPress(MotionEvent e) { } + public void onLongPress(MotionEvent e) { + } + + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + return true; + } + + public void onShowPress(MotionEvent e) { + } + + static class ServoGLRenderer implements Renderer { + private final ServoView mView; + + ServoGLRenderer(ServoView view) { + mView = view; + } + + public void onSurfaceCreated(GL10 unused, EGLConfig config) { + mView.onGLReady(); + } + + public void onDrawFrame(GL10 unused) { + } + + public void onSurfaceChanged(GL10 unused, int width, int height) { + GLES31.glViewport(0, 0, width, height); + mView.onSurfaceResized(width, height); + } + } }