[Libreoffice-commits] core.git: Branch 'feature/tiled-editing' - 6 commits - android/Bootstrap android/experimental desktop/source

Tomaž Vajngerl tomaz.vajngerl at collabora.co.uk
Fri Feb 13 03:45:46 PST 2015


 android/Bootstrap/src/org/libreoffice/kit/Document.java                               |   18 
 android/experimental/LOAndroid3/src/java/org/libreoffice/LOAbout.java                 |   21 
 android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java                 |   26 -
 android/experimental/LOAndroid3/src/java/org/libreoffice/LOEventFactory.java          |    7 
 android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java             |   43 +
 android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java |    7 
 android/experimental/LOAndroid3/src/java/org/libreoffice/TextCursorLayer.java         |    1 
 android/experimental/LOAndroid3/src/java/org/libreoffice/TextCursorView.java          |    4 
 android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/ComposedTileLayer.java |    7 
 android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/GeckoLayerClient.java  |   11 
 android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/SubTile.java           |  236 +++++++++-
 desktop/source/lib/lokandroid.cxx                                                     |    7 
 12 files changed, 310 insertions(+), 78 deletions(-)

New commits:
commit fa72e738578a8fed3609dcc2c35730766325e6f5
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Fri Feb 13 20:35:40 2015 +0900

    android: discard image buffer as soon as we upload to a texture
    
    Before TileLayer (which SubTile was a subclass of) held the
    image buffer for the whole life cycle of the tile, which wastes
    memory in case of SubTile as the image doesn't change (or changes
    only when invalidated) for the whole tile lifecycle. This change
    changes the SubTile inheritance to a general Layer and adds modified
    logic from SingleTileLayer and TileLayer. In addition it now
    discards the buffer as soon as it has been uploaded to a texture
    so that it doesn't takes up double the memory anymore.
    
    Change-Id: Ia104687d2df529182af412102459952b53e87950

diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
index c28806c..44cb7e3 100644
--- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
@@ -7,6 +7,7 @@ import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
+import org.mozilla.gecko.gfx.BufferedCairoImage;
 import org.mozilla.gecko.gfx.CairoImage;
 import org.mozilla.gecko.gfx.ComposedTileLayer;
 import org.mozilla.gecko.gfx.GeckoLayerClient;
@@ -38,7 +39,8 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
             CairoImage image = mTileProvider.createTile(tileId.x, tileId.y, tileId.size, tileId.zoom);
             if (image != null) {
                 mLayerClient.beginDrawing();
-                SubTile tile = new SubTile(image, tileId);
+                SubTile tile = new SubTile(tileId);
+                tile.setImage(image);
                 composedTileLayer.addTile(tile);
                 mLayerClient.endDrawing();
                 mLayerClient.forceRender();
@@ -57,7 +59,8 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
         mLayerClient.invalidateTiles(tiles, rect);
 
         for (SubTile tile : tiles) {
-            mTileProvider.rerenderTile(tile.getImage(), tile.id.x, tile.id.y, tile.id.size, tile.id.zoom);
+            CairoImage image = mTileProvider.createTile(tile.id.x, tile.id.y, tile.id.size, tile.id.zoom);
+            tile.setImage(image);
         }
 
         mLayerClient.beginDrawing();
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/SubTile.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/SubTile.java
index b5af410..342dc3c 100644
--- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/SubTile.java
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/SubTile.java
@@ -6,16 +6,64 @@
 package org.mozilla.gecko.gfx;
 
 import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.graphics.RegionIterator;
+import android.opengl.GLES20;
+import android.util.Log;
 
 import org.libreoffice.TileIdentifier;
 
-public class SubTile extends SingleTileLayer {
-    public boolean markedForRemoval = false;
+import java.nio.ByteBuffer;
+import java.nio.FloatBuffer;
+
+public class SubTile extends Layer {
+    private static String LOGTAG = SubTile.class.getSimpleName();
     public final TileIdentifier id;
 
-    public SubTile(CairoImage mImage, TileIdentifier id) {
-        super(mImage);
+    private final RectF mBounds;
+    private final RectF mTextureBounds;
+    private final RectF mViewport;
+    private final Rect mIntBounds;
+    private final Rect mSubRect;
+    private final RectF mSubRectF;
+    private final Region mMaskedBounds;
+    private final Rect mCropRect;
+    private final RectF mObjRectF;
+    private final float[] mCoords;
+
+    public boolean markedForRemoval = false;
+
+    private CairoImage mImage;
+    private IntSize mSize;
+    private int[] mTextureIDs;
+    private boolean mDirtyTile;
+
+    public SubTile(TileIdentifier id) {
+        super();
         this.id = id;
+
+        mBounds = new RectF();
+        mTextureBounds = new RectF();
+        mViewport = new RectF();
+        mIntBounds = new Rect();
+        mSubRect = new Rect();
+        mSubRectF = new RectF();
+        mMaskedBounds = new Region();
+        mCropRect = new Rect();
+        mObjRectF = new RectF();
+        mCoords = new float[20];
+
+        mImage = null;
+        mTextureIDs = null;
+        mSize = new IntSize(0, 0);
+        mDirtyTile = false;
+    }
+
+    public void setImage(CairoImage image) {
+        if (image.getSize().isPositive()) {
+            this.mImage = image;
+        }
     }
 
     public void refreshTileMetrics() {
@@ -25,4 +73,184 @@ public class SubTile extends SingleTileLayer {
     public void markForRemoval() {
         markedForRemoval = true;
     }
+
+    protected int getTextureID() {
+        return mTextureIDs[0];
+    }
+
+    protected boolean initialized() {
+        return mTextureIDs != null;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            destroyImage();
+            cleanTexture(false);
+        } finally {
+            super.finalize();
+        }
+    }
+
+    private void cleanTexture(boolean immediately) {
+        if (mTextureIDs != null) {
+            TextureReaper.get().add(mTextureIDs);
+            mTextureIDs = null;
+            if (immediately) {
+                TextureReaper.get().reap();
+            }
+        }
+    }
+
+    public void destroy() {
+        try {
+            destroyImage();
+            cleanTexture(false);
+        } catch (Exception ex) {
+            Log.e(LOGTAG, "Error clearing buffers: ", ex);
+        }
+    }
+
+    public void destroyImage() {
+        if (mImage != null) {
+            mImage.destroy();
+            mImage = null;
+        }
+    }
+
+    /**
+     * Invalidates the entire buffer so that it will be uploaded again. Only valid inside a
+     * transaction.
+     */
+    public void invalidate() {
+        if (!inTransaction()) {
+            throw new RuntimeException("invalidate() is only valid inside a transaction");
+        }
+        if (mImage == null) {
+            return;
+        }
+        mDirtyTile = true;
+    }
+
+    /**
+     * Remove the texture if the image is of different size than the current uploaded texture.
+     */
+    private void validateTexture() {
+        IntSize textureSize = mImage.getSize().nextPowerOfTwo();
+
+        if (!textureSize.equals(mSize)) {
+            mSize = textureSize;
+            cleanTexture(true);
+        }
+    }
+
+    @Override
+    protected void performUpdates(RenderContext context) {
+        super.performUpdates(context);
+        if (mImage == null && !mDirtyTile) {
+            return;
+        }
+        validateTexture();
+        uploadNewTexture();
+        mDirtyTile = false;
+    }
+
+    private void uploadNewTexture() {
+        ByteBuffer imageBuffer = mImage.getBuffer();
+        if (imageBuffer == null) {
+            return;
+        }
+
+        if (mTextureIDs == null) {
+            mTextureIDs = new int[1];
+            GLES20.glGenTextures(mTextureIDs.length, mTextureIDs, 0);
+        }
+
+        int cairoFormat = mImage.getFormat();
+        CairoGLInfo glInfo = new CairoGLInfo(cairoFormat);
+
+        bindAndSetGLParameters();
+
+        IntSize bufferSize = mImage.getSize();
+
+        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, glInfo.internalFormat,
+                mSize.width, mSize.height, 0, glInfo.format, glInfo.type, imageBuffer);
+
+        destroyImage();
+    }
+
+    private void bindAndSetGLParameters() {
+        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureIDs[0]);
+
+        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
+        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
+        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
+        GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
+    }
+
+    @Override
+    public void draw(RenderContext context) {
+        // mTextureIDs may be null here during startup if Layer.java's draw method
+        // failed to acquire the transaction lock and call performUpdates.
+        if (!initialized())
+            return;
+
+        mViewport.set(context.viewport);
+
+        mBounds.set(getBounds(context));
+        mTextureBounds.set(mBounds);
+
+        mBounds.roundOut(mIntBounds);
+        mMaskedBounds.set(mIntBounds);
+
+        // XXX Possible optimisation here, form this array so we can draw it in
+        //     a single call.
+        RegionIterator iterator = new RegionIterator(mMaskedBounds);
+        while (iterator.next(mSubRect)) {
+            // Compensate for rounding errors at the edge of the tile caused by
+            // the roundOut above
+            mSubRectF.set(Math.max(mBounds.left, (float) mSubRect.left),
+                    Math.max(mBounds.top, (float) mSubRect.top),
+                    Math.min(mBounds.right, (float) mSubRect.right),
+                    Math.min(mBounds.bottom, (float) mSubRect.bottom));
+
+            // This is the left/top/right/bottom of the rect, relative to the
+            // bottom-left of the layer, to use for texture coordinates.
+            mCropRect.set(Math.round(mSubRectF.left - mBounds.left),
+                    Math.round(mBounds.bottom - mSubRectF.top),
+                    Math.round(mSubRectF.right - mBounds.left),
+                    Math.round(mBounds.bottom - mSubRectF.bottom));
+
+            mObjRectF.set(mSubRectF.left - mViewport.left,
+                    mViewport.bottom - mSubRectF.bottom,
+                    mSubRectF.right - mViewport.left,
+                    mViewport.bottom - mSubRectF.top);
+
+            fillRectCoordBuffer(mCoords, mObjRectF, mViewport.width(), mViewport.height(), mCropRect, mTextureBounds.width(), mTextureBounds.height());
+
+            FloatBuffer coordBuffer = context.coordBuffer;
+            int positionHandle = context.positionHandle;
+            int textureHandle = context.textureHandle;
+
+            GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, getTextureID());
+
+            // Make sure we are at position zero in the buffer
+            coordBuffer.position(0);
+            coordBuffer.put(mCoords);
+
+            // Unbind any the current array buffer so we can use client side buffers
+            GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+
+            // Vertex coordinates are x,y,z starting at position 0 into the buffer.
+            coordBuffer.position(0);
+            GLES20.glVertexAttribPointer(positionHandle, 3, GLES20.GL_FLOAT, false, 20, coordBuffer);
+
+            // Texture coordinates are texture_x, texture_y starting at position 3 into the buffer.
+            coordBuffer.position(3);
+            GLES20.glVertexAttribPointer(textureHandle, 2, GLES20.GL_FLOAT, false, 20, coordBuffer);
+            GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+        }
+    }
 }
commit d739776fb4e2d8b2e0f5162bb7fdad9c97a89404
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Fri Feb 13 18:29:52 2015 +0900

    android: remove tileRerender method as it is obsolete
    
    Change-Id: I0087edfd2c93a80417b0002eac96e7626c35baf2

diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
index cef7ac8..c28806c 100644
--- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
@@ -48,20 +48,6 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
         }
     }
 
