pinch to zoom

This commit is contained in:
Paul Rouget 2018-08-16 13:35:21 +02:00
parent 89ab110357
commit 296b76070c
6 changed files with 157 additions and 19 deletions

View file

@ -286,6 +286,24 @@ impl ServoGlue {
self.process_event(event) 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. /// Perform a click.
pub fn click(&mut self, x: u32, y: u32) -> Result<(), &'static str> { pub fn click(&mut self, x: u32, y: u32) -> Result<(), &'static str> {
let mouse_event = let mouse_event =

View file

@ -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)); 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] #[no_mangle]
pub extern "C" fn click(x: i32, y: i32) { pub extern "C" fn click(x: i32, y: i32) {
debug!("click"); debug!("click");

View file

@ -9,7 +9,7 @@ use api::{self, EventLoopWaker, ServoGlue, SERVO, HostTrait, ReadFileTrait};
use gl_glue; use gl_glue;
use jni::{JNIEnv, JavaVM}; use jni::{JNIEnv, JavaVM};
use jni::objects::{GlobalRef, JClass, JObject, JString, JValue}; 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 log::Level;
use std; use std;
use std::os::raw::c_void; 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)); 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] #[no_mangle]
pub fn Java_com_mozilla_servoview_JNIServo_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"); debug!("click");

View file

@ -49,6 +49,12 @@ public class JNIServo {
public native void scrollEnd(int dx, int dy, int x, int y); 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 native void click(int x, int y);
public interface Callbacks { public interface Callbacks {

View file

@ -86,6 +86,18 @@ public class Servo {
mRunCallback.inGLThread(() -> mJNI.scrollEnd(dx, dy, x, y)); 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) { public void click(int x, int y) {
mRunCallback.inGLThread(() -> mJNI.click(x, y)); mRunCallback.inGLThread(() -> mJNI.click(x, y));
} }

View file

@ -11,9 +11,11 @@ import android.net.Uri;
import android.opengl.GLES31; import android.opengl.GLES31;
import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.view.Choreographer; import android.view.Choreographer;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.widget.OverScroller; import android.widget.OverScroller;
import com.mozilla.servoview.Servo.Client; import com.mozilla.servoview.Servo.Client;
@ -26,6 +28,7 @@ import javax.microedition.khronos.opengles.GL10;
public class ServoView extends GLSurfaceView public class ServoView extends GLSurfaceView
implements implements
GestureDetector.OnGestureListener, GestureDetector.OnGestureListener,
ScaleGestureDetector.OnScaleGestureListener,
Choreographer.FrameCallback, Choreographer.FrameCallback,
GfxCallbacks, GfxCallbacks,
RunCallback { RunCallback {
@ -39,12 +42,18 @@ public class ServoView extends GLSurfaceView
private boolean mAnimating; private boolean mAnimating;
private String mServoArgs = ""; private String mServoArgs = "";
private GestureDetector mGestureDetector; private GestureDetector mGestureDetector;
private ScaleGestureDetector mScaleGestureDetector;
private OverScroller mScroller; private OverScroller mScroller;
private int mLastX = 0; private int mLastX = 0;
private int mCurX = 0; private int mCurX = 0;
private int mLastY = 0; private int mLastY = 0;
private int mCurY = 0; private int mCurY = 0;
private boolean mFlinging; private boolean mFlinging;
private boolean mScrolling;
private boolean mZooming;
private float mZoomFactor = 1;
public ServoView(Context context, AttributeSet attrs) { public ServoView(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
@ -138,19 +147,18 @@ public class ServoView extends GLSurfaceView
private void initGestures(Context context) { private void initGestures(Context context) {
mGestureDetector = new GestureDetector(context, this); mGestureDetector = new GestureDetector(context, this);
mScaleGestureDetector = new ScaleGestureDetector(context, this);
mScroller = new OverScroller(context); mScroller = new OverScroller(context);
} }
public void doFrame(long frameTimeNanos) { 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; mFlinging = false;
inGLThread(() -> mServo.scrollEnd(0, 0, mCurX, mCurY)); mScrolling = false;
if (!mAnimating) { mServo.scrollEnd(0, 0, mCurX, mCurY);
// Not scrolling. Not animating. We don't need to schedule
// another frame.
return;
}
} }
if (mFlinging) { if (mFlinging) {
@ -165,15 +173,25 @@ public class ServoView extends GLSurfaceView
mLastX = mCurX; mLastX = mCurX;
mLastY = mCurY; mLastY = mCurY;
if (dx != 0 || dy != 0) { boolean scrollNecessary = mScrolling && (dx != 0 || dy != 0);
inGLThread(() -> mServo.scroll(dx, dy, mCurX, mCurY)); boolean zoomNecessary = mZooming && mZoomFactor != 1;
} else {
if (mAnimating) { if (scrollNecessary) {
requestRender(); 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) { 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) { public boolean onTouchEvent(final MotionEvent e) {
mGestureDetector.onTouchEvent(e); mGestureDetector.onTouchEvent(e);
mScaleGestureDetector.onTouchEvent(e);
int action = e.getActionMasked(); int action = e.getActionMasked();
switch (action) { switch (action) {
@ -207,7 +226,8 @@ public class ServoView extends GLSurfaceView
mCurY = (int) e.getY(); mCurY = (int) e.getY();
mLastY = mCurY; mLastY = mCurY;
mScroller.forceFinished(true); mScroller.forceFinished(true);
inGLThread(() -> mServo.scrollStart(0, 0, mCurX, mCurY)); mServo.scrollStart(0, 0, mCurX, mCurY);
mScrolling = true;
Choreographer.getInstance().postFrameCallback(this); Choreographer.getInstance().postFrameCallback(this);
return true; return true;
case (MotionEvent.ACTION_MOVE): case (MotionEvent.ACTION_MOVE):
@ -217,8 +237,8 @@ public class ServoView extends GLSurfaceView
case (MotionEvent.ACTION_UP): case (MotionEvent.ACTION_UP):
case (MotionEvent.ACTION_CANCEL): case (MotionEvent.ACTION_CANCEL):
if (!mFlinging) { if (!mFlinging) {
inGLThread(() -> mServo.scrollEnd(0, 0, mCurX, mCurY)); mScrolling = false;
Choreographer.getInstance().removeFrameCallback(this); mServo.scrollEnd(0, 0, mCurX, mCurY);
} }
return true; return true;
default: default:
@ -227,7 +247,7 @@ public class ServoView extends GLSurfaceView
} }
public boolean onSingleTapUp(MotionEvent e) { public boolean onSingleTapUp(MotionEvent e) {
inGLThread(() -> mServo.click((int) e.getX(), (int) e.getY())); mServo.click((int) e.getX(), (int) e.getY());
return false; return false;
} }
@ -241,6 +261,33 @@ public class ServoView extends GLSurfaceView
public void onShowPress(MotionEvent e) { 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 @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();