mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 663803 - Zoomed view implementation using render document r=mcomella,snorp
This commit is contained in:
parent
b4341a5a5e
commit
a059f5afa8
@ -955,7 +955,7 @@ public class BrowserApp extends GeckoApp
|
||||
|
||||
if (enabled) {
|
||||
if (mLayerView != null) {
|
||||
mLayerView.setOnMetricsChangedListener(this);
|
||||
mLayerView.setOnMetricsChangedDynamicToolbarViewportListener(this);
|
||||
}
|
||||
setToolbarMargin(0);
|
||||
mHomePagerContainer.setPadding(0, mBrowserChrome.getHeight(), 0, 0);
|
||||
@ -963,7 +963,7 @@ public class BrowserApp extends GeckoApp
|
||||
// Immediately show the toolbar when disabling the dynamic
|
||||
// toolbar.
|
||||
if (mLayerView != null) {
|
||||
mLayerView.setOnMetricsChangedListener(null);
|
||||
mLayerView.setOnMetricsChangedDynamicToolbarViewportListener(null);
|
||||
}
|
||||
mHomePagerContainer.setPadding(0, 0, 0, 0);
|
||||
if (mBrowserChrome != null) {
|
||||
|
@ -105,7 +105,8 @@ public class GeckoEvent {
|
||||
TELEMETRY_UI_EVENT(44),
|
||||
GAMEPAD_ADDREMOVE(45),
|
||||
GAMEPAD_DATA(46),
|
||||
LONG_PRESS(47);
|
||||
LONG_PRESS(47),
|
||||
ZOOMEDVIEW(48);
|
||||
|
||||
public final int value;
|
||||
|
||||
@ -749,6 +750,17 @@ public class GeckoEvent {
|
||||
return event;
|
||||
}
|
||||
|
||||
public static GeckoEvent createZoomedViewEvent(int tabId, int x, int y, int bufw, int bufh, float scaleFactor, ByteBuffer buffer) {
|
||||
GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.ZOOMEDVIEW);
|
||||
event.mPoints = new Point[2];
|
||||
event.mPoints[0] = new Point(x, y);
|
||||
event.mPoints[1] = new Point(bufw, bufh);
|
||||
event.mX = (double) scaleFactor;
|
||||
event.mMetaState = tabId;
|
||||
event.mBuffer = buffer;
|
||||
return event;
|
||||
}
|
||||
|
||||
public static GeckoEvent createScreenOrientationEvent(short aScreenOrientation) {
|
||||
GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.SCREENORIENTATION_CHANGED);
|
||||
event.mScreenOrientation = aScreenOrientation;
|
||||
|
490
mobile/android/base/ZoomedView.java
Normal file
490
mobile/android/base/ZoomedView.java
Normal file
@ -0,0 +1,490 @@
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
|
||||
import org.mozilla.gecko.gfx.LayerView;
|
||||
import org.mozilla.gecko.util.GeckoEventListener;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.mozglue.DirectBufferAllocator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
public class ZoomedView extends FrameLayout implements LayerView.OnMetricsChangedListener,
|
||||
LayerView.OnZoomedViewListener, GeckoEventListener {
|
||||
private static final String LOGTAG = "Gecko" + ZoomedView.class.getSimpleName();
|
||||
|
||||
private static final int ZOOM_FACTOR = 2;
|
||||
private static final int W_CAPTURED_VIEW_IN_PERCENT = 80;
|
||||
private static final int H_CAPTURED_VIEW_IN_PERCENT = 50;
|
||||
private static final int MINIMUM_DELAY_BETWEEN_TWO_RENDER_CALLS_NS = 1000000;
|
||||
private static final int DELAY_BEFORE_NEXT_RENDER_REQUEST_MS = 2000;
|
||||
|
||||
private ImageView zoomedImageView;
|
||||
private LayerView layerView;
|
||||
private MotionEvent actionDownEvent;
|
||||
private int viewWidth;
|
||||
private int viewHeight;
|
||||
private int xLastPosition;
|
||||
private int yLastPosition;
|
||||
private boolean shouldSetVisibleOnUpdate;
|
||||
private PointF convertedPosition;
|
||||
private PointF returnValue;
|
||||
|
||||
private boolean stopUpdateView;
|
||||
|
||||
private int lastOrientation = 0;
|
||||
|
||||
private ByteBuffer buffer;
|
||||
private Runnable requestRenderRunnable;
|
||||
private long startTimeReRender = 0;
|
||||
private long lastStartTimeReRender = 0;
|
||||
|
||||
private class ZoomedViewTouchListener implements View.OnTouchListener {
|
||||
private float originRawX;
|
||||
private float originRawY;
|
||||
private int touchState;
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent event) {
|
||||
if (layerView == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (moveZoomedView(event)) {
|
||||
touchState = MotionEvent.ACTION_MOVE;
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (touchState == MotionEvent.ACTION_MOVE) {
|
||||
touchState = -1;
|
||||
} else {
|
||||
layerView.dispatchTouchEvent(actionDownEvent);
|
||||
actionDownEvent.recycle();
|
||||
convertedPosition = getUnzoomedPositionFromPointInZoomedView(event.getX(), event.getY());
|
||||
MotionEvent e = MotionEvent.obtain(event.getDownTime(), event.getEventTime(),
|
||||
MotionEvent.ACTION_UP, convertedPosition.x, convertedPosition.y,
|
||||
event.getMetaState());
|
||||
layerView.dispatchTouchEvent(e);
|
||||
e.recycle();
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
touchState = -1;
|
||||
originRawX = event.getRawX();
|
||||
originRawY = event.getRawY();
|
||||
convertedPosition = getUnzoomedPositionFromPointInZoomedView(event.getX(), event.getY());
|
||||
actionDownEvent = MotionEvent.obtain(event.getDownTime(), event.getEventTime(),
|
||||
MotionEvent.ACTION_DOWN, convertedPosition.x, convertedPosition.y,
|
||||
event.getMetaState());
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean moveZoomedView(MotionEvent event) {
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) ZoomedView.this.getLayoutParams();
|
||||
if ((touchState != MotionEvent.ACTION_MOVE) && (Math.abs((int) (event.getRawX() - originRawX)) < 1)
|
||||
&& (Math.abs((int) (event.getRawY() - originRawY)) < 1)) {
|
||||
// When the user just touches the screen ACTION_MOVE can be detected for a very small delta on position.
|
||||
// In this case, the move is ignored if the delta is lower than 1 unit.
|
||||
return false;
|
||||
}
|
||||
|
||||
float newLeftMargin = params.leftMargin + event.getRawX() - originRawX;
|
||||
float newTopMargin = params.topMargin + event.getRawY() - originRawY;
|
||||
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
|
||||
ZoomedView.this.moveZoomedView(metrics, newLeftMargin, newTopMargin);
|
||||
originRawX = event.getRawX();
|
||||
originRawY = event.getRawY();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public ZoomedView(Context context) {
|
||||
this(context, null, 0);
|
||||
}
|
||||
|
||||
public ZoomedView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ZoomedView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
convertedPosition = new PointF();
|
||||
returnValue = new PointF();
|
||||
requestRenderRunnable = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
requestZoomedViewRender();
|
||||
}
|
||||
};
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener(this, "Gesture:nothingDoneOnLongPress",
|
||||
"Gesture:clusteredLinksClicked", "Window:Resize", "Content:LocationChange");
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener(this, "Gesture:nothingDoneOnLongPress",
|
||||
"Gesture:clusteredLinksClicked", "Window:Resize", "Content:LocationChange");
|
||||
}
|
||||
|
||||
// This method (onFinishInflate) is called only when the zoomed view class is used inside
|
||||
// an xml structure <org.mozilla.gecko.ZoomedView ...
|
||||
// It won't be called if the class is used from java code like "new ZoomedView(context);"
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
ImageView closeButton = (ImageView) findViewById(R.id.dialog_close);
|
||||
closeButton.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View view) {
|
||||
stopZoomDisplay();
|
||||
}
|
||||
});
|
||||
|
||||
zoomedImageView = (ImageView) findViewById(R.id.zoomed_image_view);
|
||||
zoomedImageView.setOnTouchListener(new ZoomedViewTouchListener());
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a click from ZoomedView. Return the position of the click in the
|
||||
* LayerView
|
||||
*/
|
||||
private PointF getUnzoomedPositionFromPointInZoomedView(float x, float y) {
|
||||
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
|
||||
PointF offset = metrics.getMarginOffset();
|
||||
final float parentWidth = metrics.getWidth();
|
||||
final float parentHeight = metrics.getHeight();
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) getLayoutParams();
|
||||
|
||||
returnValue.x = (int) ((x / ZOOM_FACTOR) + // Conversion of the x offset inside the zoomed view (using the scale factor)
|
||||
|
||||
offset.x + // The offset of the layerView
|
||||
|
||||
/* Conversion of the left side position of the zoomed view
|
||||
* Minimum value for the left side of the zoomed view is 0
|
||||
* and we return 0 after conversion
|
||||
* Maximum value for the left side of the zoomed view is (parentWidth - offset.x - viewWidth)
|
||||
* and we return (parentWidth - offset.x - (viewWidth / ZOOM_FACTOR)) after conversion.
|
||||
*/
|
||||
(((float) params.leftMargin) - offset.x) *
|
||||
((parentWidth - offset.x - (viewWidth / ZOOM_FACTOR)) /
|
||||
(parentWidth - offset.x - viewWidth)));
|
||||
|
||||
// Same comments here vertically
|
||||
returnValue.y = (int) ((y / ZOOM_FACTOR) +
|
||||
offset.y +
|
||||
(((float) params.topMargin) - offset.y) *
|
||||
((parentHeight - offset.y - (viewHeight / ZOOM_FACTOR)) /
|
||||
(parentHeight - offset.y - viewHeight)));
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/*
|
||||
* A touch point (x,y) occurs in LayerView, this point should be displayed
|
||||
* in the center of the zoomed view. The returned point is the position of
|
||||
* the Top-Left zoomed view point on the screen device
|
||||
*/
|
||||
private PointF getZoomedViewTopLeftPositionFromTouchPosition(float x, float y) {
|
||||
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
|
||||
PointF offset = metrics.getMarginOffset();
|
||||
final float parentWidth = metrics.getWidth();
|
||||
final float parentHeight = metrics.getHeight();
|
||||
|
||||
returnValue.x = (int) ((((x - (viewWidth / (2 * ZOOM_FACTOR)))) / // Translation to get the left side position of the zoomed view
|
||||
// centered on x (the value 2 to get the middle).
|
||||
|
||||
/* Conversion of the left side position of the zoomed view.
|
||||
* See the comment in getUnzoomedPositionFromPointInZoomedView.
|
||||
* The proportional factor is the same. It is used in a division
|
||||
* and not in a multiplication to convert the position from
|
||||
* the LayerView to the ZoomedView.
|
||||
*/
|
||||
((parentWidth - offset.x - (viewWidth / ZOOM_FACTOR)) /
|
||||
(parentWidth - offset.x - viewWidth)))
|
||||
|
||||
+ offset.x); // The offset of the layerView
|
||||
|
||||
// Same comments here vertically
|
||||
returnValue.y = (int) ((((y - (viewHeight / (2 * ZOOM_FACTOR)))) /
|
||||
((parentHeight - offset.y - (viewHeight / ZOOM_FACTOR)) /
|
||||
(parentHeight - offset.y - viewHeight)))
|
||||
+ offset.y);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private void moveZoomedView(ImmutableViewportMetrics metrics, float newLeftMargin, float newTopMargin) {
|
||||
if (layerView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final float parentWidth = metrics.getWidth();
|
||||
final float parentHeight = metrics.getHeight();
|
||||
RelativeLayout.LayoutParams newLayoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
|
||||
newLayoutParams.leftMargin = (int) newLeftMargin;
|
||||
newLayoutParams.topMargin = (int) newTopMargin;
|
||||
int topMarginMin;
|
||||
int leftMarginMin;
|
||||
PointF offset = metrics.getMarginOffset();
|
||||
topMarginMin = (int) offset.y;
|
||||
leftMarginMin = (int) offset.x;
|
||||
|
||||
if (newTopMargin < topMarginMin) {
|
||||
newLayoutParams.topMargin = topMarginMin;
|
||||
} else if (newTopMargin + viewHeight >= parentHeight) {
|
||||
newLayoutParams.topMargin = (int) (parentHeight - viewHeight);
|
||||
}
|
||||
|
||||
if (newLeftMargin < leftMarginMin) {
|
||||
newLayoutParams.leftMargin = leftMarginMin;
|
||||
} else if (newLeftMargin + viewWidth > parentWidth) {
|
||||
newLayoutParams.leftMargin = (int) (parentWidth - viewWidth);
|
||||
}
|
||||
|
||||
setLayoutParams(newLayoutParams);
|
||||
convertedPosition = getUnzoomedPositionFromPointInZoomedView(0, 0);
|
||||
xLastPosition = Math.round(convertedPosition.x);
|
||||
yLastPosition = Math.round(convertedPosition.y);
|
||||
requestZoomedViewRender();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
// In case of orientation change, the zoomed view update is stopped until the orientation change
|
||||
// is completed. At this time, the function onMetricsChanged is called and the
|
||||
// zoomed view update is restarted again.
|
||||
if (lastOrientation != newConfig.orientation) {
|
||||
shouldBlockUpdate(true);
|
||||
lastOrientation = newConfig.orientation;
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshZoomedViewSize(ImmutableViewportMetrics viewport) {
|
||||
if (layerView == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) getLayoutParams();
|
||||
setCapturedSize(viewport);
|
||||
moveZoomedView(viewport, params.leftMargin, params.topMargin);
|
||||
}
|
||||
|
||||
public void setCapturedSize(ImmutableViewportMetrics metrics) {
|
||||
if (layerView == null) {
|
||||
return;
|
||||
}
|
||||
float parentMinSize = Math.min(metrics.getWidth(), metrics.getHeight());
|
||||
viewWidth = (int) (parentMinSize * W_CAPTURED_VIEW_IN_PERCENT / (ZOOM_FACTOR * 100.0)) * ZOOM_FACTOR;
|
||||
viewHeight = (int) (parentMinSize * H_CAPTURED_VIEW_IN_PERCENT / (ZOOM_FACTOR * 100.0)) * ZOOM_FACTOR;
|
||||
}
|
||||
|
||||
public void shouldBlockUpdate(boolean shouldBlockUpdate) {
|
||||
stopUpdateView = shouldBlockUpdate;
|
||||
}
|
||||
|
||||
public Bitmap.Config getBitmapConfig() {
|
||||
return (GeckoAppShell.getScreenDepth() == 24) ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
|
||||
}
|
||||
|
||||
public void startZoomDisplay(LayerView aLayerView, final int leftFromGecko, final int topFromGecko) {
|
||||
if (layerView == null) {
|
||||
layerView = aLayerView;
|
||||
layerView.addOnZoomedViewListener(this);
|
||||
layerView.setOnMetricsChangedZoomedViewportListener(this);
|
||||
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
|
||||
setCapturedSize(metrics);
|
||||
}
|
||||
startTimeReRender = 0;
|
||||
shouldSetVisibleOnUpdate = true;
|
||||
moveUsingGeckoPosition(leftFromGecko, topFromGecko);
|
||||
}
|
||||
|
||||
public void stopZoomDisplay() {
|
||||
shouldSetVisibleOnUpdate = false;
|
||||
this.setVisibility(View.GONE);
|
||||
ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);
|
||||
if (layerView != null) {
|
||||
layerView.setOnMetricsChangedZoomedViewportListener(null);
|
||||
layerView.removeOnZoomedViewListener(this);
|
||||
layerView = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(final String event, final JSONObject message) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (event.equals("Gesture:nothingDoneOnLongPress") || event.equals("Gesture:clusteredLinksClicked")) {
|
||||
final JSONObject clickPosition = message.getJSONObject("clickPosition");
|
||||
int left = clickPosition.getInt("x");
|
||||
int top = clickPosition.getInt("y");
|
||||
// Start to display inside the zoomedView
|
||||
LayerView geckoAppLayerView = GeckoAppShell.getLayerView();
|
||||
if (geckoAppLayerView != null) {
|
||||
startZoomDisplay(geckoAppLayerView, left, top);
|
||||
}
|
||||
} else if (event.equals("Window:Resize")) {
|
||||
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
|
||||
refreshZoomedViewSize(metrics);
|
||||
} else if (event.equals("Content:LocationChange")) {
|
||||
stopZoomDisplay();
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "JSON exception", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void moveUsingGeckoPosition(int leftFromGecko, int topFromGecko) {
|
||||
if (layerView == null) {
|
||||
return;
|
||||
}
|
||||
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
|
||||
convertedPosition = getZoomedViewTopLeftPositionFromTouchPosition((leftFromGecko * metrics.zoomFactor),
|
||||
(topFromGecko * metrics.zoomFactor));
|
||||
moveZoomedView(metrics, convertedPosition.x, convertedPosition.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMetricsChanged(final ImmutableViewportMetrics viewport) {
|
||||
// It can be called from a Gecko thread (forceViewportMetrics in GeckoLayerClient).
|
||||
// Post to UI Thread to avoid Exception:
|
||||
// "Only the original thread that created a view hierarchy can touch its views."
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (layerView == null) {
|
||||
return;
|
||||
}
|
||||
shouldBlockUpdate(false);
|
||||
refreshZoomedViewSize(viewport);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanZoomStopped() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateView(ByteBuffer data) {
|
||||
final Bitmap sb3 = Bitmap.createBitmap(viewWidth, viewHeight, getBitmapConfig());
|
||||
if (sb3 != null) {
|
||||
data.rewind();
|
||||
try {
|
||||
sb3.copyPixelsFromBuffer(data);
|
||||
} catch (Exception iae) {
|
||||
Log.w(LOGTAG, iae.toString());
|
||||
}
|
||||
BitmapDrawable ob3 = new BitmapDrawable(getResources(), sb3);
|
||||
if (zoomedImageView != null) {
|
||||
zoomedImageView.setImageDrawable(ob3);
|
||||
}
|
||||
}
|
||||
if (shouldSetVisibleOnUpdate) {
|
||||
this.setVisibility(View.VISIBLE);
|
||||
shouldSetVisibleOnUpdate = false;
|
||||
}
|
||||
lastStartTimeReRender = startTimeReRender;
|
||||
startTimeReRender = 0;
|
||||
}
|
||||
|
||||
private void updateBufferSize() {
|
||||
int pixelSize = (GeckoAppShell.getScreenDepth() == 24) ? 4 : 2;
|
||||
int capacity = viewWidth * viewHeight * pixelSize;
|
||||
if (buffer == null || buffer.capacity() != capacity) {
|
||||
buffer = DirectBufferAllocator.free(buffer);
|
||||
buffer = DirectBufferAllocator.allocate(capacity);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isRendering() {
|
||||
return (startTimeReRender != 0);
|
||||
}
|
||||
|
||||
private boolean renderFrequencyTooHigh() {
|
||||
return ((System.nanoTime() - lastStartTimeReRender) < MINIMUM_DELAY_BETWEEN_TWO_RENDER_CALLS_NS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestZoomedViewRender() {
|
||||
if (stopUpdateView) {
|
||||
return;
|
||||
}
|
||||
// remove pending runnable
|
||||
ThreadUtils.removeCallbacksFromUiThread(requestRenderRunnable);
|
||||
|
||||
// "requestZoomedViewRender" can be called very often by Gecko (endDrawing in LayerRender) without
|
||||
// any thing changed in the zoomed area (useless calls from the "zoomed area" point of view).
|
||||
// "requestZoomedViewRender" can take time to re-render the zoomed view, it depends of the complexity
|
||||
// of the html on this area.
|
||||
// To avoid to slow down the application, the 2 following cases are tested:
|
||||
|
||||
// 1- Last render is still running, plan another render later.
|
||||
if (isRendering()) {
|
||||
// post a new runnable DELAY_BEFORE_NEXT_RENDER_REQUEST_MS later
|
||||
// We need to post with a delay to be sure that the last call to requestZoomedViewRender will be done.
|
||||
// For a static html page WITHOUT any animation/video, there is a last call to endDrawing and we need to make
|
||||
// the zoomed render on this last call.
|
||||
ThreadUtils.postDelayedToUiThread(requestRenderRunnable, DELAY_BEFORE_NEXT_RENDER_REQUEST_MS);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2- Current render occurs too early, plan another render later.
|
||||
if (renderFrequencyTooHigh()) {
|
||||
// post a new runnable DELAY_BEFORE_NEXT_RENDER_REQUEST_MS later
|
||||
// We need to post with a delay to be sure that the last call to requestZoomedViewRender will be done.
|
||||
// For a page WITH animation/video, the animation/video can be stopped, and we need to make
|
||||
// the zoomed render on this last call.
|
||||
ThreadUtils.postDelayedToUiThread(requestRenderRunnable, DELAY_BEFORE_NEXT_RENDER_REQUEST_MS);
|
||||
return;
|
||||
}
|
||||
|
||||
startTimeReRender = System.nanoTime();
|
||||
// Allocate the buffer if it's the first call.
|
||||
// Change the buffer size if it's not the right size.
|
||||
updateBufferSize();
|
||||
|
||||
int tabId = Tabs.getInstance().getSelectedTab().getId();
|
||||
|
||||
ImmutableViewportMetrics metrics = layerView.getViewportMetrics();
|
||||
PointF origin = metrics.getOrigin();
|
||||
PointF offset = metrics.getMarginOffset();
|
||||
|
||||
final int xPos = (int) (origin.x - offset.x) + xLastPosition;
|
||||
final int yPos = (int) (origin.y - offset.y) + yLastPosition;
|
||||
|
||||
GeckoEvent e = GeckoEvent.createZoomedViewEvent(tabId, xPos, yPos, viewWidth,
|
||||
viewHeight, (float) (2.0 * metrics.zoomFactor), buffer);
|
||||
GeckoAppShell.sendEventToGecko(e);
|
||||
}
|
||||
|
||||
}
|
@ -86,7 +86,8 @@ class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
|
||||
* that because mViewportMetrics might get reassigned in between reading the different
|
||||
* fields. */
|
||||
private volatile ImmutableViewportMetrics mViewportMetrics;
|
||||
private LayerView.OnMetricsChangedListener mViewportChangeListener;
|
||||
private LayerView.OnMetricsChangedListener mDynamicToolbarViewportChangeListener;
|
||||
private LayerView.OnMetricsChangedListener mZoomedViewViewportChangeListener;
|
||||
|
||||
private ZoomConstraints mZoomConstraints;
|
||||
|
||||
@ -853,8 +854,11 @@ class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
|
||||
* You must hold the monitor while calling this.
|
||||
*/
|
||||
private void viewportMetricsChanged(boolean notifyGecko) {
|
||||
if (mViewportChangeListener != null) {
|
||||
mViewportChangeListener.onMetricsChanged(mViewportMetrics);
|
||||
if (mDynamicToolbarViewportChangeListener != null) {
|
||||
mDynamicToolbarViewportChangeListener.onMetricsChanged(mViewportMetrics);
|
||||
}
|
||||
if (mZoomedViewViewportChangeListener != null) {
|
||||
mZoomedViewViewportChangeListener.onMetricsChanged(mViewportMetrics);
|
||||
}
|
||||
|
||||
mView.requestRender();
|
||||
@ -910,8 +914,11 @@ class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
|
||||
/** Implementation of PanZoomTarget */
|
||||
@Override
|
||||
public void panZoomStopped() {
|
||||
if (mViewportChangeListener != null) {
|
||||
mViewportChangeListener.onPanZoomStopped();
|
||||
if (mDynamicToolbarViewportChangeListener != null) {
|
||||
mDynamicToolbarViewportChangeListener.onPanZoomStopped();
|
||||
}
|
||||
if (mZoomedViewViewportChangeListener != null) {
|
||||
mZoomedViewViewportChangeListener.onPanZoomStopped();
|
||||
}
|
||||
}
|
||||
|
||||
@ -982,8 +989,12 @@ class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
|
||||
return layerPoint;
|
||||
}
|
||||
|
||||
void setOnMetricsChangedListener(LayerView.OnMetricsChangedListener listener) {
|
||||
mViewportChangeListener = listener;
|
||||
void setOnMetricsChangedDynamicToolbarViewportListener(LayerView.OnMetricsChangedListener listener) {
|
||||
mDynamicToolbarViewportChangeListener = listener;
|
||||
}
|
||||
|
||||
void setOnMetricsChangedZoomedViewportListener(LayerView.OnMetricsChangedListener listener) {
|
||||
mZoomedViewViewportChangeListener = listener;
|
||||
}
|
||||
|
||||
public void addDrawListener(DrawListener listener) {
|
||||
|
@ -26,13 +26,17 @@ import android.graphics.RectF;
|
||||
import android.opengl.GLES20;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import org.mozilla.gecko.mozglue.JNITarget;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.microedition.khronos.egl.EGLConfig;
|
||||
|
||||
@ -55,6 +59,8 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
|
||||
private static final long NANOS_PER_MS = 1000000;
|
||||
private static final int NANOS_PER_SECOND = 1000000000;
|
||||
|
||||
private static final int MAX_SCROLL_SPEED_TO_REQUEST_ZOOM_RENDER = 5;
|
||||
|
||||
private final LayerView mView;
|
||||
private final ScrollbarLayer mHorizScrollLayer;
|
||||
private final ScrollbarLayer mVertScrollLayer;
|
||||
@ -90,6 +96,10 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
|
||||
private int mSampleHandle;
|
||||
private int mTMatrixHandle;
|
||||
|
||||
private List<LayerView.OnZoomedViewListener> mZoomedViewListeners;
|
||||
private float mViewLeft = 0.0f;
|
||||
private float mViewTop = 0.0f;
|
||||
|
||||
// column-major matrix applied to each vertex to shift the viewport from
|
||||
// one ranging from (-1, -1),(1,1) to (0,0),(1,1) and to scale all sizes by
|
||||
// a factor of 2 to fill up the screen
|
||||
@ -158,6 +168,7 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
|
||||
mCoordBuffer = mCoordByteBuffer.asFloatBuffer();
|
||||
|
||||
Tabs.registerOnTabsChangedListener(this);
|
||||
mZoomedViewListeners = new ArrayList<LayerView.OnZoomedViewListener>();
|
||||
}
|
||||
|
||||
private Bitmap expandCanvasToPowerOfTwo(Bitmap image, IntSize size) {
|
||||
@ -185,6 +196,7 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
|
||||
mHorizScrollLayer.destroy();
|
||||
mVertScrollLayer.destroy();
|
||||
Tabs.unregisterOnTabsChangedListener(this);
|
||||
mZoomedViewListeners.clear();
|
||||
}
|
||||
|
||||
void onSurfaceCreated(EGLConfig config) {
|
||||
@ -586,6 +598,41 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
|
||||
|
||||
}
|
||||
|
||||
public void maybeRequestZoomedViewRender(RenderContext context){
|
||||
// Concurrently update of mZoomedViewListeners should not be an issue here
|
||||
if (mZoomedViewListeners.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// When scrolling fast, do not request zoomed view render to avoid to slow down
|
||||
// the scroll in the main view.
|
||||
// Speed is estimated using the offset changes between 2 display frame calls
|
||||
final float viewLeft = context.viewport.left - context.offset.x;
|
||||
final float viewTop = context.viewport.top - context.offset.y;
|
||||
boolean shouldWaitToRender = false;
|
||||
|
||||
if (Math.abs(mViewLeft - viewLeft) > MAX_SCROLL_SPEED_TO_REQUEST_ZOOM_RENDER ||
|
||||
Math.abs(mViewTop - viewTop) > MAX_SCROLL_SPEED_TO_REQUEST_ZOOM_RENDER) {
|
||||
shouldWaitToRender = true;
|
||||
}
|
||||
|
||||
mViewLeft = viewLeft;
|
||||
mViewTop = viewTop;
|
||||
|
||||
if (shouldWaitToRender) {
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (LayerView.OnZoomedViewListener listener : mZoomedViewListeners) {
|
||||
listener.requestZoomedViewRender();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** This function is invoked via JNI; be careful when modifying signature. */
|
||||
@JNITarget
|
||||
public void endDrawing() {
|
||||
@ -595,6 +642,8 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
|
||||
|
||||
PanningPerfAPI.recordFrameTime();
|
||||
|
||||
maybeRequestZoomedViewRender(mPageContext);
|
||||
|
||||
/* Used by robocop for testing purposes */
|
||||
IntBuffer pixelBuffer = mPixelBuffer;
|
||||
if (mUpdated && pixelBuffer != null) {
|
||||
@ -642,4 +691,25 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateZoomedView(final ByteBuffer data) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (LayerView.OnZoomedViewListener listener : mZoomedViewListeners) {
|
||||
listener.updateView(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addOnZoomedViewListener(LayerView.OnZoomedViewListener listener) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
mZoomedViewListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeOnZoomedViewListener(LayerView.OnZoomedViewListener listener) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
mZoomedViewListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,9 @@
|
||||
|
||||
package org.mozilla.gecko.gfx;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.mozilla.gecko.AndroidGamepadManager;
|
||||
import org.mozilla.gecko.AppConstants.Versions;
|
||||
@ -530,6 +532,19 @@ public class LayerView extends FrameLayout implements Tabs.OnTabsChangedListener
|
||||
}
|
||||
}
|
||||
|
||||
@WrapElementForJNI(allowMultithread = true, stubName = "updateZoomedView")
|
||||
public static void updateZoomedView(ByteBuffer data) {
|
||||
data.position(0);
|
||||
LayerView layerView = GeckoAppShell.getLayerView();
|
||||
if (layerView != null) {
|
||||
LayerRenderer layerRenderer = layerView.getRenderer();
|
||||
if (layerRenderer != null){
|
||||
layerRenderer.updateZoomedView(data);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void renderRequested();
|
||||
void sizeChanged(int width, int height);
|
||||
@ -662,7 +677,27 @@ public class LayerView extends FrameLayout implements Tabs.OnTabsChangedListener
|
||||
public void onPanZoomStopped();
|
||||
}
|
||||
|
||||
public void setOnMetricsChangedListener(OnMetricsChangedListener listener) {
|
||||
mLayerClient.setOnMetricsChangedListener(listener);
|
||||
public void setOnMetricsChangedDynamicToolbarViewportListener(OnMetricsChangedListener listener) {
|
||||
mLayerClient.setOnMetricsChangedDynamicToolbarViewportListener(listener);
|
||||
}
|
||||
|
||||
public void setOnMetricsChangedZoomedViewportListener(OnMetricsChangedListener listener) {
|
||||
mLayerClient.setOnMetricsChangedZoomedViewportListener(listener);
|
||||
}
|
||||
|
||||
// Public hooks for zoomed view
|
||||
|
||||
public interface OnZoomedViewListener {
|
||||
public void requestZoomedViewRender();
|
||||
public void updateView(ByteBuffer data);
|
||||
}
|
||||
|
||||
public void addOnZoomedViewListener(OnZoomedViewListener listener) {
|
||||
mRenderer.addOnZoomedViewListener(listener);
|
||||
}
|
||||
|
||||
public void removeOnZoomedViewListener(OnZoomedViewListener listener) {
|
||||
mRenderer.removeOnZoomedViewListener(listener);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -500,6 +500,7 @@ gbjar.sources += [
|
||||
'widget/ThumbnailView.java',
|
||||
'widget/TwoWayView.java',
|
||||
'ZoomConstraints.java',
|
||||
'ZoomedView.java',
|
||||
]
|
||||
# The following sources are checked in to version control but
|
||||
# generated by a script (widget/generate_themed_views.py). If you're
|
||||
|
@ -25,6 +25,7 @@
|
||||
android:visibility="gone"/>
|
||||
|
||||
<include layout="@layout/text_selection_handles"/>
|
||||
<include layout="@layout/zoomed_view"/>
|
||||
|
||||
<FrameLayout android:id="@+id/camera_layout"
|
||||
android:layout_height="wrap_content"
|
||||
|
33
mobile/android/base/resources/layout/zoomed_view.xml
Normal file
33
mobile/android/base/resources/layout/zoomed_view.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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/.
|
||||
-->
|
||||
|
||||
<org.mozilla.gecko.ZoomedView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:gecko="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/zoomed_view_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:background="@android:color/white"
|
||||
android:visibility="gone" >
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/zoomed_image_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#000000"
|
||||
android:padding="1dip" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/dialog_close"
|
||||
android:background="@drawable/close"
|
||||
android:layout_height="20dp"
|
||||
android:layout_width="20dp"
|
||||
android:layout_gravity ="top|right" />
|
||||
|
||||
</org.mozilla.gecko.ZoomedView>
|
@ -96,6 +96,14 @@ public final class ThreadUtils {
|
||||
sUiHandler.post(runnable);
|
||||
}
|
||||
|
||||
public static void postDelayedToUiThread(Runnable runnable, long timeout) {
|
||||
sUiHandler.postDelayed(runnable, timeout);
|
||||
}
|
||||
|
||||
public static void removeCallbacksFromUiThread(Runnable runnable) {
|
||||
sUiHandler.removeCallbacks(runnable);
|
||||
}
|
||||
|
||||
public static Thread getBackgroundThread() {
|
||||
return sBackgroundThread;
|
||||
}
|
||||
|
@ -4980,7 +4980,12 @@ var BrowserEventHandler = {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._inCluster = aEvent.hitCluster;
|
||||
if (this._inCluster) {
|
||||
return; // No highlight for a cluster of links
|
||||
}
|
||||
|
||||
let uri = this._getLinkURI(target);
|
||||
if (uri) {
|
||||
try {
|
||||
@ -5097,6 +5102,7 @@ var BrowserEventHandler = {
|
||||
|
||||
let data = JSON.parse(aData);
|
||||
let {x, y} = data;
|
||||
|
||||
if (this._inCluster) {
|
||||
this._clusterClicked(x, y);
|
||||
} else {
|
||||
@ -5129,14 +5135,14 @@ var BrowserEventHandler = {
|
||||
}
|
||||
},
|
||||
|
||||
_clusterClicked: function sh_clusterClicked(aX, aY) {
|
||||
Messaging.sendRequest({
|
||||
type: "Gesture:clusteredLinksClicked",
|
||||
clicPosition: {
|
||||
x: aX,
|
||||
y: aY
|
||||
}
|
||||
});
|
||||
_clusterClicked: function(aX, aY) {
|
||||
Messaging.sendRequest({
|
||||
type: "Gesture:clusteredLinksClicked",
|
||||
clickPosition: {
|
||||
x: aX,
|
||||
y: aY
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onDoubleTap: function(aData) {
|
||||
|
@ -1704,6 +1704,94 @@ AndroidBridge::GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId,
|
||||
return true;
|
||||
}
|
||||
|
||||
static float
|
||||
GetScaleFactor(nsPresContext* mPresContext) {
|
||||
nsIPresShell* presShell = mPresContext->PresShell();
|
||||
LayoutDeviceToLayerScale cumulativeResolution(presShell->GetCumulativeResolution().width);
|
||||
return cumulativeResolution.scale;
|
||||
}
|
||||
|
||||
nsresult
|
||||
AndroidBridge::CaptureZoomedView (nsIDOMWindow *window, nsIntRect zoomedViewRect, Object::Param buffer,
|
||||
float zoomFactor) {
|
||||
nsresult rv;
|
||||
struct timeval timeEnd;
|
||||
struct timeval timeEndAfter;
|
||||
struct timeval timeStart;
|
||||
struct timeval res;
|
||||
gettimeofday (&timeStart, NULL);
|
||||
|
||||
if (!buffer)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsCOMPtr < nsIDOMWindowUtils > utils = do_GetInterface (window);
|
||||
if (!utils)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
JNIEnv* env = GetJNIEnv ();
|
||||
|
||||
AutoLocalJNIFrame jniFrame (env, 0);
|
||||
|
||||
nsCOMPtr < nsPIDOMWindow > win = do_QueryInterface (window);
|
||||
if (!win) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsRefPtr < nsPresContext > presContext;
|
||||
|
||||
nsIDocShell* docshell = win->GetDocShell ();
|
||||
|
||||
if (docshell) {
|
||||
docshell->GetPresContext (getter_AddRefs (presContext));
|
||||
}
|
||||
|
||||
if (!presContext) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr < nsIPresShell > presShell = presContext->PresShell ();
|
||||
|
||||
float scaleFactor = GetScaleFactor(presContext) ;
|
||||
|
||||
nscolor bgColor = NS_RGB (255, 255, 255);
|
||||
uint32_t renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING | nsIPresShell::RENDER_DOCUMENT_RELATIVE);
|
||||
nsRect r (presContext->DevPixelsToAppUnits(zoomedViewRect.x / scaleFactor),
|
||||
presContext->DevPixelsToAppUnits(zoomedViewRect.y / scaleFactor ),
|
||||
presContext->DevPixelsToAppUnits(zoomedViewRect.width / scaleFactor ),
|
||||
presContext->DevPixelsToAppUnits(zoomedViewRect.height / scaleFactor ));
|
||||
|
||||
bool is24bit = (GetScreenDepth () == 24);
|
||||
SurfaceFormat format = is24bit ? SurfaceFormat::B8G8R8X8 : SurfaceFormat::R5G6B5;
|
||||
gfxImageFormat iFormat = gfx::SurfaceFormatToImageFormat(format);
|
||||
uint32_t stride = gfxASurface::FormatStrideForWidth(iFormat, zoomedViewRect.width);
|
||||
|
||||
uint8_t* data = static_cast<uint8_t*> (env->GetDirectBufferAddress (buffer.Get()));
|
||||
if (!data) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT (gfxPlatform::GetPlatform ()->SupportsAzureContentForType (BackendType::CAIRO),
|
||||
"Need BackendType::CAIRO support");
|
||||
RefPtr < DrawTarget > dt = Factory::CreateDrawTargetForData (
|
||||
BackendType::CAIRO, data, IntSize (zoomedViewRect.width, zoomedViewRect.height), stride,
|
||||
format);
|
||||
if (!dt) {
|
||||
ALOG_BRIDGE ("Error creating DrawTarget");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsRefPtr < gfxContext > context = new gfxContext (dt);
|
||||
context->SetMatrix (context->CurrentMatrix ().Scale(zoomFactor, zoomFactor));
|
||||
|
||||
rv = presShell->RenderDocument (r, renderDocFlags, bgColor, context);
|
||||
|
||||
if (is24bit) {
|
||||
gfxUtils::ConvertBGRAtoRGBA (data, stride * zoomedViewRect.height);
|
||||
}
|
||||
|
||||
LayerView::updateZoomedView(buffer);
|
||||
|
||||
NS_ENSURE_SUCCESS (rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult AndroidBridge::CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, Object::Param buffer, bool &shouldStore)
|
||||
{
|
||||
nsresult rv;
|
||||
|
@ -188,6 +188,7 @@ public:
|
||||
bool GetThreadNameJavaProfiling(uint32_t aThreadId, nsCString & aResult);
|
||||
bool GetFrameNameJavaProfiling(uint32_t aThreadId, uint32_t aSampleId, uint32_t aFrameId, nsCString & aResult);
|
||||
|
||||
nsresult CaptureZoomedView(nsIDOMWindow *window, nsIntRect zoomedViewRect, jni::Object::Param buffer, float zoomFactor);
|
||||
nsresult CaptureThumbnail(nsIDOMWindow *window, int32_t bufW, int32_t bufH, int32_t tabId, jni::Object::Param buffer, bool &shouldStore);
|
||||
void GetDisplayPort(bool aPageSizeUpdate, bool aIsBrowserContentDisplayed, int32_t tabId, nsIAndroidViewport* metrics, nsIAndroidDisplayport** displayPort);
|
||||
void ContentDocumentChanged();
|
||||
|
@ -538,6 +538,14 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
|
||||
break;
|
||||
}
|
||||
|
||||
case ZOOMEDVIEW: {
|
||||
mX = jenv->GetDoubleField(jobj, jXField);
|
||||
mMetaState = jenv->GetIntField(jobj, jMetaStateField);
|
||||
ReadPointArray(mPoints, jenv, jPoints, 2);
|
||||
mByteBuffer = new RefCountedJavaObject(jenv, jenv->GetObjectField(jobj, jByteBufferField));
|
||||
break;
|
||||
}
|
||||
|
||||
case SCREENORIENTATION_CHANGED: {
|
||||
mScreenOrientation = jenv->GetShortField(jobj, jScreenOrientationField);
|
||||
break;
|
||||
|
@ -746,6 +746,7 @@ public:
|
||||
GAMEPAD_ADDREMOVE = 45,
|
||||
GAMEPAD_DATA = 46,
|
||||
LONG_PRESS = 47,
|
||||
ZOOMEDVIEW = 48,
|
||||
dummy_java_enum_list_end
|
||||
};
|
||||
|
||||
|
@ -980,6 +980,14 @@ mozilla::jni::Object::LocalRef LayerView::RegisterCompositorWrapper()
|
||||
return mozilla::jni::Method<RegisterCompositorWrapper_t>::Call(nullptr, nullptr);
|
||||
}
|
||||
|
||||
constexpr char LayerView::updateZoomedView_t::name[];
|
||||
constexpr char LayerView::updateZoomedView_t::signature[];
|
||||
|
||||
void LayerView::updateZoomedView(mozilla::jni::Object::Param a0)
|
||||
{
|
||||
return mozilla::jni::Method<updateZoomedView_t>::Call(nullptr, nullptr, a0);
|
||||
}
|
||||
|
||||
constexpr char NativePanZoomController::name[];
|
||||
|
||||
constexpr char NativePanZoomController::RequestContentRepaintWrapper_t::name[];
|
||||
|
@ -1934,6 +1934,21 @@ public:
|
||||
|
||||
static mozilla::jni::Object::LocalRef RegisterCompositorWrapper();
|
||||
|
||||
public:
|
||||
struct updateZoomedView_t {
|
||||
typedef LayerView Owner;
|
||||
typedef void ReturnType;
|
||||
typedef void SetterType;
|
||||
static constexpr char name[] = "updateZoomedView";
|
||||
static constexpr char signature[] =
|
||||
"(Ljava/nio/ByteBuffer;)V";
|
||||
static const bool isStatic = true;
|
||||
static const bool isMultithreaded = true;
|
||||
static const mozilla::jni::ExceptionMode exceptionMode = mozilla::jni::ExceptionMode::ABORT;
|
||||
};
|
||||
|
||||
static void updateZoomedView(mozilla::jni::Object::Param);
|
||||
|
||||
};
|
||||
|
||||
class NativePanZoomController : public mozilla::jni::Class<NativePanZoomController> {
|
||||
|
@ -393,6 +393,33 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
||||
break;
|
||||
}
|
||||
|
||||
case AndroidGeckoEvent::ZOOMEDVIEW: {
|
||||
if (!mBrowserApp)
|
||||
break;
|
||||
int32_t tabId = curEvent->MetaState();
|
||||
const nsTArray<nsIntPoint>& points = curEvent->Points();
|
||||
float scaleFactor = (float) curEvent->X();
|
||||
nsRefPtr<RefCountedJavaObject> javaBuffer = curEvent->ByteBuffer();
|
||||
const auto& mBuffer = jni::Object::Ref::From(javaBuffer->GetObject());
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> domWindow;
|
||||
nsCOMPtr<nsIBrowserTab> tab;
|
||||
mBrowserApp->GetBrowserTab(tabId, getter_AddRefs(tab));
|
||||
if (!tab) {
|
||||
NS_ERROR("Can't find tab!");
|
||||
break;
|
||||
}
|
||||
tab->GetWindow(getter_AddRefs(domWindow));
|
||||
if (!domWindow) {
|
||||
NS_ERROR("Can't find dom window!");
|
||||
break;
|
||||
}
|
||||
NS_ASSERTION(points.Length() == 2, "ZoomedView event does not have enough coordinates");
|
||||
nsIntRect r(points[0].x, points[0].y, points[1].x, points[1].y);
|
||||
nsresult rv = AndroidBridge::Bridge()->CaptureZoomedView(domWindow, r, mBuffer, scaleFactor);
|
||||
break;
|
||||
}
|
||||
|
||||
case AndroidGeckoEvent::VIEWPORT:
|
||||
case AndroidGeckoEvent::BROADCAST: {
|
||||
if (curEvent->Characters().Length() == 0)
|
||||
|
Loading…
Reference in New Issue
Block a user