-    private void tileRerender(ComposedTileLayer composedTileLayer, SubTile tile) {
-        if (mTileProvider == null) {
-            return;
-        }
-
-        if (composedTileLayer.isStillValid(tile.id) && !tile.markedForRemoval) {
-            mLayerClient.beginDrawing();
-            mTileProvider.rerenderTile(tile.getImage(), tile.id.x, tile.id.y, tile.id.size, tile.id.zoom);
-            tile.invalidate();
-            mLayerClient.endDrawing();
-            mLayerClient.forceRender();
-        }
-    }
-
     private void tileInvalidation(RectF rect) {
         if (mLayerClient == null || mTileProvider == null) {
             return;
commit 516b6b2fd8509423a9286207060772b20d03db5c
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Fri Feb 13 18:24:55 2015 +0900

    android: remove ImmutableViewportMetrics as input to endDrawing
    
    Change-Id: Iec55bc182845bfa09cf6d03ab787fc1f2e0ee7fc

diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
index a737d18..cef7ac8 100644
--- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
@@ -40,7 +40,7 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
                 mLayerClient.beginDrawing();
                 SubTile tile = new SubTile(image, tileId);
                 composedTileLayer.addTile(tile);
-                mLayerClient.endDrawing(mViewportMetrics);
+                mLayerClient.endDrawing();
                 mLayerClient.forceRender();
             }
         } else {
@@ -57,7 +57,7 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
             mLayerClient.beginDrawing();
             mTileProvider.rerenderTile(tile.getImage(), tile.id.x, tile.id.y, tile.id.size, tile.id.zoom);
             tile.invalidate();
-            mLayerClient.endDrawing(mViewportMetrics);
+            mLayerClient.endDrawing();
             mLayerClient.forceRender();
         }
     }
