mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Auto merge of #21431 - paulrouget:pinchtozoom, r=jdm
Pinch to zoom Implement pinch to zoom. Also, I added a marker in the toolbar to show if Servo is redrawing or not. The label switches from "IDLE" to "LOOP" when Servo is looping (at 60FPS) to redraw the page. Redrawing is necessary for 3 reasons: - a CSS animation is ongoing - scrolling - zooming This label is, for now, necessary to make sure we are not looping for not reason. --- - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix #21303 (github issue number if applicable). <!-- 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/21431) <!-- Reviewable:end -->
This commit is contained in:
commit
14fff5bbe0
8 changed files with 194 additions and 19 deletions
|
@ -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 =
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -82,6 +82,17 @@
|
|||
android:text="Rld"
|
||||
android:textSize="10sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/redrawing"
|
||||
android:layout_width="70dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="monospace"
|
||||
android:text="idle"
|
||||
android:textAlignment="center"
|
||||
android:textSize="10sp"
|
||||
android:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.mozilla.servoview.ServoView
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
@ -104,6 +116,8 @@ public class Servo {
|
|||
void onUrlChanged(String url);
|
||||
|
||||
void onHistoryChanged(boolean canGoBack, boolean canGoForward);
|
||||
|
||||
void onRedrawing(boolean redrawing);
|
||||
}
|
||||
|
||||
public interface RunCallback {
|
||||
|
@ -170,6 +184,10 @@ public class Servo {
|
|||
mRunCallback.inUIThread(() -> 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);
|
||||
|
|
|
@ -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,20 @@ 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;
|
||||
|
||||
private boolean mRedrawing;
|
||||
|
||||
public ServoView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
@ -138,19 +149,22 @@ 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 (!mRedrawing) {
|
||||
mRedrawing = true;
|
||||
mClient.onRedrawing(mRedrawing);
|
||||
}
|
||||
|
||||
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 +179,28 @@ 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);
|
||||
} else {
|
||||
mRedrawing = false;
|
||||
mClient.onRedrawing(mRedrawing);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
|
@ -198,6 +225,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 +235,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 +246,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 +256,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 +270,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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue