From 296b76070c30f42335f69e993b6391e3d5c81471 Mon Sep 17 00:00:00 2001 From: Paul Rouget Date: Thu, 16 Aug 2018 13:35:21 +0200 Subject: [PATCH 1/2] pinch to zoom --- ports/libsimpleservo/src/api.rs | 18 ++++ ports/libsimpleservo/src/capi.rs | 18 ++++ ports/libsimpleservo/src/jniapi.rs | 39 ++++++++- .../java/com/mozilla/servoview/JNIServo.java | 6 ++ .../java/com/mozilla/servoview/Servo.java | 12 +++ .../java/com/mozilla/servoview/ServoView.java | 83 +++++++++++++++---- 6 files changed, 157 insertions(+), 19 deletions(-) diff --git a/ports/libsimpleservo/src/api.rs b/ports/libsimpleservo/src/api.rs index cdaa4a67cf2..4e904d698f1 100644 --- a/ports/libsimpleservo/src/api.rs +++ b/ports/libsimpleservo/src/api.rs @@ -286,6 +286,24 @@ impl ServoGlue { self.process_event(event) } + /// Start pinchzoom. + /// x/y are pinch origin coordinates. + pub fn pinchzoom_start(&mut self, factor: f32, _x: u32, _y: u32) -> Result<(), &'static str> { + self.process_event(WindowEvent::PinchZoom(factor)) + } + + /// Pinchzoom. + /// x/y are pinch origin coordinates. + pub fn pinchzoom(&mut self, factor: f32, _x: u32, _y: u32) -> Result<(), &'static str> { + self.process_event(WindowEvent::PinchZoom(factor)) + } + + /// End pinchzoom. + /// x/y are pinch origin coordinates. + pub fn pinchzoom_end(&mut self, factor: f32, _x: u32, _y: u32) -> Result<(), &'static str> { + self.process_event(WindowEvent::PinchZoom(factor)) + } + /// Perform a click. pub fn click(&mut self, x: u32, y: u32) -> Result<(), &'static str> { let mouse_event = diff --git a/ports/libsimpleservo/src/capi.rs b/ports/libsimpleservo/src/capi.rs index 3edadc81dd5..dafa49373ef 100644 --- a/ports/libsimpleservo/src/capi.rs +++ b/ports/libsimpleservo/src/capi.rs @@ -180,6 +180,24 @@ pub extern "C" fn scroll(dx: i32, dy: i32, x: i32, y: i32) { call(|s| s.scroll(dx as i32, dy as i32, x as u32, y as u32)); } +#[no_mangle] +pub extern "C" fn pinchzoom_start(factor: f32, x: i32, y: i32) { + debug!("pinchzoom_start"); + call(|s| s.pinchzoom_start(factor, x as u32, y as u32)); +} + +#[no_mangle] +pub extern "C" fn pinchzoom(factor: f32, x: i32, y: i32) { + debug!("pinchzoom"); + call(|s| s.pinchzoom(factor, x as u32, y as u32)); +} + +#[no_mangle] +pub extern "C" fn pinchzoom_end(factor: f32, x: i32, y: i32) { + debug!("pinchzoom_end"); + call(|s| s.pinchzoom_end(factor, x as u32, y as u32)); +} + #[no_mangle] pub extern "C" fn click(x: i32, y: i32) { debug!("click"); diff --git a/ports/libsimpleservo/src/jniapi.rs b/ports/libsimpleservo/src/jniapi.rs index 2367b685d47..26817bd4561 100644 --- a/ports/libsimpleservo/src/jniapi.rs +++ b/ports/libsimpleservo/src/jniapi.rs @@ -9,7 +9,7 @@ use api::{self, EventLoopWaker, ServoGlue, SERVO, HostTrait, ReadFileTrait}; use gl_glue; use jni::{JNIEnv, JavaVM}; use jni::objects::{GlobalRef, JClass, JObject, JString, JValue}; -use jni::sys::{jboolean, jint, jstring, JNI_TRUE}; +use jni::sys::{jboolean, jfloat, jint, jstring, JNI_TRUE}; use log::Level; use std; use std::os::raw::c_void; @@ -207,6 +207,43 @@ pub fn Java_com_mozilla_servoview_JNIServo_scroll( call(env, |s| s.scroll(dx as i32, dy as i32, x as u32, y as u32)); } +#[no_mangle] +pub fn Java_com_mozilla_servoview_JNIServo_pinchZoomStart( + env: JNIEnv, + _: JClass, + factor: jfloat, + x: jint, + y: jint, +) { + debug!("pinchZoomStart"); + call(env, |s| s.pinchzoom_start(factor as f32, x as u32, y as u32)); +} + +#[no_mangle] +pub fn Java_com_mozilla_servoview_JNIServo_pinchZoom( + env: JNIEnv, + _: JClass, + factor: jfloat, + x: jint, + y: jint, +) { + debug!("pinchZoom"); + call(env, |s| s.pinchzoom(factor as f32, x as u32, y as u32)); +} + +#[no_mangle] +pub fn Java_com_mozilla_servoview_JNIServo_pinchZoomEnd( + env: JNIEnv, + _: JClass, + factor: jfloat, + x: jint, + y: jint, +) { + debug!("pinchZoomEnd"); + call(env, |s| s.pinchzoom_end(factor as f32, x as u32, y as u32)); +} + + #[no_mangle] pub fn Java_com_mozilla_servoview_JNIServo_click(env: JNIEnv, _: JClass, x: jint, y: jint) { debug!("click"); diff --git a/support/android/apk/servoview/src/main/java/com/mozilla/servoview/JNIServo.java b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/JNIServo.java index aa8125038fa..a740f474af1 100644 --- a/support/android/apk/servoview/src/main/java/com/mozilla/servoview/JNIServo.java +++ b/support/android/apk/servoview/src/main/java/com/mozilla/servoview/JNIServo.java @@ -49,6 +49,12 @@ public class JNIServo { public native void scrollEnd(int dx, int dy, int x, int y); + public native void pinchZoomStart(float factor, int x, int y); + + public native void pinchZoom(float factor, int x, int y); + + public native void pinchZoomEnd(float factor, int x, int y); + public native void click(int x, int y); public interface Callbacks { 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 index e125d245d75..d517aaf1438 100644 --- 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 @@ -86,6 +86,18 @@ public class Servo { mRunCallback.inGLThread(() -> mJNI.scrollEnd(dx, dy, x, y)); } + public void pinchZoomStart(float factor, int x, int y) { + mRunCallback.inGLThread(() -> mJNI.pinchZoomStart(factor, x, y)); + } + + public void pinchZoom(float factor, int x, int y) { + mRunCallback.inGLThread(() -> mJNI.pinchZoom(factor, x, y)); + } + + public void pinchZoomEnd(float factor, int x, int y) { + mRunCallback.inGLThread(() -> mJNI.pinchZoomEnd(factor, x, y)); + } + public void click(int x, int y) { mRunCallback.inGLThread(() -> mJNI.click(x, y)); } 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 0424d84ebe0..ffc0c4504b7 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 @@ -11,9 +11,11 @@ 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.view.ScaleGestureDetector; import android.widget.OverScroller; import com.mozilla.servoview.Servo.Client; @@ -26,6 +28,7 @@ import javax.microedition.khronos.opengles.GL10; public class ServoView extends GLSurfaceView implements GestureDetector.OnGestureListener, + ScaleGestureDetector.OnScaleGestureListener, Choreographer.FrameCallback, GfxCallbacks, RunCallback { @@ -39,12 +42,18 @@ public class ServoView extends GLSurfaceView private boolean mAnimating; private String mServoArgs = ""; private GestureDetector mGestureDetector; + private ScaleGestureDetector mScaleGestureDetector; + private OverScroller mScroller; private int mLastX = 0; private int mCurX = 0; private int mLastY = 0; private int mCurY = 0; private boolean mFlinging; + private boolean mScrolling; + + private boolean mZooming; + private float mZoomFactor = 1; public ServoView(Context context, AttributeSet attrs) { super(context, attrs); @@ -138,19 +147,18 @@ public class ServoView extends GLSurfaceView private void initGestures(Context context) { mGestureDetector = new GestureDetector(context, this); + mScaleGestureDetector = new ScaleGestureDetector(context, this); mScroller = new OverScroller(context); } public void doFrame(long frameTimeNanos) { - if (mScroller.isFinished() && mFlinging) { + // 3 reasons to be here: animating or scrolling/flinging or pinching + + if (mFlinging && mScroller.isFinished()) { mFlinging = false; - inGLThread(() -> mServo.scrollEnd(0, 0, mCurX, mCurY)); - if (!mAnimating) { - // Not scrolling. Not animating. We don't need to schedule - // another frame. - return; - } + mScrolling = false; + mServo.scrollEnd(0, 0, mCurX, mCurY); } if (mFlinging) { @@ -165,15 +173,25 @@ public class ServoView extends GLSurfaceView mLastX = mCurX; mLastY = mCurY; - if (dx != 0 || dy != 0) { - inGLThread(() -> mServo.scroll(dx, dy, mCurX, mCurY)); - } else { - if (mAnimating) { - requestRender(); - } + boolean scrollNecessary = mScrolling && (dx != 0 || dy != 0); + boolean zoomNecessary = mZooming && mZoomFactor != 1; + + if (scrollNecessary) { + mServo.scroll(dx, dy, mCurX, mCurY); } - Choreographer.getInstance().postFrameCallback(this); + if (zoomNecessary) { + mServo.pinchZoom(mZoomFactor, 0, 0); + mZoomFactor = 1; + } + + if (!zoomNecessary && !scrollNecessary && mAnimating) { + requestRender(); + } + + if (mZooming || mScrolling || mAnimating) { + Choreographer.getInstance().postFrameCallback(this); + } } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { @@ -198,6 +216,7 @@ public class ServoView extends GLSurfaceView public boolean onTouchEvent(final MotionEvent e) { mGestureDetector.onTouchEvent(e); + mScaleGestureDetector.onTouchEvent(e); int action = e.getActionMasked(); switch (action) { @@ -207,7 +226,8 @@ public class ServoView extends GLSurfaceView mCurY = (int) e.getY(); mLastY = mCurY; mScroller.forceFinished(true); - inGLThread(() -> mServo.scrollStart(0, 0, mCurX, mCurY)); + mServo.scrollStart(0, 0, mCurX, mCurY); + mScrolling = true; Choreographer.getInstance().postFrameCallback(this); return true; case (MotionEvent.ACTION_MOVE): @@ -217,8 +237,8 @@ public class ServoView extends GLSurfaceView case (MotionEvent.ACTION_UP): case (MotionEvent.ACTION_CANCEL): if (!mFlinging) { - inGLThread(() -> mServo.scrollEnd(0, 0, mCurX, mCurY)); - Choreographer.getInstance().removeFrameCallback(this); + mScrolling = false; + mServo.scrollEnd(0, 0, mCurX, mCurY); } return true; default: @@ -227,7 +247,7 @@ public class ServoView extends GLSurfaceView } public boolean onSingleTapUp(MotionEvent e) { - inGLThread(() -> mServo.click((int) e.getX(), (int) e.getY())); + mServo.click((int) e.getX(), (int) e.getY()); return false; } @@ -241,6 +261,33 @@ public class ServoView extends GLSurfaceView public void onShowPress(MotionEvent e) { } + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + if (mScroller.isFinished()) { + mZoomFactor = detector.getScaleFactor(); + mZooming = true; + mServo.pinchZoomStart(mZoomFactor, 0, 0); + Choreographer.getInstance().postFrameCallback(this); + return true; + } else { + return false; + } + } + + @Override + public boolean onScale(ScaleGestureDetector detector) { + mZoomFactor *= detector.getScaleFactor(); + return true; + } + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + mZoomFactor = detector.getScaleFactor(); + mZooming = false; + mServo.pinchZoomEnd(mZoomFactor, 0, 0); + } + + @Override public void onPause() { super.onPause(); From 6aa653a46dd8774ceb01e24a004551b57d98937b Mon Sep 17 00:00:00 2001 From: Paul Rouget Date: Thu, 16 Aug 2018 13:35:38 +0200 Subject: [PATCH 2/2] Show animation status --- .../src/main/java/com/mozilla/servo/MainActivity.java | 11 +++++++++++ .../servoapp/src/main/res/layout/activity_main.xml | 11 +++++++++++ .../src/main/java/com/mozilla/servoview/Servo.java | 6 ++++++ .../main/java/com/mozilla/servoview/ServoView.java | 9 +++++++++ 4 files changed, 37 insertions(+) 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 794e8ae5564..15a0d49e0c8 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 @@ -18,6 +18,7 @@ import android.webkit.URLUtil; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; +import android.widget.TextView; import com.mozilla.servoview.ServoView; import com.mozilla.servoview.Servo; @@ -35,6 +36,7 @@ public class MainActivity extends Activity implements Servo.Client { Button mStopButton; EditText mUrlField; ProgressBar mProgressBar; + TextView mIdleText; @Override @@ -49,6 +51,7 @@ public class MainActivity extends Activity implements Servo.Client { mStopButton = findViewById(R.id.stopbutton); mUrlField = findViewById(R.id.urlfield); mProgressBar = findViewById(R.id.progressbar); + mIdleText = findViewById(R.id.redrawing); mBackButton.setEnabled(false); mFwdButton.setEnabled(false); @@ -151,6 +154,14 @@ public class MainActivity extends Activity implements Servo.Client { mFwdButton.setEnabled(canGoForward); } + public void onRedrawing(boolean redrawing) { + if (redrawing) { + mIdleText.setText("LOOP"); + } else { + mIdleText.setText("IDLE"); + } + } + @Override public void onPause() { mServoView.onPause(); diff --git a/support/android/apk/servoapp/src/main/res/layout/activity_main.xml b/support/android/apk/servoapp/src/main/res/layout/activity_main.xml index 2d8fab9c663..b8ae7fb94c3 100644 --- a/support/android/apk/servoapp/src/main/res/layout/activity_main.xml +++ b/support/android/apk/servoapp/src/main/res/layout/activity_main.xml @@ -82,6 +82,17 @@ android:text="Rld" android:textSize="10sp" /> + + mClient.onHistoryChanged(canGoBack, canGoForward)); } + public void onRedrawing(boolean redrawing) { + mRunCallback.inUIThread(() -> mClient.onRedrawing(redrawing)); + } + public byte[] readfile(String file) { try { InputStream stream = mAssetMgr.open(file); 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 ffc0c4504b7..c886b44ea4a 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 @@ -55,6 +55,8 @@ public class ServoView extends GLSurfaceView private boolean mZooming; private float mZoomFactor = 1; + private boolean mRedrawing; + public ServoView(Context context, AttributeSet attrs) { super(context, attrs); mActivity = (Activity) context; @@ -152,6 +154,10 @@ public class ServoView extends GLSurfaceView } public void doFrame(long frameTimeNanos) { + if (!mRedrawing) { + mRedrawing = true; + mClient.onRedrawing(mRedrawing); + } // 3 reasons to be here: animating or scrolling/flinging or pinching @@ -191,6 +197,9 @@ public class ServoView extends GLSurfaceView if (mZooming || mScrolling || mAnimating) { Choreographer.getInstance().postFrameCallback(this); + } else { + mRedrawing = false; + mClient.onRedrawing(mRedrawing); } }