@@ -78,7 +78,7 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
         for (SubTile tile : tiles) {
             tile.invalidate();
         }
-        mLayerClient.endDrawing(mViewportMetrics);
+        mLayerClient.endDrawing();
         mLayerClient.forceRender();
     }
 
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 83a1324..93beb3d 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
@@ -240,7 +240,7 @@ public class GeckoLayerClient implements PanZoomTarget, LayerView.Listener {
         mRootLayer.beginTransaction();
     }
 
-    public void endDrawing(ImmutableViewportMetrics viewportMetrics) {
+    public void endDrawing() {
         synchronized (this) {
             mLowResLayer.endTransaction();
             mRootLayer.endTransaction();
commit 8e3a085c0a4ee2ce6914f3983b9842e1389a3d8a
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Fri Feb 13 18:23:53 2015 +0900

    android: organise imports
    
    Change-Id: I0f71bade1172b143f0f261ab6ed741f5dd3a9d93

diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOAbout.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOAbout.java
index 13c436f..b34b2c4 100644
--- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOAbout.java
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOAbout.java
@@ -2,27 +2,14 @@ package org.libreoffice;
 
 import android.app.Activity;
 import android.app.AlertDialog;
-import android.content.DialogInterface;
 import android.content.ComponentName;
-import android.os.Bundle;
-import android.os.Handler;
-import android.support.v4.widget.DrawerLayout;
-import android.util.DisplayMetrics;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.ListView;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
+import android.content.DialogInterface;
 import android.content.Intent;
-import android.net.Uri;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.Uri;
+import android.view.View;
+import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.io.File;
 
 public abstract class LOAbout extends Activity {
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java
index 17fa867..ad4d920 100644
--- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LibreOfficeMainActivity.java
@@ -1,6 +1,5 @@
 package org.libreoffice;
 
-import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -8,10 +7,7 @@ import android.content.DialogInterface;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v4.widget.DrawerLayout;
-import android.util.DisplayMetrics;
 import android.util.Log;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
@@ -19,10 +15,8 @@ import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView;
 import android.widget.ListView;
 import android.widget.RelativeLayout;
-import android.widget.TextView;
 
 import org.mozilla.gecko.TextSelection;
-import org.mozilla.gecko.TextSelectionHandle;
 import org.mozilla.gecko.ZoomConstraints;
 import org.mozilla.gecko.gfx.GeckoLayerClient;
 import org.mozilla.gecko.gfx.LayerView;
@@ -30,7 +24,6 @@ import org.mozilla.gecko.gfx.LayerView;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
-import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/TextCursorLayer.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/TextCursorLayer.java
index e83a56c..1e6f167 100644
--- a/android/experimental/LOAndroid3/src/java/org/libreoffice/TextCursorLayer.java
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/TextCursorLayer.java
@@ -5,7 +5,6 @@ import android.graphics.RectF;
 import android.util.Log;
 import android.view.View;
 
-import org.mozilla.gecko.TextSelectionHandle;
 import org.mozilla.gecko.gfx.Layer;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.util.FloatUtils;
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/TextCursorView.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/TextCursorView.java
index 1aed2f0..b2508b6 100644
--- a/android/experimental/LOAndroid3/src/java/org/libreoffice/TextCursorView.java
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/TextCursorView.java
@@ -1,13 +1,9 @@
 package org.libreoffice;
 
 import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.PointF;
 import android.graphics.RectF;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.view.View;
 import android.widget.ImageView;
 import android.widget.RelativeLayout;
 
commit d9d2ed43955141770118f09f72d7c175e027a888
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Fri Feb 13 18:16:51 2015 +0900

    android: invalidate all intersecting tiles in one LOEvent
    
    Change-Id: Ic21984016d10a8e3da87b9fb032179cd4f6f7b9f

diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java
index a9600ea..c51b445 100644
--- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEvent.java
@@ -1,12 +1,12 @@
 package org.libreoffice;
 
 import android.graphics.PointF;
+import android.graphics.RectF;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 
 import org.mozilla.gecko.gfx.ComposedTileLayer;
 import org.mozilla.gecko.gfx.IntSize;
-import org.mozilla.gecko.gfx.SubTile;
 
 public class LOEvent implements Comparable<LOEvent> {
     public static final int SIZE_CHANGED = 1;
@@ -17,7 +17,7 @@ public class LOEvent implements Comparable<LOEvent> {
     public static final int REDRAW = 6;
     public static final int TILE_REQUEST = 7;
     public static final int THUMBNAIL = 8;
-    public static final int TILE_RERENDER = 9;
+    public static final int TILE_INVALIDATION = 9;
     public static final int TOUCH = 10;
     public static final int KEY_EVENT = 11;
 
@@ -30,13 +30,12 @@ public class LOEvent implements Comparable<LOEvent> {
     public String mFilename;
     public TileIdentifier mTileId;
     public ComposedTileLayer mComposedTileLayer;
-    public boolean mForceRedraw;
-    public SubTile mTile;
     public String mTouchType;
     public MotionEvent mMotionEvent;
     public PointF mDocumentTouchCoordinate;
     public String mKeyEventType;
     public KeyEvent mKeyEvent;
+    public RectF mInvalidationRect;
 
     public LOEvent(int type) {
         mType = type;
@@ -47,12 +46,11 @@ public class LOEvent implements Comparable<LOEvent> {
         mTypeString = "Size Changed: " + widthPixels + " " + heightPixels;
     }
 
-    public LOEvent(int type, ComposedTileLayer composedTileLayer, TileIdentifier tileId, boolean forceRedraw) {
+    public LOEvent(int type, ComposedTileLayer composedTileLayer, TileIdentifier tileId) {
         mType = type;
         mTypeString = "Tile Request";
         mComposedTileLayer = composedTileLayer;
         mTileId = tileId;
-        mForceRedraw = forceRedraw;
     }
 
     public LOEvent(int type, String filename) {
@@ -75,13 +73,7 @@ public class LOEvent implements Comparable<LOEvent> {
     public LOEvent(int type, ThumbnailCreator.ThumbnailCreationTask task) {
         mType = type;
         mTask = task;
-    }
-
-    public LOEvent(int type, ComposedTileLayer composedTileLayer, SubTile tile) {
-        mType = type;
-        mTypeString = "Tile Rerender";
-        mComposedTileLayer = composedTileLayer;
-        mTile = tile;
+        mTypeString = "Thumbnail";
     }
 
     public LOEvent(int type, String touchType, MotionEvent motionEvent, PointF documentTouchCoordinate) {
@@ -94,11 +86,17 @@ public class LOEvent implements Comparable<LOEvent> {
 
     public LOEvent(int type, String keyEventType, KeyEvent keyEvent) {
         mType = type;
-        mTypeString = "KeyEvent";
+        mTypeString = "Key Event";
         mKeyEventType = keyEventType;
         mKeyEvent = keyEvent;
     }
 
+    public LOEvent(int type, RectF rect) {
+        mType = type;
+        mTypeString = "Tile Invalidation";
+        mInvalidationRect = rect;
+    }
+
     public String getTypeString() {
         if (mTypeString == null) {
             return "Event type: " + mType;
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEventFactory.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEventFactory.java
index b866850..71bceb2 100644
--- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEventFactory.java
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOEventFactory.java
@@ -2,7 +2,6 @@ package org.libreoffice;
 
 import org.mozilla.gecko.gfx.ComposedTileLayer;
 import org.mozilla.gecko.gfx.IntSize;
-import org.mozilla.gecko.gfx.SubTile;
 
 
 public class LOEventFactory {
@@ -31,14 +30,10 @@ public class LOEventFactory {
     }
 
     public static LOEvent tileRequest(ComposedTileLayer composedTileLayer, TileIdentifier tileID, boolean forceRedraw) {
-        return new LOEvent(LOEvent.TILE_REQUEST, composedTileLayer, tileID, forceRedraw);
+        return new LOEvent(LOEvent.TILE_REQUEST, composedTileLayer, tileID);
     }
 
     public static LOEvent thumbnail(ThumbnailCreator.ThumbnailCreationTask task) {
         return new LOEvent(LOEvent.THUMBNAIL, task);
     }
-
-    public static LOEvent tileRerender(ComposedTileLayer composedTileLayer, SubTile tile) {
-        return new LOEvent(LOEvent.TILE_RERENDER, composedTileLayer, tile);
-    }
 }
diff --git a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
index 3536256..a737d18 100644
--- a/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
+++ b/android/experimental/LOAndroid3/src/java/org/libreoffice/LOKitThread.java
@@ -13,6 +13,8 @@ import org.mozilla.gecko.gfx.GeckoLayerClient;
 import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
 import org.mozilla.gecko.gfx.SubTile;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.PriorityBlockingQueue;
 
 public class LOKitThread extends Thread implements TileProvider.TileInvalidationCallback {
@@ -28,7 +30,7 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
         TileProviderFactory.initialize();
     }
 
-    private void tileRequest(ComposedTileLayer composedTileLayer, TileIdentifier tileId, boolean forceRedraw) {
+    private void tileRequest(ComposedTileLayer composedTileLayer, TileIdentifier tileId) {
         if (mTileProvider == null)
             return;
 
@@ -47,8 +49,9 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
     }
 
     private void tileRerender(ComposedTileLayer composedTileLayer, SubTile tile) {
-        if (mTileProvider == null)
+        if (mTileProvider == null) {
             return;
+        }
 
         if (composedTileLayer.isStillValid(tile.id) && !tile.markedForRemoval) {
             mLayerClient.beginDrawing();
@@ -59,6 +62,26 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
         }
     }
 
+    private void tileInvalidation(RectF rect) {
+        if (mLayerClient == null || mTileProvider == null) {
+            return;
+        }
+
+        List<SubTile> tiles = new ArrayList<SubTile>();
+        mLayerClient.invalidateTiles(tiles, rect);
+
+        for (SubTile tile : tiles) {
+            mTileProvider.rerenderTile(tile.getImage(), tile.id.x, tile.id.y, tile.id.size, tile.id.zoom);
+        }
+
+        mLayerClient.beginDrawing();
+        for (SubTile tile : tiles) {
+            tile.invalidate();
+        }
+        mLayerClient.endDrawing(mViewportMetrics);
+        mLayerClient.forceRender();
+    }
+
     /** Handle the geometry change + draw. */
     private void redraw() {
         if (mLayerClient == null || mTileProvider == null) {
@@ -159,10 +182,10 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
                 changePart(event.mPartIndex);
                 break;
             case LOEvent.TILE_REQUEST:
-                tileRequest(event.mComposedTileLayer, event.mTileId, event.mForceRedraw);
+                tileRequest(event.mComposedTileLayer, event.mTileId);
                 break;
-            case LOEvent.TILE_RERENDER:
-                tileRerender(event.mComposedTileLayer, event.mTile);
+            case LOEvent.TILE_INVALIDATION:
+                tileInvalidation(event.mInvalidationRect);
                 break;
             case LOEvent.THUMBNAIL:
                 createThumbnail(event.mTask);
@@ -216,10 +239,7 @@ public class LOKitThread extends Thread implements TileProvider.TileInvalidation
 
     @Override
     public void invalidate(RectF rect) {
-        Log.i(LOGTAG, "Invalidate request: " + rect);
-
-        mLayerClient = mApplication.getLayerClient();
-        mLayerClient.invalidateTiles(rect);
+        queueEvent(new LOEvent(LOEvent.TILE_INVALIDATION, rect));
     }
 }
 
diff --git a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/ComposedTileLayer.java b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/ComposedTileLayer.java
index ca25438..02fa4fa 100644
--- a/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/ComposedTileLayer.java
+++ b/android/experimental/LOAndroid3/src/java/org/mozilla/gecko/gfx/ComposedTileLayer.java
@@ -1,6 +1,5 @@
 package org.mozilla.gecko.gfx;
 
-import android.app.ActivityManager;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -212,12 +211,12 @@ public abstract class ComposedTileLayer extends Layer implements ComponentCallba
     /**
      * Invalidate tiles which intersect the input rect
      */
-    public void invalidateTiles(RectF cssRect) {
+    public void invalidateTiles(List<SubTile> tilesToInvalidate, RectF cssRect) {
         RectF zoomedRect = RectUtils.scale(cssRect, currentZoom);
 
         for (SubTile tile : tiles) {
-            if (RectF.intersects(zoomedRect, tile.id.getRectF())) {
-                LOKitShell.sendEvent(LOEventFactory.tileRerender(this, tile));
+            if (!tile.markedForRemoval && RectF.intersects(zoomedRect, tile.id.getRectF())) {
+                tilesToInvalidate.add(tile);
             }
         }
     }
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 644ef46..83a1324 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
@@ -15,9 +15,12 @@ import android.util.Log;
 import org.libreoffice.LOEvent;
 import org.libreoffice.LOEventFactory;
 import org.libreoffice.LOKitShell;
+import org.libreoffice.LOKitThread;
 import org.mozilla.gecko.ZoomConstraints;
 import org.mozilla.gecko.util.FloatUtils;
 
+import java.util.List;
+
 public class GeckoLayerClient implements PanZoomTarget, LayerView.Listener {
     private static final String LOGTAG = GeckoLayerClient.class.getSimpleName();
 
@@ -388,8 +391,8 @@ public class GeckoLayerClient implements PanZoomTarget, LayerView.Listener {
         mRootLayer.clearAndReset();
     }
 
-    public void invalidateTiles(RectF rect) {
-        mLowResLayer.invalidateTiles(rect);
-        mRootLayer.invalidateTiles(rect);
+    public void invalidateTiles(List<SubTile> tilesToInvalidate, RectF rect) {
+        mLowResLayer.invalidateTiles(tilesToInvalidate, rect);
+        mRootLayer.invalidateTiles(tilesToInvalidate, rect);
     }
 }
\ No newline at end of file
commit 936278d3a27de9c322f1683099ab9df39f2af26d
Author: Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
Date:   Thu Feb 12 17:14:13 2015 +0900

    android: add support for text selection to JNI
    
    Change-Id: Ifa307eb6a8cb031bdd88b9fadae42c8a0811772b

diff --git a/android/Bootstrap/src/org/libreoffice/kit/Document.java b/android/Bootstrap/src/org/libreoffice/kit/Document.java
index cb798b5..ca2f38c 100644
--- a/android/Bootstrap/src/org/libreoffice/kit/Document.java
+++ b/android/Bootstrap/src/org/libreoffice/kit/Document.java
@@ -38,6 +38,16 @@ public class Document {
      */
     public static final int CALLBACK_INVALIDATE_TILES = 0;
     public static final int CALLBACK_INVALIDATE_VISIBLE_CURSOR = 1;
+    public static final int CALLBACK_INVALIDATE_TEXT_SELECTION = 2;
+    public static final int CALLBACK_INVALIDATE_TEXT_SELECTION_START = 3;
+    public static final int CALLBACK_INVALIDATE_TEXT_SELECTION_END = 4;
+
+    /**
+     * Text selection types
+     */
+    public static final int TEXT_SELECTION_START = 0;
+    public static final int TEXT_SELECTION_END = 1;
+    public static final int TEXT_SELECTION_RESET = 2;
 
     private final ByteBuffer handle;
     private MessageCallback messageCallback = null;
@@ -108,6 +118,14 @@ public class Document {
     public native void postMouseEvent(int type, int x, int y, int count);
 
     /**
+     * Change text selection
+     * @param type - text selection type
+     * @param x - x coordinate
+     * @param y - y coordinate
+     */
+    public native void setTextSelection(int type, int x, int y);
+
+    /**
      * Callback to retrieve messages from LOK
      */
     public interface MessageCallback {
diff --git a/desktop/source/lib/lokandroid.cxx b/desktop/source/lib/lokandroid.cxx
index d253cfe..5403ea0 100644
--- a/desktop/source/lib/lokandroid.cxx
+++ b/desktop/source/lib/lokandroid.cxx
@@ -284,6 +284,13 @@ extern "C" SAL_JNI_EXPORT void JNICALL Java_org_libreoffice_kit_Document_postMou
     pDocument->pClass->postMouseEvent(pDocument, type, x, y, count);
 }
 
+extern "C" SAL_JNI_EXPORT void JNICALL Java_org_libreoffice_kit_Document_setTextSelection
+    (JNIEnv* pEnv, jobject aObject, jint type, jint x, jint y)
+{
+    LibreOfficeKitDocument* pDocument = getHandle<LibreOfficeKitDocument>(pEnv, aObject);
+    pDocument->pClass->setTextSelection(pDocument, type, x, y);
+}
+
 /* DirectBufferAllocator */
 
 extern "C" SAL_JNI_EXPORT jobject JNICALL Java_org_libreoffice_kit_DirectBufferAllocator_allocateDirectBufferNative


More information about the Libreoffice-commits mailing list