diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2014-07-03 14:57:12 +0200 |
---|---|---|
committer | Tomaž Vajngerl <tomaz.vajngerl@collabora.com> | 2014-07-03 15:05:10 +0200 |
commit | 5ccb510ef7dd6688b86038b37563583f64107936 (patch) | |
tree | 2d0378d5f6c5c86c886d6952ced214ae2c60a4c1 /android | |
parent | 9948d9566e86b190e74a62e63f273f5fa0eb8929 (diff) |
LOAndroid3: (partially) render page with LOKitTileProvider
+ TileProvider & TileIterator interfaces
+ Clean-up obsolete mozilla stuff
Change-Id: Ief56f11bf7f8fd6da383ffc7be3461b765bf0157
Diffstat (limited to 'android')
12 files changed, 506 insertions, 647 deletions
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java index abcbe650071e..90825759d21e 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java @@ -16,16 +16,10 @@ import java.nio.ByteBuffer; import java.util.Random; import java.util.concurrent.ConcurrentLinkedQueue; -import org.libreoffice.kit.LibreOfficeKit; -import org.libreoffice.kit.Office; -import org.libreoffice.kit.Document; - public class LOKitThread extends Thread { private static final String LOGTAG = "GeckoThread"; private static final int TILE_SIZE = 256; - - public Office mOffice; - public Document mDocument; + private TileProvider mTileProvider; public ConcurrentLinkedQueue<LOEvent> gEvents = new ConcurrentLinkedQueue<LOEvent>(); private ViewportMetrics mViewportMetrics; @@ -33,55 +27,40 @@ public class LOKitThread extends Thread { LOKitThread() { } - private void openDocument() { - // enable debugging messages as the first thing - LibreOfficeKit.putenv("SAL_LOG=+WARN+INFO-INFO.legacy.osl-INFO.i18nlangtag"); - LibreOfficeKit.init(LibreOfficeMainActivity.mAppContext); - - mOffice = new Office(LibreOfficeKit.getLibreOfficeKitHandle()); - String input = "/assets/test1.odt"; - mDocument = mOffice.documentLoad(input); - } - - private synchronized boolean draw() throws InterruptedException { + private boolean draw() throws InterruptedException { final LibreOfficeMainActivity application = LibreOfficeMainActivity.mAppContext; - openDocument(); - - long height = mDocument.getDocumentHeight(); - long width = mDocument.getDocumentWidth(); + if (mTileProvider == null) + mTileProvider = new LOKitTileProvider(application.getLayerController()); - Log.e(LOGTAG, "Document Size: " + width + " " + height); + int pageWidth = mTileProvider.getPageWidth(); + int pageHeight = mTileProvider.getPageHeight(); - int pageWidth = 1024; - int pageHeight = 1024; + String metadata = createJson(0, 0, pageWidth, pageHeight, pageWidth, pageHeight, 0, 0, 1.0); + mViewportMetrics = new ViewportMetrics(); - String metadata = createJson(0, 0, 256, 256, pageWidth, pageHeight, 0, 0, 1.0); + boolean shouldContinue = application.getLayerClient().beginDrawing(pageWidth, pageHeight, TILE_SIZE, TILE_SIZE, metadata); - Rect bufferRect = application.getLayerClient().beginDrawing(256, 256, TILE_SIZE, TILE_SIZE, metadata); - - /*if (bufferRect == null) { - Log.e(LOGTAG, "beginDrawing - false"); + if (!shouldContinue) { return false; - }*/ - - Log.e(LOGTAG, "Filling tiles.."); - - ByteBuffer buffer = ByteBuffer.allocateDirect(TILE_SIZE * TILE_SIZE * 4); - - Log.e(LOGTAG, "PaintTile.."); - - mDocument.paintTile(buffer, 256, 256, 1024, 1024, 4096, 4096); + } - Log.e(LOGTAG, "EndPaintTile.."); + Log.i(LOGTAG, "Filling tiles.."); - Bitmap bitmap = Bitmap.createBitmap(TILE_SIZE, TILE_SIZE, Bitmap.Config.ARGB_8888); - bitmap.copyPixelsFromBuffer(buffer); + int x = 0; + int y = 0; + for (Bitmap bitmap : mTileProvider.getTileIterator()) { + application.getLayerClient().addTile(bitmap, x, y); + x += TILE_SIZE; + if (x > pageWidth) { + x = 0; + y += TILE_SIZE; + } + } - application.getLayerClient().addTile(bitmap, 0, 0); + Log.i(LOGTAG, "End Draw"); - Log.e(LOGTAG, "EndDrawing.."); - application.getLayerClient().endDrawing(0, 0, 256, 256); + application.getLayerClient().endDrawing(0, 0, pageWidth, pageHeight); return true; } @@ -143,22 +122,20 @@ public class LOKitThread extends Thread { try { boolean drawn = false; while (true) { - if (!gEvents.isEmpty()) { processEvent(gEvents.poll()); } else { if (!drawn) { drawn = draw(); } - Thread.sleep(2000L); + Thread.sleep(100L); } } } catch (InterruptedException ex) { - } } - private synchronized void processEvent(LOEvent event) throws InterruptedException { + private void processEvent(LOEvent event) throws InterruptedException { switch (event.mType) { case LOEvent.VIEWPORT: mViewportMetrics = event.getViewport(); diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java new file mode 100644 index 000000000000..4b6d8faac932 --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java @@ -0,0 +1,103 @@ +package org.libreoffice; + +import android.graphics.Bitmap; +import android.util.Log; + +import org.mozilla.gecko.gfx.LayerController; + +import java.nio.ByteBuffer; +import java.util.Iterator; + +import org.libreoffice.kit.LibreOfficeKit; +import org.libreoffice.kit.Office; +import org.libreoffice.kit.Document; + +public class LOKitTileProvider implements TileProvider { + private final LayerController mLayerController; + + public static int TILE_SIZE = 256; + + public final Office mOffice; + public final Document mDocument; + + public LOKitTileProvider(LayerController layerController) { + this.mLayerController = layerController; + LibreOfficeKit.putenv("SAL_LOG=+WARN+INFO-INFO.legacy.osl-INFO.i18nlangtag"); + LibreOfficeKit.init(LibreOfficeMainActivity.mAppContext); + + mOffice = new Office(LibreOfficeKit.getLibreOfficeKitHandle()); + String input = "/assets/test1.odt"; + mDocument = mOffice.documentLoad(input); + } + + @Override + public int getPageWidth() { + return (int) (mDocument.getDocumentWidth() / 1440.0 * LOKitShell.getDpi()); + } + + @Override + public int getPageHeight() { + return (int) (mDocument.getDocumentHeight() / 1440.0 * LOKitShell.getDpi()); + } + + public TileIterator getTileIterator() { + return new LoKitTileIterator(); + } + + public class LoKitTileIterator implements TileIterator, Iterator<Bitmap> { + private final double mTileWidth; + private final double mTileHeight; + + private boolean mShouldContinue = true; + + private double mPositionWidth = 0; + private double mPositionHeight = 0; + + private double mPageWidth; + private double mPageHeight; + + public LoKitTileIterator() { + mTileWidth = (TILE_SIZE / (double) LOKitShell.getDpi()) * 1440.0; + mTileHeight = (TILE_SIZE / (double) LOKitShell.getDpi()) * 1440.0; + mPageWidth = mDocument.getDocumentWidth(); + mPageHeight = mDocument.getDocumentHeight(); + } + + @Override + public boolean hasNext() { + return mShouldContinue; + } + + @Override + public Bitmap next() { + ByteBuffer buffer = ByteBuffer.allocateDirect(TILE_SIZE * TILE_SIZE * 4); + Bitmap bitmap = Bitmap.createBitmap(TILE_SIZE, TILE_SIZE, Bitmap.Config.ARGB_8888); + + mDocument.paintTile(buffer, TILE_SIZE, TILE_SIZE, (int) mPositionWidth, (int) mPositionHeight, (int) mTileWidth, (int) mTileHeight); + + mPositionWidth += mTileWidth; + + if (mPositionWidth > mPageWidth) { + mPositionHeight += mTileHeight; + mPositionWidth = 0; + } + + if (mPositionHeight > mPageHeight || mPositionHeight > 20000) { + mShouldContinue = false; + } + + bitmap.copyPixelsFromBuffer(buffer); + return bitmap; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator<Bitmap> iterator() { + return this; + } + } +} diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java index a3144e16440e..0f12208d885e 100644 --- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java @@ -11,8 +11,6 @@ import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; import android.widget.RelativeLayout; -import android.os.Environment; -import java.io.File; import org.mozilla.gecko.gfx.GeckoSoftwareLayerClient; import org.mozilla.gecko.gfx.LayerController; @@ -63,10 +61,12 @@ public class LibreOfficeMainActivity extends Activity { mAppContext = this; super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); + Log.w(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - onCreate"); + setContentView(R.layout.activity_main); + // setup gecko layout mGeckoLayout = (RelativeLayout) findViewById(R.id.gecko_layout); mMainLayout = (LinearLayout) findViewById(R.id.main_layout); diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/MockTileProvider.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/MockTileProvider.java new file mode 100644 index 000000000000..04ebfb464a23 --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/MockTileProvider.java @@ -0,0 +1,64 @@ +package org.libreoffice; + +import android.graphics.Bitmap; + +import org.apache.http.MethodNotSupportedException; +import org.mozilla.gecko.gfx.LayerController; + +import java.util.Iterator; +import java.util.List; + +public class MockTileProvider implements TileProvider { + private final LayerController layerController; + + public MockTileProvider(LayerController layerController) { + this.layerController = layerController; + } + + @Override + public int getPageWidth() { + return 549; + } + + @Override + public int getPageHeight() { + return 630; + } + + public TileIterator getTileIterator() { + return new MockTileIterator(layerController); + } + + public class MockTileIterator implements TileIterator, Iterator<Bitmap> { + private final LayerController layerController; + + private int tileNumber = 1; + + public MockTileIterator(LayerController layerController) { + this.layerController = layerController; + } + + @Override + public boolean hasNext() { + return tileNumber <= 9; + } + + @Override + public Bitmap next() { + String imageName = "d" + tileNumber; + tileNumber++; + Bitmap bitmap = layerController.getDrawable(imageName); + return bitmap; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + @Override + public Iterator<Bitmap> iterator() { + return this; + } + } +} diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/TileIterator.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/TileIterator.java new file mode 100644 index 000000000000..68c39e53bccc --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/TileIterator.java @@ -0,0 +1,6 @@ +package org.libreoffice; + +import android.graphics.Bitmap; + +public interface TileIterator extends Iterable<Bitmap> { +} diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/TileProvider.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/TileProvider.java new file mode 100644 index 000000000000..a405fdf827da --- /dev/null +++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/TileProvider.java @@ -0,0 +1,14 @@ +package org.libreoffice; + + +import android.graphics.Bitmap; + +import java.util.List; + +public interface TileProvider { + int getPageWidth(); + + int getPageHeight(); + + TileIterator getTileIterator(); +} diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java index 134c40628d0b..c196cf8e9feb 100644 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java @@ -59,15 +59,7 @@ import org.mozilla.gecko.util.FloatUtils; import java.util.regex.Matcher; import java.util.regex.Pattern; -//import org.mozilla.gecko.GeckoApp; -//import org.mozilla.gecko.GeckoAppShell; -//import org.mozilla.gecko.GeckoEvent; - -public abstract class GeckoLayerClient extends LayerClient implements GeckoEventListener { - public static final int LAYER_CLIENT_TYPE_NONE = 0; - public static final int LAYER_CLIENT_TYPE_SOFTWARE = 1; - public static final int LAYER_CLIENT_TYPE_GL = 2; - +public abstract class GeckoLayerClient implements GeckoEventListener { private static final String LOGTAG = "GeckoLayerClient"; private static final long MIN_VIEWPORT_CHANGE_DELAY = 25L; private static Pattern sColorPattern; @@ -88,53 +80,26 @@ public abstract class GeckoLayerClient extends LayerClient implements GeckoEvent // inside a transaction, so no synchronization is needed. private boolean mUpdateViewportOnEndDraw; private String mLastCheckerboardColor; - /* Used by robocop for testing purposes */ - private DrawListener mDrawListener; + + protected LayerController mLayerController; public GeckoLayerClient(Context context) { mScreenSize = new IntSize(0, 0); } - // Parses a color from an RGB triple of the form "rgb([0-9]+, [0-9]+, [0-9]+)". If the color - // cannot be parsed, returns white. - private static int parseColorFromGecko(String string) { - if (sColorPattern == null) { - sColorPattern = Pattern.compile("rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)"); - } - - Matcher matcher = sColorPattern.matcher(string); - if (!matcher.matches()) { - return Color.WHITE; - } - - int r = Integer.parseInt(matcher.group(1)); - int g = Integer.parseInt(matcher.group(2)); - int b = Integer.parseInt(matcher.group(3)); - return Color.rgb(r, g, b); - } - protected abstract boolean setupLayer(); - protected abstract boolean shouldDrawProceed(int tileWidth, int tileHeight); - protected abstract void updateLayerAfterDraw(Rect updatedRect); protected abstract IntSize getBufferSize(); protected abstract IntSize getTileSize(); - protected abstract void tileLayerUpdated(); - - public abstract Bitmap getBitmap(); - - public abstract int getType(); - /** * Attaches the root layer to the layer controller so that Gecko appears. */ - @Override public void setLayerController(LayerController layerController) { - super.setLayerController(layerController); + mLayerController = layerController; layerController.setRoot(mTileLayer); if (mGeckoViewport != null) { @@ -144,80 +109,25 @@ public abstract class GeckoLayerClient extends LayerClient implements GeckoEvent sendResizeEventIfNecessary(); } - public Rect beginDrawing(int width, int height, int tileWidth, int tileHeight, String metadata) { - + public boolean beginDrawing(int width, int height, int tileWidth, int tileHeight, String metadata) { Log.e(LOGTAG, "### beginDrawing " + width + " " + height + " " + tileWidth + " " + tileHeight); - if (setupLayer()) { + if (setupLayer()) { Log.e(LOGTAG, "### Cancelling due to layer setup"); - return null; - } - - if (!shouldDrawProceed(tileWidth, tileHeight)) { - Log.e(LOGTAG, "### Cancelling draw due to shouldDrawProceed()"); - return null; + return false; } - LayerController controller = getLayerController(); - try { JSONObject viewportObject = new JSONObject(metadata); mNewGeckoViewport = new ViewportMetrics(viewportObject); - Log.e(LOGTAG, "### beginDrawing new Gecko viewport " + mNewGeckoViewport); - - // Update the background color, if it's present. - String backgroundColorString = viewportObject.optString("backgroundColor"); - if (backgroundColorString != null && !backgroundColorString.equals(mLastCheckerboardColor)) { - mLastCheckerboardColor = backgroundColorString; - controller.setCheckerboardColor(parseColorFromGecko(backgroundColorString)); - } } catch (JSONException e) { Log.e(LOGTAG, "Aborting draw, bad viewport description: " + metadata); - return null; + return false; } - // Make sure we don't spend time painting areas we aren't interested in. - // Only do this if the Gecko viewport isn't going to override our viewport. - Rect bufferRect = new Rect(0, 0, width, height); - - if (!mUpdateViewportOnEndDraw) { - // First, find out our ideal displayport. We do this by taking the - // clamped viewport origin and taking away the optimum viewport offset. - // This would be what we would send to Gecko if adjustViewport were - // called now. - ViewportMetrics currentMetrics = controller.getViewportMetrics(); - PointF currentBestOrigin = RectUtils.getOrigin(currentMetrics.getClampedViewport()); - PointF viewportOffset = currentMetrics.getOptimumViewportOffset(new IntSize(width, height)); - currentBestOrigin.offset(-viewportOffset.x, -viewportOffset.y); - - Rect currentRect = RectUtils.round(new RectF(currentBestOrigin.x, currentBestOrigin.y, - currentBestOrigin.x + width, currentBestOrigin.y + height)); - - // Second, store Gecko's displayport. - PointF currentOrigin = mNewGeckoViewport.getDisplayportOrigin(); - bufferRect = RectUtils.round(new RectF(currentOrigin.x, currentOrigin.y, - currentOrigin.x + width, currentOrigin.y + height)); - - - // Take the intersection of the two as the area we're interested in rendering. - - if (!bufferRect.intersect(currentRect)) { - // If there's no intersection, we have no need to render anything, - // but make sure to update the viewport size. - beginTransaction(mTileLayer); - try { - updateViewport(true); - } finally { - endTransaction(mTileLayer); - } - return null; - } - bufferRect.offset(Math.round(-currentOrigin.x), Math.round(-currentOrigin.y)); - } - - beginTransaction(mTileLayer); - return bufferRect; + mTileLayer.beginTransaction(); + return true; } /* @@ -225,23 +135,17 @@ public abstract class GeckoLayerClient extends LayerClient implements GeckoEvent * a little more JNI magic. */ public void endDrawing(int x, int y, int width, int height) { - synchronized (getLayerController()) { + synchronized (mLayerController) { try { updateViewport(!mUpdateViewportOnEndDraw); mUpdateViewportOnEndDraw = false; - Rect rect = new Rect(x, y, x + width, y + height); updateLayerAfterDraw(rect); } finally { - endTransaction(mTileLayer); + mTileLayer.endTransaction(); } } Log.i(LOGTAG, "zerdatime " + SystemClock.uptimeMillis() + " - endDrawing"); - - /* Used by robocop for testing purposes */ - if (mDrawListener != null) { - mDrawListener.drawFinished(x, y, width, height); - } } protected void updateViewport(boolean onlyUpdatePageSize) { @@ -249,27 +153,25 @@ public abstract class GeckoLayerClient extends LayerClient implements GeckoEvent // JS-side viewport dimensions override the java-side ones because // java is the One True Source of this information, and allowing JS // to override can lead to race conditions where this data gets clobbered. - FloatSize viewportSize = getLayerController().getViewportSize(); + FloatSize viewportSize = mLayerController.getViewportSize(); mGeckoViewport = mNewGeckoViewport; mGeckoViewport.setSize(viewportSize); - LayerController controller = getLayerController(); PointF displayportOrigin = mGeckoViewport.getDisplayportOrigin(); mTileLayer.setOrigin(PointUtils.round(displayportOrigin)); mTileLayer.setResolution(mGeckoViewport.getZoomFactor()); - this.tileLayerUpdated(); Log.e(LOGTAG, "### updateViewport onlyUpdatePageSize=" + onlyUpdatePageSize + " getTileViewport " + mGeckoViewport); if (onlyUpdatePageSize) { // Don't adjust page size when zooming unless zoom levels are // approximately equal. - if (FloatUtils.fuzzyEquals(controller.getZoomFactor(), mGeckoViewport.getZoomFactor())) { - controller.setPageSize(mGeckoViewport.getPageSize()); + if (FloatUtils.fuzzyEquals(mLayerController.getZoomFactor(), mGeckoViewport.getZoomFactor())) { + mLayerController.setPageSize(mGeckoViewport.getPageSize()); } } else { - controller.setViewportMetrics(mGeckoViewport); - controller.abortPanZoomAnimation(); + mLayerController.setViewportMetrics(mGeckoViewport); + mLayerController.abortPanZoomAnimation(); } } @@ -284,14 +186,15 @@ public abstract class GeckoLayerClient extends LayerClient implements GeckoEvent // size is zero (which indicates that the rendering surface hasn't been // allocated yet). boolean screenSizeChanged = (metrics.widthPixels != mScreenSize.width || metrics.heightPixels != mScreenSize.height); - boolean viewportSizeValid = (getLayerController() != null && getLayerController().getViewportSize().isPositive()); + boolean viewportSizeValid = (mLayerController != null && mLayerController.getViewportSize().isPositive()); if (!(force || (screenSizeChanged && viewportSizeValid))) { return; } mScreenSize = new IntSize(metrics.widthPixels, metrics.heightPixels); - IntSize bufferSize = getBufferSize(), tileSize = getTileSize(); + IntSize bufferSize = getBufferSize(); + IntSize tileSize = getTileSize(); Log.e(LOGTAG, "### Screen-size changed to " + mScreenSize); @@ -301,13 +204,12 @@ public abstract class GeckoLayerClient extends LayerClient implements GeckoEvent LOKitShell.sendEvent(event); } - @Override public void render() { adjustViewportWithThrottling(); } private void adjustViewportWithThrottling() { - if (!getLayerController().getRedrawHint()) + if (!mLayerController.getRedrawHint()) return; if (mPendingViewportAdjust) @@ -315,7 +217,7 @@ public abstract class GeckoLayerClient extends LayerClient implements GeckoEvent long timeDelta = System.currentTimeMillis() - mLastViewportChangeTime; if (timeDelta < MIN_VIEWPORT_CHANGE_DELAY) { - getLayerController().getView().postDelayed( + mLayerController.getView().postDelayed( new Runnable() { public void run() { mPendingViewportAdjust = false; @@ -330,13 +232,12 @@ public abstract class GeckoLayerClient extends LayerClient implements GeckoEvent adjustViewport(); } - @Override public void viewportSizeChanged() { mViewportSizeChanged = true; } private void adjustViewport() { - ViewportMetrics viewportMetrics = new ViewportMetrics(getLayerController().getViewportMetrics()); + ViewportMetrics viewportMetrics = new ViewportMetrics(mLayerController.getViewportMetrics()); PointF viewportOffset = viewportMetrics.getOptimumViewportOffset(getBufferSize()); viewportMetrics.setViewportOffset(viewportOffset); @@ -366,7 +267,6 @@ public abstract class GeckoLayerClient extends LayerClient implements GeckoEvent } } - @Override public void geometryChanged() { sendResizeEventIfNecessary(); render(); @@ -381,18 +281,4 @@ public abstract class GeckoLayerClient extends LayerClient implements GeckoEvent private void sendResizeEventIfNecessary() { sendResizeEventIfNecessary(false); } - - /** - * Used by robocop for testing purposes. Not for production use! This is called via reflection by robocop. - */ - public void setDrawListener(DrawListener listener) { - mDrawListener = listener; - } - - /** - * Used by robocop for testing purposes. Not for production use! This is used via reflection by robocop. - */ - public interface DrawListener { - public void drawFinished(int x, int y, int width, int height); - } }
\ No newline at end of file diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoSoftwareLayerClient.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoSoftwareLayerClient.java index de8076aed4d2..42bc0b6ac52d 100644 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoSoftwareLayerClient.java +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoSoftwareLayerClient.java @@ -41,7 +41,7 @@ package org.mozilla.gecko.gfx; import org.libreoffice.LOKitShell; import org.mozilla.gecko.gfx.CairoImage; import org.mozilla.gecko.gfx.IntSize; -import org.mozilla.gecko.gfx.LayerClient; +import org.mozilla.gecko.gfx.GeckoLayerClient; import org.mozilla.gecko.gfx.LayerController; import org.mozilla.gecko.gfx.LayerRenderer; import org.mozilla.gecko.gfx.MultiTileLayer; @@ -77,20 +77,11 @@ public class GeckoSoftwareLayerClient extends GeckoLayerClient { mFormat = CairoImage.FORMAT_ARGB32; } - /*protected void finalize() throws Throwable { - try { - if (mBuffer != null) - LOKitShell.freeDirectBuffer(mBuffer); - mBuffer = null; - } finally { - super.finalize(); - } - }*/ - public void setLayerController(LayerController layerController) { super.setLayerController(layerController); layerController.setRoot(mTileLayer); + if (mGeckoViewport != null) { layerController.setViewportMetrics(mGeckoViewport); } @@ -104,7 +95,7 @@ public class GeckoSoftwareLayerClient extends GeckoLayerClient { if(mTileLayer == null) mTileLayer = new MultiTileLayer(TILE_SIZE); - getLayerController().setRoot(mTileLayer); + mLayerController.setRoot(mTileLayer); // Force a resize event to be sent because the results of this // are different depending on what tile system we're using @@ -114,22 +105,11 @@ public class GeckoSoftwareLayerClient extends GeckoLayerClient { } @Override - protected boolean shouldDrawProceed(int tileWidth, int tileHeight) { - // Make sure the tile-size matches. If it doesn't, we could crash trying - // to access invalid memory. - if (tileWidth != TILE_SIZE.width || tileHeight != TILE_SIZE.height) { - Log.e(LOGTAG, "Aborting draw, incorrect tile size of " + tileWidth + "x" + tileHeight); - return false; - } - return true; - } - - @Override - public Rect beginDrawing(int width, int height, int tileWidth, int tileHeight, String metadata) { - Rect bufferRect = super.beginDrawing(width, height, tileWidth, tileHeight, metadata); + public boolean beginDrawing(int width, int height, int tileWidth, int tileHeight, String metadata) { + boolean shouldContinue = super.beginDrawing(width, height, tileWidth, tileHeight, metadata); - if (bufferRect == null) { - return bufferRect; + if (!shouldContinue) { + return shouldContinue; } // If the window size has changed, reallocate the buffer to match. @@ -137,7 +117,7 @@ public class GeckoSoftwareLayerClient extends GeckoLayerClient { mBufferSize = new IntSize(width, height); } - return bufferRect; + return shouldContinue; } @Override @@ -147,76 +127,6 @@ public class GeckoSoftwareLayerClient extends GeckoLayerClient { } } - /*private void copyPixelsFromMultiTileLayer(Bitmap target) { - Canvas c = new Canvas(target); - ByteBuffer tileBuffer = mBuffer.slice(); - int bpp = CairoUtils.bitsPerPixelForCairoFormat(mFormat) / 8; - - for (int y = 0; y < mBufferSize.height; y += TILE_SIZE.height) { - for (int x = 0; x < mBufferSize.width; x += TILE_SIZE.width) { - // Calculate tile size - IntSize tileSize = new IntSize(Math.min(mBufferSize.width - x, TILE_SIZE.width), - Math.min(mBufferSize.height - y, TILE_SIZE.height)); - - // Create a Bitmap from this tile - Bitmap tile = Bitmap.createBitmap(tileSize.width, tileSize.height, - CairoUtils.cairoFormatTobitmapConfig(mFormat)); - tile.copyPixelsFromBuffer(tileBuffer.asIntBuffer()); - - // Copy the tile to the master Bitmap and recycle it - c.drawBitmap(tile, x, y, null); - tile.recycle(); - - // Progress the buffer to the next tile - tileBuffer.position(tileSize.getArea() * bpp); - tileBuffer = tileBuffer.slice(); - } - } - }*/ - - @Override - protected void tileLayerUpdated() { - /* No-op. */ - } - - @Override - public Bitmap getBitmap() { - if (mTileLayer == null) - return null; - - // Begin a tile transaction, otherwise the buffer can be destroyed while - // we're reading from it. - /*beginTransaction(mTileLayer); - try { - if (mBuffer == null || mBufferSize.width <= 0 || mBufferSize.height <= 0) - return null; - try { - Bitmap b = null; - - if (mTileLayer instanceof MultiTileLayer) { - b = Bitmap.createBitmap(mBufferSize.width, mBufferSize.height,CairoUtils.cairoFormatTobitmapConfig(mFormat)); - copyPixelsFromMultiTileLayer(b); - } else { - Log.w(LOGTAG, "getBitmap() called on a layer (" + mTileLayer + ") we don't know how to get a bitmap from"); - } - - return b; - } catch (OutOfMemoryError oom) { - Log.w(LOGTAG, "Unable to create bitmap", oom); - return null; - } - } finally { - endTransaction(mTileLayer); - }*/ - - return null; - } - - @Override - public int getType() { - return LAYER_CLIENT_TYPE_SOFTWARE; - } - @Override protected IntSize getBufferSize() { return new IntSize( @@ -235,3 +145,4 @@ public class GeckoSoftwareLayerClient extends GeckoLayerClient { } } } + diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerClient.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerClient.java deleted file mode 100644 index 4f461088203e..000000000000 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerClient.java +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Android code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009-2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Patrick Walton <pcwalton@mozilla.com> - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -package org.mozilla.gecko.gfx; - -/** - * A layer client provides tiles and manages other information used by the layer controller. - */ -public abstract class LayerClient { - private LayerController mLayerController; - - public abstract void geometryChanged(); - - public abstract void viewportSizeChanged(); - - protected abstract void render(); - - public LayerController getLayerController() { - return mLayerController; - } - - public void setLayerController(LayerController layerController) { - mLayerController = layerController; - } - - /** - * A utility function for calling Layer.beginTransaction with the - * appropriate LayerView. - */ - public void beginTransaction(Layer aLayer) { - if (mLayerController != null) { - LayerView view = mLayerController.getView(); - if (view != null) { - aLayer.beginTransaction(view); - return; - } - } - - aLayer.beginTransaction(); - } - - // Included for symmetry. - public void endTransaction(Layer aLayer) { - aLayer.endTransaction(); - } -} - diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerController.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerController.java index 250dc84c69fe..e237052976c7 100644 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerController.java +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerController.java @@ -88,7 +88,7 @@ public class LayerController { private boolean mWaitForTouchListeners; private PanZoomController mPanZoomController; private OnTouchListener mOnTouchListener; /* The touch listener. */ - private LayerClient mLayerClient; /* The layer client. */ + private GeckoLayerClient mLayerClient; /* The layer client. */ /* The new color for the checkerboard. */ private int mCheckerboardColor; private boolean mCheckerboardShouldShowChecks; @@ -111,11 +111,11 @@ public class LayerController { mForceRedraw = true; } - public LayerClient getLayerClient() { + public GeckoLayerClient getLayerClient() { return mLayerClient; } - public void setLayerClient(LayerClient layerClient) { + public void setLayerClient(GeckoLayerClient layerClient) { mLayerClient = layerClient; layerClient.setLayerController(this); } diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/Axis.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/Axis.java index 8c0fce4c73b3..521e60a1ecd6 100644 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/Axis.java +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/Axis.java @@ -88,7 +88,7 @@ abstract class Axis { private float mTouchPos; /* Position of the most recent touch event on the current drag. */ private float mLastTouchPos; /* Position of the touch event before touchPos. */ private float mVelocity; /* Velocity in this direction; pixels per animation frame. */ - public boolean mScrollingDisabled; /* Whether movement on this axis is locked. */ + private boolean mScrollingDisabled; /* Whether movement on this axis is locked. */ private boolean mDisableSnap; /* Whether overscroll snapping is disabled. */ private float mDisplacement; @@ -147,7 +147,7 @@ abstract class Axis { } private Overscroll getOverscroll() { - boolean minus = (getOrigin() < 0.0f); + boolean minus = getOrigin() < 0.0f; boolean plus = (getViewportEnd() > getPageLength()); if (minus && plus) { return Overscroll.BOTH; @@ -164,10 +164,14 @@ abstract class Axis { // overscrolled on this axis, returns 0. private float getExcess() { switch (getOverscroll()) { - case MINUS: return -getOrigin(); - case PLUS: return getViewportEnd() - getPageLength(); - case BOTH: return getViewportEnd() - getPageLength() - getOrigin(); - default: return 0.0f; + case MINUS: + return -getOrigin(); + case PLUS: + return getViewportEnd() - getPageLength(); + case BOTH: + return getViewportEnd() - getPageLength() - getOrigin(); + default: + return 0.0f; } } @@ -176,8 +180,7 @@ abstract class Axis { * possible and this axis has not been scroll locked while panning. Otherwise, returns false. */ private boolean scrollable() { - return getViewportLength() <= getPageLength() - MIN_SCROLLABLE_DISTANCE && - !mScrollingDisabled; + return getViewportLength() <= getPageLength() - MIN_SCROLLABLE_DISTANCE && !mScrollingDisabled; } /* diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/PanZoomController.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/PanZoomController.java index c3cacccf805e..066f4cea2630 100644 --- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/PanZoomController.java +++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/PanZoomController.java @@ -38,22 +38,23 @@ package org.mozilla.gecko.ui; +import android.graphics.PointF; +import android.graphics.RectF; +import android.util.FloatMath; +import android.util.Log; +import android.view.GestureDetector; +import android.view.MotionEvent; + import org.json.JSONObject; -import org.json.JSONException; import org.libreoffice.LOKitShell; import org.libreoffice.LibreOfficeMainActivity; +import org.mozilla.gecko.GeckoEventListener; import org.mozilla.gecko.gfx.FloatSize; import org.mozilla.gecko.gfx.LayerController; import org.mozilla.gecko.gfx.PointUtils; import org.mozilla.gecko.gfx.ViewportMetrics; import org.mozilla.gecko.util.FloatUtils; -import org.mozilla.gecko.GeckoEventListener; -import android.graphics.PointF; -import android.graphics.RectF; -import android.util.FloatMath; -import android.util.Log; -import android.view.GestureDetector; -import android.view.MotionEvent; + import java.util.Timer; import java.util.TimerTask; @@ -65,29 +66,19 @@ import java.util.TimerTask; */ public class PanZoomController extends GestureDetector.SimpleOnGestureListener - implements SimpleScaleGestureDetector.SimpleScaleGestureListener, GeckoEventListener -{ + implements SimpleScaleGestureDetector.SimpleScaleGestureListener, GeckoEventListener { + // The distance the user has to pan before we recognize it as such (e.g. to avoid 1-pixel pans + // between the touch-down and touch-up of a click). In units of density-independent pixels. + public static final float PAN_THRESHOLD = 1 / 16f * LOKitShell.getDpi(); private static final String LOGTAG = "GeckoPanZoomController"; - - private static String MESSAGE_ZOOM_RECT = "Browser:ZoomToRect"; - private static String MESSAGE_ZOOM_PAGE = "Browser:ZoomToPageWidth"; - // Animation stops if the velocity is below this value when overscrolled or panning. private static final float STOPPED_THRESHOLD = 4.0f; - // Animation stops is the velocity is below this threshold when flinging. private static final float FLING_STOPPED_THRESHOLD = 0.1f; - - // The distance the user has to pan before we recognize it as such (e.g. to avoid 1-pixel pans - // between the touch-down and touch-up of a click). In units of density-independent pixels. - public static final float PAN_THRESHOLD = 1/16f * LOKitShell.getDpi(); - // Angle from axis within which we stay axis-locked private static final double AXIS_LOCK_ANGLE = Math.PI / 6.0; // 30 degrees - // The maximum amount we allow you to zoom into a page private static final float MAX_ZOOM = 4.0f; - /* 16 precomputed frames of the _ease-out_ animation from the CSS Transitions specification. */ private static final float[] EASE_OUT_ANIMATION_FRAMES = { 0.00000f, /* 0 */ @@ -107,27 +98,13 @@ public class PanZoomController 0.97401f, /* 14 */ 0.99309f, /* 15 */ }; - - private enum PanZoomState { - NOTHING, /* no touch-start events received */ - FLING, /* all touches removed, but we're still scrolling page */ - TOUCHING, /* one touch-start event received */ - PANNING_LOCKED, /* touch-start followed by move (i.e. panning with axis lock) */ - PANNING, /* panning without axis lock */ - PANNING_HOLD, /* in panning, but not moving. - * similar to TOUCHING but after starting a pan */ - PANNING_HOLD_LOCKED, /* like PANNING_HOLD, but axis lock still in effect */ - PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */ - ANIMATED_ZOOM /* animated zoom to a new rect */ - } - + private static String MESSAGE_ZOOM_RECT = "Browser:ZoomToRect"; + private static String MESSAGE_ZOOM_PAGE = "Browser:ZoomToPageWidth"; private final LayerController mController; private final SubdocumentScrollHelper mSubscroller; private final Axis mX; private final Axis mY; - private Thread mMainThread; - /* The timer that handles flings or bounces. */ private Timer mAnimationTimer; /* The runnable being scheduled by the animation timer. */ @@ -146,31 +123,19 @@ public class PanZoomController mY = new AxisY(mSubscroller); mMainThread = LibreOfficeMainActivity.mAppContext.getMainLooper().getThread(); - checkMainThread(); mState = PanZoomState.NOTHING; - - //GeckoAppShell.registerGeckoEventListener(MESSAGE_ZOOM_RECT, this); - //GeckoAppShell.registerGeckoEventListener(MESSAGE_ZOOM_PAGE, this); - } - - // for debugging bug 713011; it can be taken out once that is resolved. - private void checkMainThread() { - if (mMainThread != Thread.currentThread()) { - // log with full stack trace - Log.e(LOGTAG, "Uh-oh, we're running on the wrong thread!", new Exception()); - } } public void handleMessage(String event, JSONObject message) { Log.i(LOGTAG, "Got message: " + event); try { if (MESSAGE_ZOOM_RECT.equals(event)) { - float x = (float)message.getDouble("x"); - float y = (float)message.getDouble("y"); + float x = (float) message.getDouble("x"); + float y = (float) message.getDouble("y"); final RectF zoomRect = new RectF(x, y, - x + (float)message.getDouble("w"), - y + (float)message.getDouble("h")); + x + (float) message.getDouble("w"), + y + (float) message.getDouble("h")); mController.post(new Runnable() { public void run() { animatedZoomTo(zoomRect); @@ -185,9 +150,9 @@ public class PanZoomController float newHeight = viewableRect.height() * pageSize.width / viewableRect.width(); float dh = viewableRect.height() - newHeight; // increase in the height final RectF r = new RectF(0.0f, - y + dh/2, + y + dh / 2, pageSize.width, - y + dh/2 + newHeight); + y + dh / 2 + newHeight); mController.post(new Runnable() { public void run() { animatedZoomTo(r); @@ -201,17 +166,23 @@ public class PanZoomController public boolean onTouchEvent(MotionEvent event) { switch (event.getAction() & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: return onTouchStart(event); - case MotionEvent.ACTION_MOVE: return onTouchMove(event); - case MotionEvent.ACTION_UP: return onTouchEnd(event); - case MotionEvent.ACTION_CANCEL: return onTouchCancel(event); - default: return false; + case MotionEvent.ACTION_DOWN: + return onTouchStart(event); + case MotionEvent.ACTION_MOVE: + return onTouchMove(event); + case MotionEvent.ACTION_UP: + return onTouchEnd(event); + case MotionEvent.ACTION_CANCEL: + return onTouchCancel(event); + default: + return false; } } - /** This function must be called from the UI thread. */ + /** + * This function must be called from the UI thread. + */ public void abortAnimation() { - checkMainThread(); // this happens when gecko changes the viewport on us or if the device is rotated. // if that's the case, abort any animation in progress and re-zoom so that the page // snaps to edges. for other cases (where the user's finger(s) are down) don't do @@ -235,11 +206,13 @@ public class PanZoomController } } - /** This must be called on the UI thread. */ + /** + * This must be called on the UI thread. + */ public void pageSizeUpdated() { if (mState == PanZoomState.NOTHING) { ViewportMetrics validated = getValidViewportMetrics(); - if (! mController.getViewportMetrics().fuzzyEquals(validated)) { + if (!mController.getViewportMetrics().fuzzyEquals(validated)) { // page size changed such that we are now in overscroll. snap to the // the nearest valid viewport mController.setViewportMetrics(validated); @@ -248,10 +221,6 @@ public class PanZoomController } } - /* - * Panning/scrolling - */ - private boolean onTouchStart(MotionEvent event) { Log.d(LOGTAG, "onTouchStart in state " + mState); // user is taking control of movement, so stop @@ -279,6 +248,9 @@ public class PanZoomController return false; } + /* + * Panning/scrolling + */ private boolean onTouchMove(MotionEvent event) { Log.d(LOGTAG, "onTouchMove in state " + mState); @@ -295,8 +267,6 @@ public class PanZoomController } cancelTouch(); startPanning(event.getX(0), event.getY(0), event.getEventTime()); - //GeckoApp.mAppContext.hidePlugins(false /* don't hide layers */); - //GeckoApp.mAutoCompletePopup.hide(); track(event); return true; @@ -404,7 +374,7 @@ public class PanZoomController } private void track(float x, float y, long time) { - float timeDelta = (float)(time - mLastEventTime); + float timeDelta = (float) (time - mLastEventTime); if (FloatUtils.fuzzyEquals(timeDelta, 0)) { // probably a duplicate event, ignore it. using a zero timeDelta will mess // up our velocity @@ -490,8 +460,10 @@ public class PanZoomController mAnimationRunnable = runnable; mAnimationTimer.scheduleAtFixedRate(new TimerTask() { @Override - public void run() { mController.post(runnable); } - }, 0, 1000L/60L); + public void run() { + mController.post(runnable); + } + }, 0, 1000L / 60L); } /* Stops the fling or bounce animation. */ @@ -504,14 +476,12 @@ public class PanZoomController mAnimationRunnable.terminate(); mAnimationRunnable = null; } - - //GeckoApp.mAppContext.showPlugins(); } private float getVelocity() { - float xvel = mX.getRealVelocity(); - float yvel = mY.getRealVelocity(); - return FloatMath.sqrt(xvel * xvel + yvel * yvel); + float xVelocity = mX.getRealVelocity(); + float yVelocity = mY.getRealVelocity(); + return FloatMath.sqrt(xVelocity * xVelocity + yVelocity * yVelocity); } private boolean stopped() { @@ -526,155 +496,18 @@ public class PanZoomController mX.displace(); mY.displace(); PointF displacement = getDisplacement(); - if (! mSubscroller.scrollBy(displacement)) { + if (!mSubscroller.scrollBy(displacement)) { synchronized (mController) { mController.scrollBy(displacement); } } } - private abstract class AnimationRunnable implements Runnable { - private boolean mAnimationTerminated; - - /* This should always run on the UI thread */ - public final void run() { - /* - * Since the animation timer queues this runnable on the UI thread, it - * is possible that even when the animation timer is cancelled, there - * are multiple instances of this queued, so we need to have another - * mechanism to abort. This is done by using the mAnimationTerminated flag. - */ - if (mAnimationTerminated) { - return; - } - animateFrame(); - } - - protected abstract void animateFrame(); - - /* This should always run on the UI thread */ - protected final void terminate() { - mAnimationTerminated = true; - } - } - - /* The callback that performs the bounce animation. */ - private class BounceRunnable extends AnimationRunnable { - /* The current frame of the bounce-back animation */ - private int mBounceFrame; - /* - * The viewport metrics that represent the start and end of the bounce-back animation, - * respectively. - */ - private ViewportMetrics mBounceStartMetrics; - private ViewportMetrics mBounceEndMetrics; - - BounceRunnable(ViewportMetrics startMetrics, ViewportMetrics endMetrics) { - mBounceStartMetrics = startMetrics; - mBounceEndMetrics = endMetrics; - } - - protected void animateFrame() { - /* - * The pan/zoom controller might have signaled to us that it wants to abort the - * animation by setting the state to PanZoomState.NOTHING. Handle this case and bail - * out. - */ - if (mState != PanZoomState.FLING) { - finishAnimation(); - return; - } - - /* Perform the next frame of the bounce-back animation. */ - if (mBounceFrame < EASE_OUT_ANIMATION_FRAMES.length) { - advanceBounce(); - return; - } - - /* Finally, if there's nothing else to do, complete the animation and go to sleep. */ - finishBounce(); - finishAnimation(); - mState = PanZoomState.NOTHING; - } - - /* Performs one frame of a bounce animation. */ - private void advanceBounce() { - synchronized (mController) { - float t = EASE_OUT_ANIMATION_FRAMES[mBounceFrame]; - ViewportMetrics newMetrics = mBounceStartMetrics.interpolate(mBounceEndMetrics, t); - mController.setViewportMetrics(newMetrics); - mController.notifyLayerClientOfGeometryChange(); - mBounceFrame++; - } - } - - /* Concludes a bounce animation and snaps the viewport into place. */ - private void finishBounce() { - synchronized (mController) { - mController.setViewportMetrics(mBounceEndMetrics); - mController.notifyLayerClientOfGeometryChange(); - mBounceFrame = -1; - } - } - } - - // The callback that performs the fling animation. - private class FlingRunnable extends AnimationRunnable { - protected void animateFrame() { - /* - * The pan/zoom controller might have signaled to us that it wants to abort the - * animation by setting the state to PanZoomState.NOTHING. Handle this case and bail - * out. - */ - if (mState != PanZoomState.FLING) { - finishAnimation(); - return; - } - - /* Advance flings, if necessary. */ - boolean flingingX = mX.advanceFling(); - boolean flingingY = mY.advanceFling(); - - boolean overscrolled = (mX.overscrolled() || mY.overscrolled()); - - /* If we're still flinging in any direction, update the origin. */ - if (flingingX || flingingY) { - updatePosition(); - - /* - * Check to see if we're still flinging with an appreciable velocity. The threshold is - * higher in the case of overscroll, so we bounce back eagerly when overscrolling but - * coast smoothly to a stop when not. In other words, require a greater velocity to - * maintain the fling once we enter overscroll. - */ - float threshold = (overscrolled && !mSubscroller.scrolling() ? STOPPED_THRESHOLD : FLING_STOPPED_THRESHOLD); - if (getVelocity() >= threshold) { - // we're still flinging - return; - } - - mX.stopFling(); - mY.stopFling(); - } - - /* Perform a bounce-back animation if overscrolled. */ - if (overscrolled) { - bounce(); - } else { - finishAnimation(); - mState = PanZoomState.NOTHING; - } - } - } - private void finishAnimation() { - checkMainThread(); - Log.d(LOGTAG, "Finishing animation at " + mController.getViewportMetrics()); stopAnimationTimer(); // Force a viewport synchronisation - //GeckoApp.mAppContext.showPlugins(); mController.setForceRedraw(); mController.notifyLayerClientOfGeometryChange(); } @@ -726,26 +559,6 @@ public class PanZoomController return viewportMetrics; } - private class AxisX extends Axis { - AxisX(SubdocumentScrollHelper subscroller) { super(subscroller); } - @Override - public float getOrigin() { return mController.getOrigin().x; } - @Override - protected float getViewportLength() { return mController.getViewportSize().width; } - @Override - protected float getPageLength() { return mController.getPageSize().width; } - } - - private class AxisY extends Axis { - AxisY(SubdocumentScrollHelper subscroller) { super(subscroller); } - @Override - public float getOrigin() { return mController.getOrigin().y; } - @Override - protected float getViewportLength() { return mController.getViewportSize().height; } - @Override - protected float getPageLength() { return mController.getPageSize().height; } - } - /* * Zooming */ @@ -758,8 +571,7 @@ public class PanZoomController mState = PanZoomState.PINCHING; mLastZoomFocus = new PointF(detector.getFocusX(), detector.getFocusY()); - //GeckoApp.mAppContext.hidePlugins(false /* don't hide layers, only views */); - //GeckoApp.mAutoCompletePopup.hide(); + cancelTouch(); return true; @@ -785,10 +597,11 @@ public class PanZoomController * factor toward 1.0. */ float resistance = Math.min(mX.getEdgeResistance(), mY.getEdgeResistance()); - if (spanRatio > 1.0f) + if (spanRatio > 1.0f) { spanRatio = 1.0f + (spanRatio - 1.0f) * resistance; - else + } else { spanRatio = 1.0f - (1.0f - spanRatio) * resistance; + } synchronized (mController) { float newZoomFactor = mController.getZoomFactor() * spanRatio; @@ -797,7 +610,7 @@ public class PanZoomController // such that it asymptotically reaches MAX_ZOOM + 1.0 // but never exceeds that float excessZoom = newZoomFactor - MAX_ZOOM; - excessZoom = 1.0f - (float)Math.exp(-excessZoom); + excessZoom = 1.0f - (float) Math.exp(-excessZoom); newZoomFactor = MAX_ZOOM + excessZoom; } @@ -832,55 +645,29 @@ public class PanZoomController return (mState != PanZoomState.PINCHING && mState != PanZoomState.ANIMATED_ZOOM); } - private void sendPointToGecko(String event, MotionEvent motionEvent) { - String json; - try { - PointF point = new PointF(motionEvent.getX(), motionEvent.getY()); - point = mController.convertViewPointToLayerPoint(point); - if (point == null) { - return; - } - json = PointUtils.toJSON(point).toString(); - } catch (Exception e) { - Log.e(LOGTAG, "Unable to convert point to JSON for " + event, e); - return; - } - - //GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(event, json)); - } - @Override public void onLongPress(MotionEvent motionEvent) { - sendPointToGecko("Gesture:LongPress", motionEvent); } @Override public boolean onDown(MotionEvent motionEvent) { - sendPointToGecko("Gesture:ShowPress", motionEvent); return false; } @Override public boolean onSingleTapConfirmed(MotionEvent motionEvent) { - //GeckoApp.mAutoCompletePopup.hide(); - sendPointToGecko("Gesture:SingleTap", motionEvent); return true; } @Override public boolean onDoubleTap(MotionEvent motionEvent) { - sendPointToGecko("Gesture:DoubleTap", motionEvent); return true; } public void cancelTouch() { - //GeckoEvent e = GeckoEvent.createBroadcastEvent("Gesture:CancelTouch", ""); - //GeckoAppShell.sendEventToGecko(e); } private boolean animatedZoomTo(RectF zoomToRect) { - //GeckoApp.mAutoCompletePopup.hide(); - mState = PanZoomState.ANIMATED_ZOOM; final float startZoom = mController.getZoomFactor(); @@ -918,4 +705,193 @@ public class PanZoomController bounce(finalMetrics); return true; } + + private enum PanZoomState { + NOTHING, /* no touch-start events received */ + FLING, /* all touches removed, but we're still scrolling page */ + TOUCHING, /* one touch-start event received */ + PANNING_LOCKED, /* touch-start followed by move (i.e. panning with axis lock) */ + PANNING, /* panning without axis lock */ + PANNING_HOLD, /* in panning, but not moving. + * similar to TOUCHING but after starting a pan */ + PANNING_HOLD_LOCKED, /* like PANNING_HOLD, but axis lock still in effect */ + PINCHING, /* nth touch-start, where n > 1. this mode allows pan and zoom */ + ANIMATED_ZOOM /* animated zoom to a new rect */ + } + + private abstract class AnimationRunnable implements Runnable { + private boolean mAnimationTerminated; + + /* This should always run on the UI thread */ + public final void run() { + /* + * Since the animation timer queues this runnable on the UI thread, it + * is possible that even when the animation timer is cancelled, there + * are multiple instances of this queued, so we need to have another + * mechanism to abort. This is done by using the mAnimationTerminated flag. + */ + if (mAnimationTerminated) { + return; + } + animateFrame(); + } + + protected abstract void animateFrame(); + + /* This should always run on the UI thread */ + protected final void terminate() { + mAnimationTerminated = true; + } + } + + /* The callback that performs the bounce animation. */ + private class BounceRunnable extends AnimationRunnable { + /* The current frame of the bounce-back animation */ + private int mBounceFrame; + /* + * The viewport metrics that represent the start and end of the bounce-back animation, + * respectively. + */ + private ViewportMetrics mBounceStartMetrics; + private ViewportMetrics mBounceEndMetrics; + + BounceRunnable(ViewportMetrics startMetrics, ViewportMetrics endMetrics) { + mBounceStartMetrics = startMetrics; + mBounceEndMetrics = endMetrics; + } + + protected void animateFrame() { + /* + * The pan/zoom controller might have signaled to us that it wants to abort the + * animation by setting the state to PanZoomState.NOTHING. Handle this case and bail + * out. + */ + if (mState != PanZoomState.FLING) { + finishAnimation(); + return; + } + + /* Perform the next frame of the bounce-back animation. */ + if (mBounceFrame < EASE_OUT_ANIMATION_FRAMES.length) { + advanceBounce(); + return; + } + + /* Finally, if there's nothing else to do, complete the animation and go to sleep. */ + finishBounce(); + finishAnimation(); + mState = PanZoomState.NOTHING; + } + + /* Performs one frame of a bounce animation. */ + private void advanceBounce() { + synchronized (mController) { + float t = EASE_OUT_ANIMATION_FRAMES[mBounceFrame]; + ViewportMetrics newMetrics = mBounceStartMetrics.interpolate(mBounceEndMetrics, t); + mController.setViewportMetrics(newMetrics); + mController.notifyLayerClientOfGeometryChange(); + mBounceFrame++; + } + } + + /* Concludes a bounce animation and snaps the viewport into place. */ + private void finishBounce() { + synchronized (mController) { + mController.setViewportMetrics(mBounceEndMetrics); + mController.notifyLayerClientOfGeometryChange(); + mBounceFrame = -1; + } + } + } + + // The callback that performs the fling animation. + private class FlingRunnable extends AnimationRunnable { + protected void animateFrame() { + /* + * The pan/zoom controller might have signaled to us that it wants to abort the + * animation by setting the state to PanZoomState.NOTHING. Handle this case and bail + * out. + */ + if (mState != PanZoomState.FLING) { + finishAnimation(); + return; + } + + /* Advance flings, if necessary. */ + boolean flingingX = mX.advanceFling(); + boolean flingingY = mY.advanceFling(); + + boolean overscrolled = (mX.overscrolled() || mY.overscrolled()); + + /* If we're still flinging in any direction, update the origin. */ + if (flingingX || flingingY) { + updatePosition(); + + /* + * Check to see if we're still flinging with an appreciable velocity. The threshold is + * higher in the case of overscroll, so we bounce back eagerly when overscrolling but + * coast smoothly to a stop when not. In other words, require a greater velocity to + * maintain the fling once we enter overscroll. + */ + float threshold = (overscrolled && !mSubscroller.scrolling() ? STOPPED_THRESHOLD : FLING_STOPPED_THRESHOLD); + if (getVelocity() >= threshold) { + // we're still flinging + return; + } + + mX.stopFling(); + mY.stopFling(); + } + + /* Perform a bounce-back animation if overscrolled. */ + if (overscrolled) { + bounce(); + } else { + finishAnimation(); + mState = PanZoomState.NOTHING; + } + } + } + + private class AxisX extends Axis { + AxisX(SubdocumentScrollHelper subscroller) { + super(subscroller); + } + + @Override + public float getOrigin() { + return mController.getOrigin().x; + } + + @Override + protected float getViewportLength() { + return mController.getViewportSize().width; + } + + @Override + protected float getPageLength() { + return mController.getPageSize().width; + } + } + + private class AxisY extends Axis { + AxisY(SubdocumentScrollHelper subscroller) { + super(subscroller); + } + + @Override + public float getOrigin() { + return mController.getOrigin().y; + } + + @Override + protected float getViewportLength() { + return mController.getViewportSize().height; + } + + @Override + protected float getPageLength() { + return mController.getPageSize().height; + } + } } |