Bug 777351 - Fold LayerController into GeckoLayerClient. r=sriram

This commit is contained in:
Kartikaya Gupta 2012-08-07 10:39:04 -04:00
Родитель f94834ff5e
Коммит 4f27b0d08c
15 изменённых файлов: 376 добавлений и 428 удалений

Просмотреть файл

@ -222,7 +222,7 @@ public class FormAssistPopup extends RelativeLayout implements GeckoEventListene
int popupWidth = RelativeLayout.LayoutParams.FILL_PARENT; int popupWidth = RelativeLayout.LayoutParams.FILL_PARENT;
int popupLeft = left < 0 ? 0 : left; int popupLeft = left < 0 ? 0 : left;
FloatSize viewport = GeckoApp.mAppContext.getLayerController().getViewportSize(); FloatSize viewport = GeckoApp.mAppContext.getLayerClient().getViewportSize();
// For autocomplete suggestions, if the input is smaller than the screen-width, // For autocomplete suggestions, if the input is smaller than the screen-width,
// shrink the popup's width. Otherwise, keep it as FILL_PARENT. // shrink the popup's width. Otherwise, keep it as FILL_PARENT.

Просмотреть файл

@ -8,7 +8,6 @@ package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserDB; import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.gfx.GeckoLayerClient; import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.Layer; import org.mozilla.gecko.gfx.Layer;
import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PluginLayer; import org.mozilla.gecko.gfx.PluginLayer;
import org.mozilla.gecko.gfx.PointUtils; import org.mozilla.gecko.gfx.PointUtils;
@ -154,7 +153,6 @@ abstract public class GeckoApp
protected FormAssistPopup mFormAssistPopup; protected FormAssistPopup mFormAssistPopup;
protected TabsPanel mTabsPanel; protected TabsPanel mTabsPanel;
private LayerController mLayerController;
private GeckoLayerClient mLayerClient; private GeckoLayerClient mLayerClient;
private AbsoluteLayout mPluginContainer; private AbsoluteLayout mPluginContainer;
@ -856,10 +854,10 @@ abstract public class GeckoApp
tab.setCheckerboardColor(Color.WHITE); tab.setCheckerboardColor(Color.WHITE);
} }
// Sync up the LayerController and the tab if the tab's // Sync up the GeckoLayerClient and the tab if the tab's
// currently displayed. // currently displayed.
if (getLayerController() != null && Tabs.getInstance().isSelectedTab(tab)) { if (getLayerClient() != null && Tabs.getInstance().isSelectedTab(tab)) {
getLayerController().setCheckerboardColor(tab.getCheckerboardColor()); getLayerClient().setCheckerboardColor(tab.getCheckerboardColor());
} }
} else if (event.equals("DOMTitleChanged")) { } else if (event.equals("DOMTitleChanged")) {
final int tabId = message.getInt("tabID"); final int tabId = message.getInt("tabID");
@ -1002,10 +1000,10 @@ abstract public class GeckoApp
if (tab == null) if (tab == null)
return; return;
tab.setZoomConstraints(new ZoomConstraints(message)); tab.setZoomConstraints(new ZoomConstraints(message));
// Sync up the LayerController and the tab if the tab's currently displayed. // Sync up the GeckoLayerClient and the tab if the tab is currently displayed.
LayerController controller = getLayerController(); GeckoLayerClient layerClient = getLayerClient();
if (controller != null && Tabs.getInstance().isSelectedTab(tab)) { if (layerClient != null && Tabs.getInstance().isSelectedTab(tab)) {
controller.setZoomConstraints(tab.getZoomConstraints()); layerClient.setZoomConstraints(tab.getZoomConstraints());
} }
} else if (event.equals("Tab:HasTouchListener")) { } else if (event.equals("Tab:HasTouchListener")) {
int tabId = message.getInt("tabID"); int tabId = message.getInt("tabID");
@ -1014,7 +1012,7 @@ abstract public class GeckoApp
mMainHandler.post(new Runnable() { mMainHandler.post(new Runnable() {
public void run() { public void run() {
if (Tabs.getInstance().isSelectedTab(tab)) if (Tabs.getInstance().isSelectedTab(tab))
mLayerController.getView().getTouchEventHandler().setWaitForTouchListeners(true); mLayerClient.getView().getTouchEventHandler().setWaitForTouchListeners(true);
} }
}); });
} else if (event.equals("Session:StatePurged")) { } else if (event.equals("Session:StatePurged")) {
@ -1214,7 +1212,7 @@ abstract public class GeckoApp
tab.updateIdentityData(null); tab.updateIdentityData(null);
tab.setReaderEnabled(false); tab.setReaderEnabled(false);
if (Tabs.getInstance().isSelectedTab(tab)) if (Tabs.getInstance().isSelectedTab(tab))
getLayerController().getView().getRenderer().resetCheckerboard(); getLayerClient().getView().getRenderer().resetCheckerboard();
mMainHandler.post(new Runnable() { mMainHandler.post(new Runnable() {
public void run() { public void run() {
Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.START, showProgress); Tabs.getInstance().notifyListeners(tab, Tabs.TabEvents.START, showProgress);
@ -1351,14 +1349,14 @@ abstract public class GeckoApp
PluginLayer layer = (PluginLayer) tab.getPluginLayer(view); PluginLayer layer = (PluginLayer) tab.getPluginLayer(view);
if (layer == null) { if (layer == null) {
layer = new PluginLayer(view, rect, mLayerController.getView().getRenderer().getMaxTextureSize()); layer = new PluginLayer(view, rect, mLayerClient.getView().getRenderer().getMaxTextureSize());
tab.addPluginLayer(view, layer); tab.addPluginLayer(view, layer);
} else { } else {
layer.reset(rect); layer.reset(rect);
layer.setVisible(true); layer.setVisible(true);
} }
mLayerController.getView().addLayer(layer); mLayerClient.getView().addLayer(layer);
} }
}); });
} }
@ -1380,7 +1378,7 @@ abstract public class GeckoApp
// a deadlock, see comment below in FullScreenHolder // a deadlock, see comment below in FullScreenHolder
mMainHandler.post(new Runnable() { mMainHandler.post(new Runnable() {
public void run() { public void run() {
mLayerController.getView().setVisibility(View.VISIBLE); mLayerClient.getView().setVisibility(View.VISIBLE);
} }
}); });
@ -1435,19 +1433,19 @@ abstract public class GeckoApp
} }
private void hidePluginLayer(Layer layer) { private void hidePluginLayer(Layer layer) {
LayerView layerView = mLayerController.getView(); LayerView layerView = mLayerClient.getView();
layerView.removeLayer(layer); layerView.removeLayer(layer);
layerView.requestRender(); layerView.requestRender();
} }
private void showPluginLayer(Layer layer) { private void showPluginLayer(Layer layer) {
LayerView layerView = mLayerController.getView(); LayerView layerView = mLayerClient.getView();
layerView.addLayer(layer); layerView.addLayer(layer);
layerView.requestRender(); layerView.requestRender();
} }
public void requestRender() { public void requestRender() {
mLayerController.getView().requestRender(); mLayerClient.getView().requestRender();
} }
public void hidePlugins(Tab tab) { public void hidePlugins(Tab tab) {
@ -1663,23 +1661,9 @@ abstract public class GeckoApp
cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
} }
if (mLayerController == null) { if (mLayerClient == null) {
/*
* Create a layer client, but don't hook it up to the layer controller yet.
*/
mLayerClient = new GeckoLayerClient(this); mLayerClient = new GeckoLayerClient(this);
mLayerClient.setView((LayerView)findViewById(R.id.layer_view));
/*
* Hook a placeholder layer client up to the layer controller so that the user can pan
* and zoom a cached screenshot of the previous page. This call will return null if
* there is no cached screenshot; in that case, we have no choice but to display a
* checkerboard.
*
* TODO: Fall back to a built-in screenshot of the Fennec Start page for a nice first-
* run experience, perhaps?
*/
mLayerController = new LayerController(this);
mLayerController.setView((LayerView)findViewById(R.id.layer_view));
} }
mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container); mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container);
@ -2096,8 +2080,6 @@ abstract public class GeckoApp
deleteTempFiles(); deleteTempFiles();
if (mLayerController != null)
mLayerController.destroy();
if (mLayerClient != null) if (mLayerClient != null)
mLayerClient.destroy(); mLayerClient.destroy();
if (mDoorHangerPopup != null) if (mDoorHangerPopup != null)
@ -2565,7 +2547,6 @@ abstract public class GeckoApp
/* This method is referenced by Robocop via reflection. */ /* This method is referenced by Robocop via reflection. */
public GeckoLayerClient getLayerClient() { return mLayerClient; } public GeckoLayerClient getLayerClient() { return mLayerClient; }
public LayerController getLayerController() { return mLayerController; }
public AbsoluteLayout getPluginContainer() { return mPluginContainer; } public AbsoluteLayout getPluginContainer() { return mPluginContainer; }
@ -2611,10 +2592,10 @@ abstract public class GeckoApp
} }
private void connectGeckoLayerClient() { private void connectGeckoLayerClient() {
LayerController layerController = getLayerController(); GeckoLayerClient layerClient = getLayerClient();
layerController.setLayerClient(mLayerClient); layerClient.notifyGeckoReady();
layerController.getView().getTouchEventHandler().setOnTouchListener(new ContentTouchListener() { layerClient.getView().getTouchEventHandler().setOnTouchListener(new ContentTouchListener() {
private PointF initialPoint = null; private PointF initialPoint = null;
@Override @Override
@ -2699,7 +2680,7 @@ abstract public class GeckoApp
mMainHandler.post(new Runnable() { mMainHandler.post(new Runnable() {
public void run() { public void run() {
mLayerController.getView().setVisibility(View.INVISIBLE); mLayerClient.getView().setVisibility(View.INVISIBLE);
} }
}); });
} }

Просмотреть файл

@ -10,7 +10,6 @@ import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.GfxInfoThread; import org.mozilla.gecko.gfx.GfxInfoThread;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics; import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.IntSize; import org.mozilla.gecko.gfx.IntSize;
import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.gfx.LayerView; import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.RectUtils; import org.mozilla.gecko.gfx.RectUtils;
import org.mozilla.gecko.gfx.ScreenshotLayer; import org.mozilla.gecko.gfx.ScreenshotLayer;
@ -539,11 +538,11 @@ public class GeckoAppShell
// Called on the UI thread after Gecko loads. // Called on the UI thread after Gecko loads.
private static void geckoLoaded() { private static void geckoLoaded() {
final LayerController layerController = GeckoApp.mAppContext.getLayerController(); final GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
LayerView v = layerController.getView(); LayerView v = layerClient.getView();
mInputConnection = GeckoInputConnection.create(v); mInputConnection = GeckoInputConnection.create(v);
v.setInputConnectionHandler(mInputConnection); v.setInputConnectionHandler(mInputConnection);
layerController.setForceRedraw(); layerClient.setForceRedraw();
} }
static void sendPendingEventsToGecko() { static void sendPendingEventsToGecko() {
@ -1425,8 +1424,8 @@ public class GeckoAppShell
// Don't perform haptic feedback if a vibration is currently playing, // Don't perform haptic feedback if a vibration is currently playing,
// because the haptic feedback will nuke the vibration. // because the haptic feedback will nuke the vibration.
if (!sVibrationMaybePlaying || System.nanoTime() >= sVibrationEndTime) { if (!sVibrationMaybePlaying || System.nanoTime() >= sVibrationEndTime) {
LayerController layerController = GeckoApp.mAppContext.getLayerController(); GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
LayerView layerView = layerController.getView(); LayerView layerView = layerClient.getView();
layerView.performHapticFeedback(aIsLongPress ? layerView.performHapticFeedback(aIsLongPress ?
HapticFeedbackConstants.LONG_PRESS : HapticFeedbackConstants.LONG_PRESS :
HapticFeedbackConstants.VIRTUAL_KEY); HapticFeedbackConstants.VIRTUAL_KEY);
@ -1434,8 +1433,8 @@ public class GeckoAppShell
} }
private static Vibrator vibrator() { private static Vibrator vibrator() {
LayerController layerController = GeckoApp.mAppContext.getLayerController(); GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
LayerView layerView = layerController.getView(); LayerView layerView = layerClient.getView();
return (Vibrator) layerView.getContext().getSystemService(Context.VIBRATOR_SERVICE); return (Vibrator) layerView.getContext().getSystemService(Context.VIBRATOR_SERVICE);
} }
@ -1483,7 +1482,7 @@ public class GeckoAppShell
public static void notifyDefaultPrevented(final boolean defaultPrevented) { public static void notifyDefaultPrevented(final boolean defaultPrevented) {
getMainHandler().post(new Runnable() { getMainHandler().post(new Runnable() {
public void run() { public void run() {
LayerView view = GeckoApp.mAppContext.getLayerController().getView(); LayerView view = GeckoApp.mAppContext.getLayerClient().getView();
view.getTouchEventHandler().handleEventListenerAction(!defaultPrevented); view.getTouchEventHandler().handleEventListenerAction(!defaultPrevented);
} }
}); });
@ -2401,11 +2400,11 @@ class ScreenshotHandler implements Runnable {
} }
private void screenshotWholePage(int tabId) { private void screenshotWholePage(int tabId) {
LayerController layerController = GeckoApp.mAppContext.getLayerController(); GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
if (layerController == null) { if (layerClient == null) {
return; return;
} }
ImmutableViewportMetrics viewport = layerController.getViewportMetrics(); ImmutableViewportMetrics viewport = layerClient.getViewportMetrics();
RectF pageRect = viewport.getCssPageRect(); RectF pageRect = viewport.getCssPageRect();
if (FloatUtils.fuzzyEquals(pageRect.width(), 0) || FloatUtils.fuzzyEquals(pageRect.height(), 0)) { if (FloatUtils.fuzzyEquals(pageRect.width(), 0) || FloatUtils.fuzzyEquals(pageRect.height(), 0)) {
@ -2505,14 +2504,14 @@ class ScreenshotHandler implements Runnable {
return; return;
} }
LayerController layerController = GeckoApp.mAppContext.getLayerController(); GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
if (layerController == null) { if (layerClient == null) {
// we could be in the midst of an activity tear-down and re-start, so guard // we could be in the midst of an activity tear-down and re-start, so guard
// against a null layer controller. // against a null layer controller.
return; return;
} }
ImmutableViewportMetrics viewport = layerController.getViewportMetrics(); ImmutableViewportMetrics viewport = layerClient.getViewportMetrics();
if (RectUtils.fuzzyEquals(mPageRect, viewport.getCssPageRect())) { if (RectUtils.fuzzyEquals(mPageRect, viewport.getCssPageRect())) {
// the page size hasn't changed, so our dirty rect is still valid and we can just // the page size hasn't changed, so our dirty rect is still valid and we can just
// repaint that area // repaint that area
@ -2592,9 +2591,9 @@ class ScreenshotHandler implements Runnable {
// this screenshot has all its slices done, so push it out // this screenshot has all its slices done, so push it out
// to the layer renderer and remove it from the list // to the layer renderer and remove it from the list
} }
LayerController layerController = GeckoApp.mAppContext.getLayerController(); GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
if (layerController != null) { if (layerClient != null) {
layerController.getView().getRenderer().setCheckerboardBitmap( layerClient.getView().getRenderer().setCheckerboardBitmap(
data, bufferWidth, bufferHeight, handler.mPageRect, data, bufferWidth, bufferHeight, handler.mPageRect,
current.getPaintedRegion()); current.getPaintedRegion());
} }

Просмотреть файл

@ -227,7 +227,7 @@ public class GeckoEvent {
public void addMotionPoint(int index, int eventIndex, MotionEvent event) { public void addMotionPoint(int index, int eventIndex, MotionEvent event) {
try { try {
PointF geckoPoint = new PointF(event.getX(eventIndex), event.getY(eventIndex)); PointF geckoPoint = new PointF(event.getX(eventIndex), event.getY(eventIndex));
geckoPoint = GeckoApp.mAppContext.getLayerController().convertViewPointToLayerPoint(geckoPoint); geckoPoint = GeckoApp.mAppContext.getLayerClient().convertViewPointToLayerPoint(geckoPoint);
mPoints[index] = new Point(Math.round(geckoPoint.x), Math.round(geckoPoint.y)); mPoints[index] = new Point(Math.round(geckoPoint.x), Math.round(geckoPoint.y));
mPointIndicies[index] = event.getPointerId(eventIndex); mPointIndicies[index] = event.getPointerId(eventIndex);

Просмотреть файл

@ -5,8 +5,8 @@
package org.mozilla.gecko; package org.mozilla.gecko;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.InputConnectionHandler; import org.mozilla.gecko.gfx.InputConnectionHandler;
import org.mozilla.gecko.gfx.LayerController;
import android.R; import android.R;
import android.content.Context; import android.content.Context;
@ -294,8 +294,8 @@ class GeckoInputConnection
} }
private static View getView() { private static View getView() {
LayerController controller = GeckoApp.mAppContext.getLayerController(); GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
return (controller == null ? null : controller.getView()); return (layerClient == null ? null : layerClient.getView());
} }
private Span getSelection() { private Span getSelection() {

Просмотреть файл

@ -131,7 +131,6 @@ FENNEC_JAVA_FILES = \
gfx/InputConnectionHandler.java \ gfx/InputConnectionHandler.java \
gfx/IntSize.java \ gfx/IntSize.java \
gfx/Layer.java \ gfx/Layer.java \
gfx/LayerController.java \
gfx/LayerRenderer.java \ gfx/LayerRenderer.java \
gfx/LayerView.java \ gfx/LayerView.java \
gfx/PluginLayer.java \ gfx/PluginLayer.java \

Просмотреть файл

@ -5,7 +5,7 @@
package org.mozilla.gecko; package org.mozilla.gecko;
import org.mozilla.gecko.gfx.LayerController; import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
@ -181,11 +181,11 @@ public class PromptService implements OnClickListener, OnCancelListener, OnItemC
} }
public void show(String aTitle, String aText, PromptButton[] aButtons, PromptListItem[] aMenuList, boolean aMultipleSelection) { public void show(String aTitle, String aText, PromptButton[] aButtons, PromptListItem[] aMenuList, boolean aMultipleSelection) {
final LayerController controller = GeckoApp.mAppContext.getLayerController(); final GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
controller.post(new Runnable() { layerClient.post(new Runnable() {
public void run() { public void run() {
// treat actions that show a dialog as if preventDefault by content to prevent panning // treat actions that show a dialog as if preventDefault by content to prevent panning
controller.getPanZoomController().abortPanning(); layerClient.getPanZoomController().abortPanning();
} }
}); });

Просмотреть файл

@ -4,9 +4,9 @@
package org.mozilla.gecko; package org.mozilla.gecko;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.Layer; import org.mozilla.gecko.gfx.Layer;
import org.mozilla.gecko.gfx.Layer.RenderContext; import org.mozilla.gecko.gfx.Layer.RenderContext;
import org.mozilla.gecko.gfx.LayerController;
import org.mozilla.gecko.util.FloatUtils; import org.mozilla.gecko.util.FloatUtils;
import org.json.JSONObject; import org.json.JSONObject;
@ -55,18 +55,18 @@ class TextSelection extends Layer implements GeckoEventListener {
mViewLeft = 0.0f; mViewLeft = 0.0f;
mViewTop = 0.0f; mViewTop = 0.0f;
mViewZoom = 0.0f; mViewZoom = 0.0f;
LayerController layerController = GeckoApp.mAppContext.getLayerController(); GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
if (layerController != null) { if (layerClient != null) {
layerController.getView().addLayer(TextSelection.this); layerClient.getView().addLayer(TextSelection.this);
} }
} }
}); });
} else if (event.equals("TextSelection:HideHandles")) { } else if (event.equals("TextSelection:HideHandles")) {
GeckoApp.mAppContext.mMainHandler.post(new Runnable() { GeckoApp.mAppContext.mMainHandler.post(new Runnable() {
public void run() { public void run() {
LayerController layerController = GeckoApp.mAppContext.getLayerController(); GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
if (layerController != null) { if (layerClient != null) {
layerController.getView().removeLayer(TextSelection.this); layerClient.getView().removeLayer(TextSelection.this);
} }
mStartHandle.setVisibility(View.GONE); mStartHandle.setVisibility(View.GONE);

Просмотреть файл

@ -4,8 +4,8 @@
package org.mozilla.gecko; package org.mozilla.gecko;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics; import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.LayerController;
import org.json.JSONObject; import org.json.JSONObject;
@ -83,15 +83,15 @@ class TextSelectionHandle extends ImageView implements View.OnTouchListener {
mLeft = mLeft + newX - mTouchStartX; mLeft = mLeft + newX - mTouchStartX;
mTop = mTop + newY - mTouchStartY; mTop = mTop + newY - mTouchStartY;
LayerController layerController = GeckoApp.mAppContext.getLayerController(); GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
if (layerController == null) { if (layerClient == null) {
Log.e(LOGTAG, "Can't move selection because layerController is null"); Log.e(LOGTAG, "Can't move selection because layerClient is null");
return; return;
} }
// Send x coordinate on the right side of the start handle, left side of the end handle. // Send x coordinate on the right side of the start handle, left side of the end handle.
float left = (float) mLeft + (mHandleType.equals(HandleType.START) ? mWidth - mShadow : mShadow); float left = (float) mLeft + (mHandleType.equals(HandleType.START) ? mWidth - mShadow : mShadow);
PointF geckoPoint = new PointF(left, (float) mTop); PointF geckoPoint = new PointF(left, (float) mTop);
geckoPoint = layerController.convertViewPointToLayerPoint(geckoPoint); geckoPoint = layerClient.convertViewPointToLayerPoint(geckoPoint);
JSONObject args = new JSONObject(); JSONObject args = new JSONObject();
try { try {
@ -107,14 +107,14 @@ class TextSelectionHandle extends ImageView implements View.OnTouchListener {
} }
void positionFromGecko(int left, int top) { void positionFromGecko(int left, int top) {
LayerController layerController = GeckoApp.mAppContext.getLayerController(); GeckoLayerClient layerClient = GeckoApp.mAppContext.getLayerClient();
if (layerController == null) { if (layerClient == null) {
Log.e(LOGTAG, "Can't position handle because layerController is null"); Log.e(LOGTAG, "Can't position handle because layerClient is null");
return; return;
} }
mGeckoPoint = new PointF((float) left, (float) top); mGeckoPoint = new PointF((float) left, (float) top);
ImmutableViewportMetrics metrics = layerController.getViewportMetrics(); ImmutableViewportMetrics metrics = layerClient.getViewportMetrics();
repositionWithViewport(metrics.viewportRectLeft, metrics.viewportRectTop, metrics.zoomFactor); repositionWithViewport(metrics.viewportRectLeft, metrics.viewportRectTop, metrics.zoomFactor);
} }

Просмотреть файл

@ -10,6 +10,10 @@ import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.GeckoEventResponder; import org.mozilla.gecko.GeckoEventResponder;
import org.mozilla.gecko.Tab; import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs; import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.ZoomConstraints;
import org.mozilla.gecko.ui.PanZoomController;
import org.mozilla.gecko.ui.PanZoomTarget;
import org.mozilla.gecko.ui.SimpleScaleGestureDetector;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
@ -17,20 +21,22 @@ import org.json.JSONObject;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PointF; import android.graphics.PointF;
import android.graphics.RectF; import android.graphics.RectF;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.GestureDetector;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener { public class GeckoLayerClient
implements GeckoEventResponder, LayerView.Listener, PanZoomTarget
{
private static final String LOGTAG = "GeckoLayerClient"; private static final String LOGTAG = "GeckoLayerClient";
private LayerController mLayerController;
private LayerRenderer mLayerRenderer; private LayerRenderer mLayerRenderer;
private boolean mLayerRendererInitialized; private boolean mLayerRendererInitialized;
@ -63,6 +69,33 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
/* This is written by the compositor thread and read by the UI thread. */ /* This is written by the compositor thread and read by the UI thread. */
private volatile boolean mCompositorCreated; private volatile boolean mCompositorCreated;
private boolean mForceRedraw;
/* The current viewport metrics.
* This is volatile so that we can read and write to it from different threads.
* We avoid synchronization to make getting the viewport metrics from
* the compositor as cheap as possible. The viewport is immutable so
* we don't need to worry about anyone mutating it while we're reading from it.
* Specifically:
* 1) reading mViewportMetrics from any thread is fine without synchronization
* 2) writing to mViewportMetrics requires synchronizing on the layer controller object
* 3) whenver reading multiple fields from mViewportMetrics without synchronization (i.e. in
* case 1 above) you should always frist grab a local copy of the reference, and then use
* that because mViewportMetrics might get reassigned in between reading the different
* fields. */
private volatile ImmutableViewportMetrics mViewportMetrics;
private ZoomConstraints mZoomConstraints;
private boolean mGeckoIsReady;
/* The new color for the checkerboard. */
private int mCheckerboardColor;
private boolean mCheckerboardShouldShowChecks;
private final PanZoomController mPanZoomController;
private LayerView mView;
public GeckoLayerClient(Context context) { public GeckoLayerClient(Context context) {
// we can fill these in with dummy values because they are always written // we can fill these in with dummy values because they are always written
// to before being read // to before being read
@ -75,16 +108,28 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
mCurrentViewTransform = new ViewTransform(0, 0, 1); mCurrentViewTransform = new ViewTransform(0, 0, 1);
mCompositorCreated = false; mCompositorCreated = false;
mForceRedraw = true;
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
mViewportMetrics = new ImmutableViewportMetrics(new ViewportMetrics(displayMetrics));
mZoomConstraints = new ZoomConstraints(false);
mCheckerboardColor = Color.WHITE;
mCheckerboardShouldShowChecks = true;
mPanZoomController = new PanZoomController(this);
} }
/** Attaches the root layer to the layer controller so that Gecko appears. */ public void setView(LayerView v) {
void setLayerController(LayerController layerController) { mView = v;
LayerView view = layerController.getView(); mView.connect(this);
}
mLayerController = layerController; /** Attaches to root layer so that Gecko appears. */
public void notifyGeckoReady() {
mGeckoIsReady = true;
mRootLayer = new VirtualLayer(new IntSize(view.getWidth(), view.getHeight())); mRootLayer = new VirtualLayer(new IntSize(mView.getWidth(), mView.getHeight()));
mLayerRenderer = new LayerRenderer(view); mLayerRenderer = new LayerRenderer(mView);
GeckoAppShell.registerGeckoEventListener("Viewport:Update", this); GeckoAppShell.registerGeckoEventListener("Viewport:Update", this);
GeckoAppShell.registerGeckoEventListener("Viewport:PageSize", this); GeckoAppShell.registerGeckoEventListener("Viewport:PageSize", this);
@ -92,9 +137,8 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
GeckoAppShell.registerGeckoEventListener("Checkerboard:Toggle", this); GeckoAppShell.registerGeckoEventListener("Checkerboard:Toggle", this);
GeckoAppShell.registerGeckoEventListener("Preferences:Data", this); GeckoAppShell.registerGeckoEventListener("Preferences:Data", this);
view.setListener(this); mView.setListener(this);
view.setLayerRenderer(mLayerRenderer); mView.setLayerRenderer(mLayerRenderer);
layerController.setRoot(mRootLayer);
sendResizeEventIfNecessary(true); sendResizeEventIfNecessary(true);
@ -105,6 +149,7 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
} }
public void destroy() { public void destroy() {
mPanZoomController.destroy();
GeckoAppShell.unregisterGeckoEventListener("Viewport:Update", this); GeckoAppShell.unregisterGeckoEventListener("Viewport:Update", this);
GeckoAppShell.unregisterGeckoEventListener("Viewport:PageSize", this); GeckoAppShell.unregisterGeckoEventListener("Viewport:PageSize", this);
GeckoAppShell.unregisterGeckoEventListener("Viewport:CalculateDisplayPort", this); GeckoAppShell.unregisterGeckoEventListener("Viewport:CalculateDisplayPort", this);
@ -112,17 +157,76 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
GeckoAppShell.unregisterGeckoEventListener("Preferences:Data", this); GeckoAppShell.unregisterGeckoEventListener("Preferences:Data", this);
} }
DisplayPortMetrics getDisplayPort() { /**
return mDisplayPort; * Returns true if this client is fine with performing a redraw operation or false if it
* would prefer that the action didn't take place.
*/
public boolean getRedrawHint() {
if (mForceRedraw) {
mForceRedraw = false;
return true;
}
if (!mPanZoomController.getRedrawHint()) {
return false;
}
return DisplayPortCalculator.aboutToCheckerboard(mViewportMetrics,
mPanZoomController.getVelocityVector(), mDisplayPort);
}
public Layer getRoot() {
return mGeckoIsReady ? mRootLayer : null;
}
public LayerView getView() {
return mView;
}
public FloatSize getViewportSize() {
return mViewportMetrics.getSize();
}
/**
* The view calls this function to indicate that the viewport changed size. It must hold the
* monitor while calling it.
*
* TODO: Refactor this to use an interface. Expose that interface only to the view and not
* to the layer client. That way, the layer client won't be tempted to call this, which might
* result in an infinite loop.
*/
public void setViewportSize(FloatSize size) {
ViewportMetrics viewportMetrics = new ViewportMetrics(mViewportMetrics);
viewportMetrics.setSize(size);
mViewportMetrics = new ImmutableViewportMetrics(viewportMetrics);
if (mGeckoIsReady) {
viewportSizeChanged();
}
}
public PanZoomController getPanZoomController() {
return mPanZoomController;
}
public GestureDetector.OnGestureListener getGestureListener() {
return mPanZoomController;
}
public SimpleScaleGestureDetector.SimpleScaleGestureListener getScaleGestureListener() {
return mPanZoomController;
}
public GestureDetector.OnDoubleTapListener getDoubleTapListener() {
return mPanZoomController;
} }
/* Informs Gecko that the screen size has changed. */ /* Informs Gecko that the screen size has changed. */
private void sendResizeEventIfNecessary(boolean force) { private void sendResizeEventIfNecessary(boolean force) {
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
View view = mLayerController.getView();
IntSize newScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels); IntSize newScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels);
IntSize newWindowSize = new IntSize(view.getWidth(), view.getHeight()); IntSize newWindowSize = new IntSize(mView.getWidth(), mView.getHeight());
boolean screenSizeChanged = !mScreenSize.equals(newScreenSize); boolean screenSizeChanged = !mScreenSize.equals(newScreenSize);
boolean windowSizeChanged = !mWindowSize.equals(newWindowSize); boolean windowSizeChanged = !mWindowSize.equals(newWindowSize);
@ -163,15 +267,37 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
GeckoAppShell.viewSizeChanged(); GeckoAppShell.viewSizeChanged();
} }
/** Sets the current page rect. You must hold the monitor while calling this. */
private void setPageRect(RectF rect, RectF cssRect) {
// Since the "rect" is always just a multiple of "cssRect" we don't need to
// check both; this function assumes that both "rect" and "cssRect" are relative
// the zoom factor in mViewportMetrics.
if (mViewportMetrics.getCssPageRect().equals(cssRect))
return;
ViewportMetrics viewportMetrics = new ViewportMetrics(mViewportMetrics);
viewportMetrics.setPageRect(rect, cssRect);
mViewportMetrics = new ImmutableViewportMetrics(viewportMetrics);
// Page size is owned by the layer client, so no need to notify it of
// this change.
post(new Runnable() {
public void run() {
mPanZoomController.pageRectUpdated();
mView.requestRender();
}
});
}
void adjustViewport(DisplayPortMetrics displayPort) { void adjustViewport(DisplayPortMetrics displayPort) {
ImmutableViewportMetrics metrics = mLayerController.getViewportMetrics(); ImmutableViewportMetrics metrics = getViewportMetrics();
ViewportMetrics clampedMetrics = new ViewportMetrics(metrics); ViewportMetrics clampedMetrics = new ViewportMetrics(metrics);
clampedMetrics.setViewport(clampedMetrics.getClampedViewport()); clampedMetrics.setViewport(clampedMetrics.getClampedViewport());
if (displayPort == null) { if (displayPort == null) {
displayPort = DisplayPortCalculator.calculate(metrics, displayPort = DisplayPortCalculator.calculate(metrics, mPanZoomController.getVelocityVector());
mLayerController.getPanZoomController().getVelocityVector());
} }
mDisplayPort = displayPort; mDisplayPort = displayPort;
@ -184,6 +310,17 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
GeckoAppShell.sendEventToGecko(GeckoEvent.createViewportEvent(clampedMetrics, displayPort)); GeckoAppShell.sendEventToGecko(GeckoEvent.createViewportEvent(clampedMetrics, displayPort));
} }
/** Aborts any pan/zoom animation that is currently in progress. */
private void abortPanZoomAnimation() {
if (mPanZoomController != null) {
post(new Runnable() {
public void run() {
mPanZoomController.abortAnimation();
}
});
}
}
/** /**
* The different types of Viewport messages handled. All viewport events * The different types of Viewport messages handled. All viewport events
* expect a display-port to be returned, but can handle one not being * expect a display-port to be returned, but can handle one not being
@ -197,9 +334,9 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
/** Viewport message handler. */ /** Viewport message handler. */
private void handleViewportMessage(JSONObject message, ViewportMessageType type) throws JSONException { private void handleViewportMessage(JSONObject message, ViewportMessageType type) throws JSONException {
ViewportMetrics messageMetrics = new ViewportMetrics(message); ViewportMetrics messageMetrics = new ViewportMetrics(message);
synchronized (mLayerController) { synchronized (this) {
final ViewportMetrics newMetrics; final ViewportMetrics newMetrics;
ImmutableViewportMetrics oldMetrics = mLayerController.getViewportMetrics(); ImmutableViewportMetrics oldMetrics = getViewportMetrics();
switch (type) { switch (type) {
default: default:
@ -207,7 +344,7 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
newMetrics = messageMetrics; newMetrics = messageMetrics;
// Keep the old viewport size // Keep the old viewport size
newMetrics.setSize(oldMetrics.getSize()); newMetrics.setSize(oldMetrics.getSize());
mLayerController.abortPanZoomAnimation(); abortPanZoomAnimation();
break; break;
case PAGE_SIZE: case PAGE_SIZE:
// adjust the page dimensions to account for differences in zoom // adjust the page dimensions to account for differences in zoom
@ -219,13 +356,13 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
break; break;
} }
mLayerController.post(new Runnable() { post(new Runnable() {
public void run() { public void run() {
mGeckoViewport = newMetrics; mGeckoViewport = newMetrics;
} }
}); });
mLayerController.setViewportMetrics(newMetrics); setViewportMetrics(newMetrics);
mDisplayPort = DisplayPortCalculator.calculate(mLayerController.getViewportMetrics(), null); mDisplayPort = DisplayPortCalculator.calculate(getViewportMetrics(), null);
} }
mReturnDisplayPort = mDisplayPort; mReturnDisplayPort = mDisplayPort;
} }
@ -242,7 +379,7 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
mReturnDisplayPort = DisplayPortCalculator.calculate(newMetrics, null); mReturnDisplayPort = DisplayPortCalculator.calculate(newMetrics, null);
} else if ("Checkerboard:Toggle".equals(event)) { } else if ("Checkerboard:Toggle".equals(event)) {
boolean showChecks = message.getBoolean("value"); boolean showChecks = message.getBoolean("value");
mLayerController.setCheckerboardShowChecks(showChecks); setCheckerboardShowChecks(showChecks);
Log.i(LOGTAG, "Showing checks: " + showChecks); Log.i(LOGTAG, "Showing checks: " + showChecks);
} else if ("Preferences:Data".equals(event)) { } else if ("Preferences:Data".equals(event)) {
JSONArray jsonPrefs = message.getJSONArray("preferences"); JSONArray jsonPrefs = message.getJSONArray("preferences");
@ -286,13 +423,6 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
} }
} }
void geometryChanged() {
/* Let Gecko know if the screensize has changed */
sendResizeEventIfNecessary(false);
if (mLayerController.getRedrawHint())
adjustViewport(null);
}
/* /*
* This function returns the last viewport that we sent to Gecko. If any additional events are * This function returns the last viewport that we sent to Gecko. If any additional events are
* being sent to Gecko that are relative on the Gecko viewport position, they must (a) be relative * being sent to Gecko that are relative on the Gecko viewport position, they must (a) be relative
@ -305,6 +435,28 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
return mGeckoViewport; return mGeckoViewport;
} }
public boolean checkerboardShouldShowChecks() {
return mCheckerboardShouldShowChecks;
}
public int getCheckerboardColor() {
return mCheckerboardColor;
}
public void setCheckerboardShowChecks(boolean showChecks) {
mCheckerboardShouldShowChecks = showChecks;
mView.requestRender();
}
public void setCheckerboardColor(int newColor) {
mCheckerboardColor = newColor;
mView.requestRender();
}
public void setZoomConstraints(ZoomConstraints constraints) {
mZoomConstraints = constraints;
}
/** This function is invoked by Gecko via JNI; be careful when modifying signature. /** This function is invoked by Gecko via JNI; be careful when modifying signature.
* The compositor invokes this function just before compositing a frame where the document * The compositor invokes this function just before compositing a frame where the document
* is different from the document composited on the last frame. In these cases, the viewport * is different from the document composited on the last frame. In these cases, the viewport
@ -315,26 +467,26 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
public void setFirstPaintViewport(float offsetX, float offsetY, float zoom, public void setFirstPaintViewport(float offsetX, float offsetY, float zoom,
float pageLeft, float pageTop, float pageRight, float pageBottom, float pageLeft, float pageTop, float pageRight, float pageBottom,
float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) { float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) {
synchronized (mLayerController) { synchronized (this) {
final ViewportMetrics currentMetrics = new ViewportMetrics(mLayerController.getViewportMetrics()); final ViewportMetrics currentMetrics = new ViewportMetrics(getViewportMetrics());
currentMetrics.setOrigin(new PointF(offsetX, offsetY)); currentMetrics.setOrigin(new PointF(offsetX, offsetY));
currentMetrics.setZoomFactor(zoom); currentMetrics.setZoomFactor(zoom);
currentMetrics.setPageRect(new RectF(pageLeft, pageTop, pageRight, pageBottom), currentMetrics.setPageRect(new RectF(pageLeft, pageTop, pageRight, pageBottom),
new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom)); new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom));
// Since we have switched to displaying a different document, we need to update any // Since we have switched to displaying a different document, we need to update any
// viewport-related state we have lying around. This includes mGeckoViewport and the // viewport-related state we have lying around. This includes mGeckoViewport and
// viewport in mLayerController. Usually this information is updated via handleViewportMessage // mViewportMetrics. Usually this information is updated via handleViewportMessage
// while we remain on the same document. // while we remain on the same document.
mLayerController.post(new Runnable() { post(new Runnable() {
public void run() { public void run() {
mGeckoViewport = currentMetrics; mGeckoViewport = currentMetrics;
} }
}); });
mLayerController.setViewportMetrics(currentMetrics); setViewportMetrics(currentMetrics);
Tab tab = Tabs.getInstance().getSelectedTab(); Tab tab = Tabs.getInstance().getSelectedTab();
mLayerController.setCheckerboardColor(tab.getCheckerboardColor()); setCheckerboardColor(tab.getCheckerboardColor());
mLayerController.setZoomConstraints(tab.getZoomConstraints()); setZoomConstraints(tab.getZoomConstraints());
// At this point, we have just switched to displaying a different document than we // At this point, we have just switched to displaying a different document than we
// we previously displaying. This means we need to abort any panning/zooming animations // we previously displaying. This means we need to abort any panning/zooming animations
@ -343,12 +495,12 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
// sends the request after aborting the animation. The display port request is actually // sends the request after aborting the animation. The display port request is actually
// a full viewport update, which is fine because if browser.js has somehow moved to // a full viewport update, which is fine because if browser.js has somehow moved to
// be out of sync with this first-paint viewport, then we force them back in sync. // be out of sync with this first-paint viewport, then we force them back in sync.
mLayerController.abortPanZoomAnimation(); abortPanZoomAnimation();
mLayerController.getView().setPaintState(LayerView.PAINT_BEFORE_FIRST); mView.setPaintState(LayerView.PAINT_BEFORE_FIRST);
} }
DisplayPortCalculator.resetPageState(); DisplayPortCalculator.resetPageState();
mDrawTimingQueue.reset(); mDrawTimingQueue.reset();
mLayerController.getView().getRenderer().resetCheckerboard(); mView.getRenderer().resetCheckerboard();
GeckoAppShell.screenshotWholePage(Tabs.getInstance().getSelectedTab()); GeckoAppShell.screenshotWholePage(Tabs.getInstance().getSelectedTab());
} }
@ -359,10 +511,10 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
* function will be invoked before syncViewportInfo. * function will be invoked before syncViewportInfo.
*/ */
public void setPageRect(float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) { public void setPageRect(float cssPageLeft, float cssPageTop, float cssPageRight, float cssPageBottom) {
synchronized (mLayerController) { synchronized (this) {
RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom); RectF cssPageRect = new RectF(cssPageLeft, cssPageTop, cssPageRight, cssPageBottom);
float ourZoom = mLayerController.getViewportMetrics().zoomFactor; float ourZoom = getViewportMetrics().zoomFactor;
mLayerController.setPageRect(RectUtils.scale(cssPageRect, ourZoom), cssPageRect); setPageRect(RectUtils.scale(cssPageRect, ourZoom), cssPageRect);
// Here the page size of the document has changed, but the document being displayed // Here the page size of the document has changed, but the document being displayed
// is still the same. Therefore, we don't need to send anything to browser.js; any // is still the same. Therefore, we don't need to send anything to browser.js; any
// changes we need to make to the display port will get sent the next time we call // changes we need to make to the display port will get sent the next time we call
@ -380,14 +532,13 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
* which would avoid the copy into mCurrentViewTransform. * which would avoid the copy into mCurrentViewTransform.
*/ */
public ViewTransform syncViewportInfo(int x, int y, int width, int height, float resolution, boolean layersUpdated) { public ViewTransform syncViewportInfo(int x, int y, int width, int height, float resolution, boolean layersUpdated) {
// getViewportMetrics is thread safe so we don't need to synchronize // getViewportMetrics is thread safe so we don't need to synchronize.
// on mLayerController.
// We save the viewport metrics here, so we later use it later in // We save the viewport metrics here, so we later use it later in
// createFrame (which will be called by nsWindow::DrawWindowUnderlay on // createFrame (which will be called by nsWindow::DrawWindowUnderlay on
// the native side, by the compositor). The LayerController's viewport // the native side, by the compositor). The viewport
// metrics can change between here and there, as it's accessed outside // metrics can change between here and there, as it's accessed outside
// of the compositor thread. // of the compositor thread.
mFrameMetrics = mLayerController.getViewportMetrics(); mFrameMetrics = getViewportMetrics();
mCurrentViewTransform.x = mFrameMetrics.viewportRectLeft; mCurrentViewTransform.x = mFrameMetrics.viewportRectLeft;
mCurrentViewTransform.y = mFrameMetrics.viewportRectTop; mCurrentViewTransform.y = mFrameMetrics.viewportRectTop;
@ -438,6 +589,14 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
mLayerRenderer.deactivateDefaultProgram(); mLayerRenderer.deactivateDefaultProgram();
} }
void geometryChanged() {
/* Let Gecko know if the screensize has changed */
sendResizeEventIfNecessary(false);
if (getRedrawHint()) {
adjustViewport(null);
}
}
/** Implementation of LayerView.Listener */ /** Implementation of LayerView.Listener */
public void renderRequested() { public void renderRequested() {
GeckoAppShell.scheduleComposite(); GeckoAppShell.scheduleComposite();
@ -472,7 +631,7 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
/** Implementation of LayerView.Listener */ /** Implementation of LayerView.Listener */
public void surfaceChanged(int width, int height) { public void surfaceChanged(int width, int height) {
mLayerController.setViewportSize(new FloatSize(width, height)); setViewportSize(new FloatSize(width, height));
// We need to make this call even when the compositor isn't currently // We need to make this call even when the compositor isn't currently
// paused (e.g. during an orientation change), to make the compositor // paused (e.g. during an orientation change), to make the compositor
@ -486,6 +645,89 @@ public class GeckoLayerClient implements GeckoEventResponder, LayerView.Listener
mCompositorCreated = true; mCompositorCreated = true;
} }
/** Implementation of PanZoomTarget */
public ImmutableViewportMetrics getViewportMetrics() {
return mViewportMetrics;
}
/** Implementation of PanZoomTarget */
public ZoomConstraints getZoomConstraints() {
return mZoomConstraints;
}
/** Implementation of PanZoomTarget */
public void setAnimationTarget(ViewportMetrics viewport) {
if (mGeckoIsReady) {
// We know what the final viewport of the animation is going to be, so
// immediately request a draw of that area by setting the display port
// accordingly. This way we should have the content pre-rendered by the
// time the animation is done.
ImmutableViewportMetrics metrics = new ImmutableViewportMetrics(viewport);
DisplayPortMetrics displayPort = DisplayPortCalculator.calculate(metrics, null);
adjustViewport(displayPort);
}
}
/** Implementation of PanZoomTarget
* You must hold the monitor while calling this.
*/
public void setViewportMetrics(ViewportMetrics viewport) {
mViewportMetrics = new ImmutableViewportMetrics(viewport);
mView.requestRender();
if (mGeckoIsReady) {
geometryChanged();
}
}
/** Implementation of PanZoomTarget */
public void setForceRedraw() {
mForceRedraw = true;
if (mGeckoIsReady) {
geometryChanged();
}
}
/** Implementation of PanZoomTarget */
public boolean post(Runnable action) {
return mView.post(action);
}
/** Implementation of PanZoomTarget */
public Object getLock() {
return this;
}
/** Implementation of PanZoomTarget
* Converts a point from layer view coordinates to layer coordinates. In other words, given a
* point measured in pixels from the top left corner of the layer view, returns the point in
* pixels measured from the last scroll position we sent to Gecko, in CSS pixels. Assuming the
* events being sent to Gecko are processed in FIFO order, this calculation should always be
* correct.
*/
public PointF convertViewPointToLayerPoint(PointF viewPoint) {
if (!mGeckoIsReady) {
return null;
}
ImmutableViewportMetrics viewportMetrics = mViewportMetrics;
PointF origin = viewportMetrics.getOrigin();
float zoom = viewportMetrics.zoomFactor;
ViewportMetrics geckoViewport = getGeckoViewportMetrics();
PointF geckoOrigin = geckoViewport.getOrigin();
float geckoZoom = geckoViewport.getZoomFactor();
// viewPoint + origin gives the coordinate in device pixels from the top-left corner of the page.
// Divided by zoom, this gives us the coordinate in CSS pixels from the top-left corner of the page.
// geckoOrigin / geckoZoom is where Gecko thinks it is (scrollTo position) in CSS pixels from
// the top-left corner of the page. Subtracting the two gives us the offset of the viewPoint from
// the current Gecko coordinate in CSS pixels.
PointF layerPoint = new PointF(
((viewPoint.x + origin.x) / zoom) - (geckoOrigin.x / geckoZoom),
((viewPoint.y + origin.y) / zoom) - (geckoOrigin.y / geckoZoom));
return layerPoint;
}
/** Used by robocop for testing purposes. Not for production use! This is called via reflection by robocop. */ /** Used by robocop for testing purposes. Not for production use! This is called via reflection by robocop. */
public void setDrawListener(DrawListener listener) { public void setDrawListener(DrawListener listener) {
mDrawListener = listener; mDrawListener = listener;

Просмотреть файл

@ -1,270 +0,0 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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 org.mozilla.gecko.gfx;
import org.mozilla.gecko.ZoomConstraints;
import org.mozilla.gecko.ui.PanZoomController;
import org.mozilla.gecko.ui.PanZoomTarget;
import org.mozilla.gecko.ui.SimpleScaleGestureDetector;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.DisplayMetrics;
import android.view.GestureDetector;
/**
* The layer controller manages a tile that represents the visible page. It does panning and
* zooming natively by delegating to a panning/zooming controller. Touch events can be dispatched
* to a higher-level view.
*
* Many methods require that the monitor be held, with a synchronized (controller) { ... } block.
*/
public class LayerController implements PanZoomTarget {
private static final String LOGTAG = "GeckoLayerController";
private Layer mRootLayer; /* The root layer. */
private LayerView mView; /* The main rendering view. */
private Context mContext; /* The current context. */
/* This is volatile so that we can read and write to it from different threads.
* We avoid synchronization to make getting the viewport metrics from
* the compositor as cheap as possible. The viewport is immutable so
* we don't need to worry about anyone mutating it while we're reading from it.
* Specifically:
* 1) reading mViewportMetrics from any thread is fine without synchronization
* 2) writing to mViewportMetrics requires synchronizing on the layer controller object
* 3) whenver reading multiple fields from mViewportMetrics without synchronization (i.e. in
* case 1 above) you should always frist grab a local copy of the reference, and then use
* that because mViewportMetrics might get reassigned in between reading the different
* fields. */
private volatile ImmutableViewportMetrics mViewportMetrics; /* The current viewport metrics. */
/*
* The panning and zooming controller, which interprets pan and zoom gestures for us and
* updates our visible rect appropriately.
*/
private PanZoomController mPanZoomController;
private GeckoLayerClient mLayerClient; /* The layer client. */
/* The new color for the checkerboard. */
private int mCheckerboardColor = Color.WHITE;
private boolean mCheckerboardShouldShowChecks;
private ZoomConstraints mZoomConstraints;
private boolean mForceRedraw;
public LayerController(Context context) {
mContext = context;
mForceRedraw = true;
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
mViewportMetrics = new ImmutableViewportMetrics(new ViewportMetrics(displayMetrics));
mPanZoomController = new PanZoomController(this);
mCheckerboardShouldShowChecks = true;
mZoomConstraints = new ZoomConstraints(false);
}
public void setView(LayerView v) {
mView = v;
mView.connect(this);
}
public void setRoot(Layer layer) { mRootLayer = layer; }
public void setLayerClient(GeckoLayerClient layerClient) {
mLayerClient = layerClient;
layerClient.setLayerController(this);
}
public void destroy() {
mPanZoomController.destroy();
}
public void setForceRedraw() {
mForceRedraw = true;
notifyLayerClientOfGeometryChange();
}
public Layer getRoot() { return mRootLayer; }
public LayerView getView() { return mView; }
public Context getContext() { return mContext; }
public ImmutableViewportMetrics getViewportMetrics() { return mViewportMetrics; }
public Object getLock() { return this; }
public FloatSize getViewportSize() {
return mViewportMetrics.getSize();
}
public PanZoomController getPanZoomController() { return mPanZoomController; }
public GestureDetector.OnGestureListener getGestureListener() { return mPanZoomController; }
public SimpleScaleGestureDetector.SimpleScaleGestureListener getScaleGestureListener() {
return mPanZoomController;
}
public GestureDetector.OnDoubleTapListener getDoubleTapListener() { return mPanZoomController; }
/**
* The view calls this function to indicate that the viewport changed size. It must hold the
* monitor while calling it.
*
* TODO: Refactor this to use an interface. Expose that interface only to the view and not
* to the layer client. That way, the layer client won't be tempted to call this, which might
* result in an infinite loop.
*/
public void setViewportSize(FloatSize size) {
ViewportMetrics viewportMetrics = new ViewportMetrics(mViewportMetrics);
viewportMetrics.setSize(size);
mViewportMetrics = new ImmutableViewportMetrics(viewportMetrics);
if (mLayerClient != null) {
mLayerClient.viewportSizeChanged();
}
}
/** Sets the current page rect. You must hold the monitor while calling this. */
public void setPageRect(RectF rect, RectF cssRect) {
// Since the "rect" is always just a multiple of "cssRect" we don't need to
// check both; this function assumes that both "rect" and "cssRect" are relative
// the zoom factor in mViewportMetrics.
if (mViewportMetrics.getCssPageRect().equals(cssRect))
return;
ViewportMetrics viewportMetrics = new ViewportMetrics(mViewportMetrics);
viewportMetrics.setPageRect(rect, cssRect);
mViewportMetrics = new ImmutableViewportMetrics(viewportMetrics);
// Page size is owned by the layer client, so no need to notify it of
// this change.
mView.post(new Runnable() {
public void run() {
mPanZoomController.pageRectUpdated();
mView.requestRender();
}
});
}
/**
* Sets the entire viewport metrics at once.
* You must hold the monitor while calling this.
*/
public void setViewportMetrics(ViewportMetrics viewport) {
mViewportMetrics = new ImmutableViewportMetrics(viewport);
mView.requestRender();
notifyLayerClientOfGeometryChange();
}
public void setAnimationTarget(ViewportMetrics viewport) {
if (mLayerClient != null) {
// We know what the final viewport of the animation is going to be, so
// immediately request a draw of that area by setting the display port
// accordingly. This way we should have the content pre-rendered by the
// time the animation is done.
ImmutableViewportMetrics metrics = new ImmutableViewportMetrics(viewport);
DisplayPortMetrics displayPort = DisplayPortCalculator.calculate(metrics, null);
mLayerClient.adjustViewport(displayPort);
}
}
public boolean post(Runnable action) { return mView.post(action); }
private void notifyLayerClientOfGeometryChange() {
if (mLayerClient != null)
mLayerClient.geometryChanged();
}
/** Aborts any pan/zoom animation that is currently in progress. */
public void abortPanZoomAnimation() {
if (mPanZoomController != null) {
mView.post(new Runnable() {
public void run() {
mPanZoomController.abortAnimation();
}
});
}
}
/**
* Returns true if this controller is fine with performing a redraw operation or false if it
* would prefer that the action didn't take place.
*/
public boolean getRedrawHint() {
if (mForceRedraw) {
mForceRedraw = false;
return true;
}
if (!mPanZoomController.getRedrawHint()) {
return false;
}
return DisplayPortCalculator.aboutToCheckerboard(mViewportMetrics,
mPanZoomController.getVelocityVector(), mLayerClient.getDisplayPort());
}
/**
* Converts a point from layer view coordinates to layer coordinates. In other words, given a
* point measured in pixels from the top left corner of the layer view, returns the point in
* pixels measured from the last scroll position we sent to Gecko, in CSS pixels. Assuming the
* events being sent to Gecko are processed in FIFO order, this calculation should always be
* correct.
*/
public PointF convertViewPointToLayerPoint(PointF viewPoint) {
if (mLayerClient == null) {
return null;
}
ImmutableViewportMetrics viewportMetrics = mViewportMetrics;
PointF origin = viewportMetrics.getOrigin();
float zoom = viewportMetrics.zoomFactor;
ViewportMetrics geckoViewport = mLayerClient.getGeckoViewportMetrics();
PointF geckoOrigin = geckoViewport.getOrigin();
float geckoZoom = geckoViewport.getZoomFactor();
// viewPoint + origin gives the coordinate in device pixels from the top-left corner of the page.
// Divided by zoom, this gives us the coordinate in CSS pixels from the top-left corner of the page.
// geckoOrigin / geckoZoom is where Gecko thinks it is (scrollTo position) in CSS pixels from
// the top-left corner of the page. Subtracting the two gives us the offset of the viewPoint from
// the current Gecko coordinate in CSS pixels.
PointF layerPoint = new PointF(
((viewPoint.x + origin.x) / zoom) - (geckoOrigin.x / geckoZoom),
((viewPoint.y + origin.y) / zoom) - (geckoOrigin.y / geckoZoom));
return layerPoint;
}
/** Retrieves whether we should show checkerboard checks or not. */
public boolean checkerboardShouldShowChecks() {
return mCheckerboardShouldShowChecks;
}
/** Retrieves the color that the checkerboard should be. */
public int getCheckerboardColor() {
return mCheckerboardColor;
}
/** Sets whether or not the checkerboard should show checkmarks. */
public void setCheckerboardShowChecks(boolean showChecks) {
mCheckerboardShouldShowChecks = showChecks;
mView.requestRender();
}
/** Sets a new color for the checkerboard. */
public void setCheckerboardColor(int newColor) {
mCheckerboardColor = newColor;
mView.requestRender();
}
public void setZoomConstraints(ZoomConstraints constraints) {
mZoomConstraints = constraints;
}
public ZoomConstraints getZoomConstraints() {
return mZoomConstraints;
}
}

Просмотреть файл

@ -445,7 +445,7 @@ public class LayerRenderer {
mUpdated = true; mUpdated = true;
Layer rootLayer = mView.getController().getRoot(); Layer rootLayer = mView.getLayerClient().getRoot();
if (!mPageContext.fuzzyEquals(mLastPageContext)) { if (!mPageContext.fuzzyEquals(mLastPageContext)) {
// the viewport or page changed, so show the scrollbars again // the viewport or page changed, so show the scrollbars again
@ -518,7 +518,7 @@ public class LayerRenderer {
GLES20.glDisable(GLES20.GL_SCISSOR_TEST); GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
/* Update background color. */ /* Update background color. */
mBackgroundColor = mView.getController().getCheckerboardColor(); mBackgroundColor = mView.getLayerClient().getCheckerboardColor();
/* Clear to the page background colour. The bits set here need to /* Clear to the page background colour. The bits set here need to
* match up with those used in gfx/layers/opengl/LayerManagerOGL.cpp. * match up with those used in gfx/layers/opengl/LayerManagerOGL.cpp.
@ -543,9 +543,9 @@ public class LayerRenderer {
/* Draw the 'checkerboard'. We use gfx.show_checkerboard_pattern to /* Draw the 'checkerboard'. We use gfx.show_checkerboard_pattern to
* determine whether to draw the screenshot layer. * determine whether to draw the screenshot layer.
*/ */
if (mView.getController().checkerboardShouldShowChecks()) { if (mView.getLayerClient().checkerboardShouldShowChecks()) {
/* Find the area the root layer will render into, to mask the checkerboard layer */ /* Find the area the root layer will render into, to mask the checkerboard layer */
Rect rootMask = getMaskForLayer(mView.getController().getRoot()); Rect rootMask = getMaskForLayer(mView.getLayerClient().getRoot());
mCheckerboardLayer.setMask(rootMask); mCheckerboardLayer.setMask(rootMask);
/* Scissor around the page-rect, in case the page has shrunk /* Scissor around the page-rect, in case the page has shrunk
@ -558,7 +558,7 @@ public class LayerRenderer {
// Draws the layer the client added to us. // Draws the layer the client added to us.
void drawRootLayer() { void drawRootLayer() {
Layer rootLayer = mView.getController().getRoot(); Layer rootLayer = mView.getLayerClient().getRoot();
if (rootLayer == null) { if (rootLayer == null) {
return; return;
} }
@ -590,7 +590,7 @@ public class LayerRenderer {
mHorizScrollLayer.draw(mPageContext); mHorizScrollLayer.draw(mPageContext);
/* Measure how much of the screen is checkerboarding */ /* Measure how much of the screen is checkerboarding */
Layer rootLayer = mView.getController().getRoot(); Layer rootLayer = mView.getLayerClient().getRoot();
if ((rootLayer != null) && if ((rootLayer != null) &&
(mProfileRender || PanningPerfAPI.isRecordingCheckerboard())) { (mProfileRender || PanningPerfAPI.isRecordingCheckerboard())) {
// Find out how much of the viewport area is valid // Find out how much of the viewport area is valid

Просмотреть файл

@ -34,15 +34,12 @@ import java.lang.reflect.Method;
/** /**
* A view rendered by the layer compositor. * A view rendered by the layer compositor.
* *
* This view delegates to LayerRenderer to actually do the drawing. Its role is largely that of a
* mediator between the LayerRenderer and the LayerController.
*
* Note that LayerView is accessed by Robocop via reflection. * Note that LayerView is accessed by Robocop via reflection.
*/ */
public class LayerView extends FrameLayout { public class LayerView extends FrameLayout {
private static String LOGTAG = "GeckoLayerView"; private static String LOGTAG = "GeckoLayerView";
private LayerController mController; private GeckoLayerClient mLayerClient;
private TouchEventHandler mTouchEventHandler; private TouchEventHandler mTouchEventHandler;
private GLController mGLController; private GLController mGLController;
private InputConnectionHandler mInputConnectionHandler; private InputConnectionHandler mInputConnectionHandler;
@ -98,9 +95,9 @@ public class LayerView extends FrameLayout {
mGLController = new GLController(this); mGLController = new GLController(this);
} }
void connect(LayerController controller) { void connect(GeckoLayerClient layerClient) {
mController = controller; mLayerClient = layerClient;
mTouchEventHandler = new TouchEventHandler(getContext(), this, mController); mTouchEventHandler = new TouchEventHandler(getContext(), this, layerClient);
mRenderer = new LayerRenderer(this); mRenderer = new LayerRenderer(this);
mInputConnectionHandler = null; mInputConnectionHandler = null;
@ -125,12 +122,12 @@ public class LayerView extends FrameLayout {
return mTouchEventHandler.handleEvent(event); return mTouchEventHandler.handleEvent(event);
} }
public LayerController getController() { return mController; } public GeckoLayerClient getLayerClient() { return mLayerClient; }
public TouchEventHandler getTouchEventHandler() { return mTouchEventHandler; } public TouchEventHandler getTouchEventHandler() { return mTouchEventHandler; }
/** The LayerRenderer calls this to indicate that the window has changed size. */ /** The LayerRenderer calls this to indicate that the window has changed size. */
public void setViewportSize(IntSize size) { public void setViewportSize(IntSize size) {
mController.setViewportSize(new FloatSize(size)); mLayerClient.setViewportSize(new FloatSize(size));
} }
public void setInputConnectionHandler(InputConnectionHandler inputConnectionHandler) { public void setInputConnectionHandler(InputConnectionHandler inputConnectionHandler) {
@ -280,7 +277,7 @@ public class LayerView extends FrameLayout {
/** This function is invoked by Gecko (compositor thread) via JNI; be careful when modifying signature. */ /** This function is invoked by Gecko (compositor thread) via JNI; be careful when modifying signature. */
public static GLController registerCxxCompositor() { public static GLController registerCxxCompositor() {
try { try {
LayerView layerView = GeckoApp.mAppContext.getLayerController().getView(); LayerView layerView = GeckoApp.mAppContext.getLayerClient().getView();
layerView.mListener.compositorCreated(); layerView.mListener.compositorCreated();
return layerView.getGLController(); return layerView.getGLController();
} catch (Exception e) { } catch (Exception e) {

Просмотреть файл

@ -125,17 +125,17 @@ public final class TouchEventHandler implements Tabs.OnTabsChangedListener {
// processed. (n is the absolute value of the balance.) // processed. (n is the absolute value of the balance.)
private int mProcessingBalance; private int mProcessingBalance;
TouchEventHandler(Context context, LayerView view, LayerController controller) { TouchEventHandler(Context context, LayerView view, GeckoLayerClient layerClient) {
mView = view; mView = view;
mEventQueue = new LinkedList<MotionEvent>(); mEventQueue = new LinkedList<MotionEvent>();
mGestureDetector = new GestureDetector(context, controller.getGestureListener()); mGestureDetector = new GestureDetector(context, layerClient.getGestureListener());
mScaleGestureDetector = new SimpleScaleGestureDetector(controller.getScaleGestureListener()); mScaleGestureDetector = new SimpleScaleGestureDetector(layerClient.getScaleGestureListener());
mPanZoomController = controller.getPanZoomController(); mPanZoomController = layerClient.getPanZoomController();
mListenerTimeoutProcessor = new ListenerTimeoutProcessor(); mListenerTimeoutProcessor = new ListenerTimeoutProcessor();
mDispatchEvents = true; mDispatchEvents = true;
mGestureDetector.setOnDoubleTapListener(controller.getDoubleTapListener()); mGestureDetector.setOnDoubleTapListener(layerClient.getDoubleTapListener());
Tabs.registerOnTabsChangedListener(this); Tabs.registerOnTabsChangedListener(this);
} }

Просмотреть файл

@ -79,7 +79,7 @@ class MotionEventReplayer {
// edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=21972329, // edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=21972329,
// downTime=21972329, deviceId=6, source=0x1002 } // downTime=21972329, deviceId=6, source=0x1002 }
// //
// These can be generated by printing out event.toString() in LayerController's // These can be generated by printing out event.toString() in LayerView's
// onTouchEvent function on a phone running Ice Cream Sandwich. Different // onTouchEvent function on a phone running Ice Cream Sandwich. Different
// Android versions have different serializations of the motion event, and this // Android versions have different serializations of the motion event, and this
// code could probably be modified to parse other serializations if needed. // code could probably be modified to parse other serializations if needed.