[Libreoffice-commits] core.git: android/experimental

Tomaž Vajngerl tomaz.vajngerl at collabora.com
Thu Jul 3 06:05:05 PDT 2014


 android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java                    |   75 -
 android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitTileProvider.java              |  103 ++
 android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java        |    6 
 android/experimental/LOAndroid3/src/java/org/libreoffice/MockTileProvider.java               |   64 +
 android/experimental/LOAndroid3/src/java/org/libreoffice/TileIterator.java                   |    6 
 android/experimental/LOAndroid3/src/java/org/libreoffice/TileProvider.java                   |   14 
 android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java         |  160 ---
 android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoSoftwareLayerClient.java |  107 --
 android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerClient.java              |   81 -
 android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/LayerController.java          |    6 
 android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/Axis.java                      |   19 
 android/experimental/LOAndroid3/src/java/org/mozilla/gecko/ui/PanZoomController.java         |  512 ++++------
 12 files changed, 506 insertions(+), 647 deletions(-)

New commits:
commit 5ccb510ef7dd6688b86038b37563583f64107936
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.com>
Date:   Thu Jul 3 14:57:12 2014 +0200

    LOAndroid3: (partially) render page with LOKitTileProvider
    
    + TileProvider & TileIterator interfaces
    + Clean-up obsolete mozilla stuff
    
    Change-Id: Ief56f11bf7f8fd6da383ffc7be3461b765bf0157

diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
index abcbe65..9082575 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 0000000..4b6d8fa
--- /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 a3144e1..0f12208 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 0000000..04ebfb4
--- /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 0000000..68c39e5
--- /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 0000000..a405fdf
--- /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 134c406..c196cf8 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 de8076a..42bc0b6 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 4f46108..0000000
--- 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 at 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 250dc84..e237052 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 8c0fce4..521e60a 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 c3caccc..066f4ce 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;
+        }
+    }
 }


More information about the Libreoffice-commits mailing list