mirror of
https://github.com/servo/servo.git
synced 2025-07-16 03:43:38 +01:00
Auto merge of #21234 - paulrouget:surface, r=MortimerGoro
Android: Introduce ServoSurface (WIP as it depends on 2 other PRs) Depends on #21199. Only last commit matters. r? @MortimerGoro Please look at ServoSurface.java. The rest is mostly some refactoring to share as much code as possible with ServoView. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21234) <!-- Reviewable:end -->
This commit is contained in:
commit
733552d997
9 changed files with 544 additions and 212 deletions
|
@ -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.
|
||||
|
@ -355,6 +358,7 @@ impl WindowMethods for ServoCallbacks {
|
|||
_height: Length<u32, DevicePixel>,
|
||||
) -> bool {
|
||||
debug!("WindowMethods::prepare_for_composite");
|
||||
self.host_callbacks.make_current();
|
||||
true
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ fn call<F>(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)();
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -277,6 +271,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();
|
||||
|
|
|
@ -20,10 +20,11 @@ import android.widget.EditText;
|
|||
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 @@ public class MainActivity extends Activity implements ServoView.Client {
|
|||
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 @@ public class MainActivity extends Activity implements ServoView.Client {
|
|||
}
|
||||
|
||||
String args = getIntent().getStringExtra("servoargs");
|
||||
if (args != null) {
|
||||
mServoView.setServoArgs(args);
|
||||
}
|
||||
mServoView.setServoArgs(args);
|
||||
|
||||
setupUrlField();
|
||||
}
|
||||
|
@ -105,18 +104,16 @@ public class MainActivity extends Activity implements ServoView.Client {
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -10,48 +10,65 @@ import android.app.Activity;
|
|||
/**
|
||||
* Maps /ports/libsimpleservo API
|
||||
*/
|
||||
public class NativeServo {
|
||||
public native String version();
|
||||
public native void init(Activity activity,
|
||||
String args,
|
||||
String url,
|
||||
WakeupCallback wakeup,
|
||||
ReadFileCallback readfile,
|
||||
ServoCallbacks 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() {
|
||||
@SuppressWarnings("JniMissingFunction")
|
||||
public class JNIServo {
|
||||
JNIServo() {
|
||||
System.loadLibrary("c++_shared");
|
||||
System.loadLibrary("simpleservo");
|
||||
}
|
||||
|
||||
public interface ReadFileCallback {
|
||||
public native String version();
|
||||
|
||||
public native void init(Activity activity,
|
||||
String args,
|
||||
String url,
|
||||
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);
|
||||
|
||||
public interface Callbacks {
|
||||
void wakeup();
|
||||
|
||||
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);
|
||||
|
||||
byte[] readfile(String file);
|
||||
}
|
||||
|
||||
public interface WakeupCallback {
|
||||
void wakeup();
|
||||
}
|
||||
|
||||
public interface ServoCallbacks {
|
||||
void flush();
|
||||
void onLoadStarted();
|
||||
void onLoadEnded();
|
||||
void onTitleChanged(String title);
|
||||
void onUrlChanged(String url);
|
||||
void onHistoryChanged(boolean canGoBack, boolean canGoForward);
|
||||
void onAnimatingChanged(boolean animating);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,28 +7,44 @@ package com.mozilla.servoview;
|
|||
|
||||
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 class ServoView extends GLSurfaceView implements GestureDetector.OnGestur
|
|||
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());
|
||||
};
|
||||
public void flushGLBuffers() {
|
||||
requestRender();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// Scroll and click
|
||||
|
||||
public void animationStateChanged(boolean animating) {
|
||||
if (!mAnimating && animating) {
|
||||
post(() -> Choreographer.getInstance().postFrameCallback(ServoView.this));
|
||||
}
|
||||
mAnimating = animating;
|
||||
}
|
||||
|
||||
class ServoCallbacks implements NativeServo.ServoCallbacks {
|
||||
public void flush() {
|
||||
requestRender();
|
||||
}
|
||||
public void makeCurrent() {
|
||||
}
|
||||
|
||||
public void onLoadStarted() {
|
||||
if (mClient != null) {
|
||||
post(() -> mClient.onLoadStarted());
|
||||
}
|
||||
}
|
||||
public void inGLThread(Runnable f) {
|
||||
queueEvent(f);
|
||||
}
|
||||
|
||||
public void onLoadEnded() {
|
||||
if (mClient != null) {
|
||||
post(() -> mClient.onLoadEnded());
|
||||
}
|
||||
}
|
||||
|
||||
public void onTitleChanged(final String title) {
|
||||
if (mClient != null) {
|
||||
post(() -> mClient.onTitleChanged(title));
|
||||
}
|
||||
}
|
||||
|
||||
public void onUrlChanged(final String url) {
|
||||
if (mClient != null) {
|
||||
post(() -> mClient.onUrlChanged(url));
|
||||
}
|
||||
}
|
||||
|
||||
public void onHistoryChanged(final boolean canGoBack, final boolean canGoForward) {
|
||||
if (mClient != null) {
|
||||
post(() -> mClient.onHistoryChanged(canGoBack, canGoForward));
|
||||
}
|
||||
}
|
||||
|
||||
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 class ServoView extends GLSurfaceView implements GestureDetector.OnGestur
|
|||
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 class ServoView extends GLSurfaceView implements GestureDetector.OnGestur
|
|||
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 class ServoView extends GLSurfaceView implements GestureDetector.OnGestur
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue