[Libreoffice-commits] .: 2 commits - android/experimental

Tor Lillqvist tml at kemper.freedesktop.org
Sat Jun 30 00:23:30 PDT 2012


 android/experimental/DocumentLoader/build.xml                                                |   13 
 android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java |  386 +++++++++-
 2 files changed, 387 insertions(+), 12 deletions(-)

New commits:
commit f7e4239ce420c09f3a60339edf10c3a96acb59e5
Author: Tor Lillqvist <tlillqvist at suse.com>
Date:   Sat Jun 30 10:13:04 2012 +0300

    Update for SDK tools rev 20
    
    Change-Id: I482d0a488e9de5b59ce74b9c4057b4103fb048dc

diff --git a/android/experimental/DocumentLoader/build.xml b/android/experimental/DocumentLoader/build.xml
index 5d96019..09f65a9 100644
--- a/android/experimental/DocumentLoader/build.xml
+++ b/android/experimental/DocumentLoader/build.xml
@@ -79,7 +79,7 @@
          In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
          in order to avoid having your file be overridden by tools such as "android update project"
     -->
-    <!-- version-tag: 1 -->
+    <!-- version-tag: custom -->
     <import file="${sdk.dir}/tools/ant/build.xml" />
 
     <!-- Re-define the "-package-resources" target to not compress resources -->
@@ -92,17 +92,18 @@
                     versioncode="${version.code}"
                     versionname="${version.name}"
                     debug="${build.is.packaging.debug}"
-                    manifest="AndroidManifest.xml"
+                    manifest="${out.manifest.abs.file}"
                     assets="${asset.absolute.dir}"
-                    androidjar="${android.jar}"
+                    androidjar="${project.target.android.jar}"
                     apkfolder="${out.absolute.dir}"
                     nocrunch="${build.packaging.nocrunch}"
                     resourcefilename="${resource.package.file.name}"
                     resourcefilter="${aapt.resource.filter}"
-                    projectLibrariesResName="project.libraries.res"
-                    projectLibrariesPackageName="project.libraries.package"
+                    libraryResFolderPathRefid="project.library.res.folder.path"
+                    libraryPackagesRefid="project.library.packages"
                     previousBuildType="${build.last.target}"
-                    buildType="${build.target}">
+                    buildType="${build.target}"
+                    ignoreAssets="${aapt.ignore.assets}">
                 <res path="${out.res.absolute.dir}" />
                 <res path="${resource.absolute.dir}" />
                 <nocompress /> <!-- forces no compression on any files in assets or res/raw -->
commit 8841e75d5af26f96e3ac168474a03d956bd7bb40
Author: Tor Lillqvist <tlillqvist at suse.com>
Date:   Thu Jun 28 23:17:35 2012 +0300

    Hacking on on-demand multiple-level-of-detail quad-tree ideas
    
    Change-Id: Ie5efb45d401721e844e3137474c1a7473a1ac144

diff --git a/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java b/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java
index 677c6d4..993a87c 100644
--- a/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java
+++ b/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java
@@ -58,7 +58,17 @@ package org.libreoffice.android.examples;
 
 import android.app.Activity;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.PixelFormat;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.util.Log;
@@ -74,6 +84,8 @@ import android.widget.TextView;
 import android.widget.ViewFlipper;
 import android.widget.ViewSwitcher;
 
+import junit.framework.Assert;
+
 import com.polites.android.GestureImageView;
 
 import com.sun.star.awt.Size;
@@ -252,10 +264,341 @@ public class DocumentLoader
         }
     }
 
+    static int zoomLevel(float scale)
+    {
+        if (scale <= 1)
+            return 0;
+
+        int result = 1;
+        int power = 2;
+
+        while (scale > power) {
+            result++;
+            power *= 2;
+        }
+        return result;
+    }
+
+    static int scaleOfZoom(int zoom)
+    {
+        int result = 1;
+
+        while (zoom > 0) {
+            result *= 2;
+            zoom--;
+        }
+
+        return result;
+    }
+
+    static int setColorAlpha(int color,
+                             double alpha)
+    {
+        return Color.argb((int)(alpha*255), Color.red(color), Color.green(color), Color.blue(color));
+    }
+
+    // Each (Gesture)ImageView is showing an object of this subclass of
+    // BitmapDrawable, the root of a quadtree of higher-resolution partial
+    // page bitmaps. Obviously these should be rendered asynchronously on
+    // demand but that code is not here yet. And anyway, rendering partial
+    // pages won't work until I have figured out why offsetting VirtualDevice
+    // has no effect.
+    class QuadTree
+        extends BitmapDrawable
+    {
+        final int pageNumber;
+        final int level;
+        final int location;
+        final int w, h;
+
+        static final int NW = 0;
+        static final int NE = 1;
+        static final int SE = 2;
+        static final int SW = 3;
+
+        QuadTree sub[] = new QuadTree[4];
+
+        QuadTree(Bitmap bm,
+                 int level,
+                 int pageNumber,
+                 int location)
+        {
+            super(bm);
+
+            w = getIntrinsicWidth();
+            h = getIntrinsicHeight();
+
+            this.pageNumber = pageNumber;
+            this.level = level;
+            this.location = location;
+
+            // I spent several days wondering why nothing showed up for the
+            // sub-tiles, desperately tweaking stuff left and right, until I
+            // found out I need to call setBounds()... (For the level 0
+            // drawable the GestureImageView handles calling setBounds(), but
+            // it doesn't hurt to do it here for all levels.)
+            setBounds(0, 0, w, h);
+
+            // Just for testing until properly doing this asynchronously and
+            // with insert()
+            if (level == 0) {
+                // Don't do it anyway for now
+
+                // 1) offsetting of VirtualDevice doesn't seem to work so this
+                // would work for the NW sub-tile only anyway.
+
+                // 2) LO renders Windows-style "Y grows upwards" bitmaps, thus
+                // the imageView.setScaleY(-1) below in
+                // PageLoadTask.onPostExecute(), but that means that the
+                // scaling and translation stuff here in QuadTree needs to be
+                // twiddled for Y coordinates. (Just try: comment out the
+                // createSub(NW) call below. If you also comment out the
+                // setScaleY() call, the sub-tile will show up in the correct
+                // location, otherwise not. Or something like that. It's hard
+                // to try to write up sevral nights of desperate hacking back
+                // and forth... which in the end turned out to be just chasing
+                // the wrong ducks. If that is how the metaphor goes?)
+
+                // So probably should write a native method to reflect the
+                // rendered byte buffer in the Y direction, and call that
+                // after rendering, instead? Or maybe the tweaks needed aren't
+                // that large anyway, and I just am mixing up my memory of the
+                // trouble caused by that with the trouble caused by not
+                // calling setBounds()...
+
+                //createSub(NW);
+                //createSub(NE);
+                //createSub(SE);
+                //createSub(SW);
+            }
+        }
+
+        QuadTree(QuadTree rhs,
+                 Bitmap bm)
+        {
+            this(bm, rhs.level, rhs.pageNumber, rhs.location);
+
+            sub = rhs.sub;
+        }
+
+        QuadTree(Bitmap bm,
+                 int pageNumber)
+        {
+            this(bm, 0, pageNumber, 0);
+        }
+
+        QuadTree(int level,
+                 int pageNumber,
+                 int location)
+        {
+            this.level = level;
+            this.pageNumber = pageNumber;
+            this.location = location;
+            w = -1;
+            h = -1;
+        }
+
+        void createSub(int q)
+        {
+            if (true) {
+                ByteBuffer bb = renderPage(pageNumber, level+1, (location<<2)+q);
+                Bitmap subbm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+                subbm.copyPixelsFromBuffer(bb);
+                sub[q] = new QuadTree(subbm, level+1, pageNumber, (location<<2)+q);
+            } else {
+                // Test... just use transparent single colour subtiles
+                Bitmap subbm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
+                int color = 0;
+                switch (q) {
+                case NW: color = Color.RED; break;
+                case NE: color = Color.GREEN; break;
+                case SE: color = Color.BLUE; break;
+                case SW: color = Color.YELLOW; break;
+                }
+                subbm.eraseColor(setColorAlpha(color, 0.5));
+                sub[q] = new QuadTree(subbm, 1, pageNumber, (location<<2)+q);
+            }
+        }
+
+        int quadrantOf(int x,
+                       int y)
+        {
+            if (x < 0 || y < 0 || x >= w || y >= h)
+                return -1;
+
+            if (x < w/2 && y < h/2)
+                return NW;
+            if (x >= w/2 && y < h/2)
+                return NE;
+            if (x >= w/2  && y >= h/2)
+                return SE;
+            if (x < w/2 && y >= h/2)
+                return SW;
+
+            return -1;
+        }
+
+        int quadrantOf(Point p)
+        {
+            return quadrantOf(p.x, p.y);
+        }
+
+        Point subCoord(Point p)
+        {
+            return subCoord(quadrantOf(p), p);
+        }
+
+        Point subCoord(int q,
+                       Point p)
+        {
+            switch (q) {
+            case NW:
+                return new Point(p.x*2, p.y*2);
+            case NE:
+                return new Point((p.x-w/2)*2, p.y*2);
+            case SE:
+                return new Point((p.x-w/2)*2, (p.y-h/2)*2);
+            case SW:
+                return new Point(p.x*2, (p.y-h/2)*2);
+            }
+            return null;
+        }
+
+        // The insert() stuff has not been tested and is just a draft
+        void insert(Bitmap bm,
+                    int level,
+                    int x,
+                    int y)
+        {
+            insert(bm, level, 1, new Point(x, y));
+        }
+
+        void insert(Bitmap bm,
+                    int level,
+                    int recursionDepth,
+                    Point p)
+        {
+            int q = quadrantOf(p);
+
+            if (q == -1)
+                return;
+
+            if (recursionDepth == level) {
+                if (sub[q] == null)
+                    sub[q] = new QuadTree(bm, level);
+                else
+                    sub[q] = new QuadTree(sub[q], bm);
+            } else {
+                if (sub[q] == null)
+                    sub[q] = new QuadTree(this.level+1, pageNumber, location);
+                sub[q].insert(bm, level, recursionDepth+1, subCoord(q, p));
+            }
+        }
+
+        // Ditto for find()
+
+        QuadTree find(int levelCountdown,
+                      int x,
+                      int y)
+        {
+            return find(levelCountdown, new Point(x, y));
+        }
+
+        QuadTree find(int levelCountdown,
+                      Point p)
+        {
+            final int x = p.x, y = p.y;
+
+            Log.i(TAG, "find(" + levelCountdown + ", (" + p.x + ", " + p.y + "))");
+
+            if (x < 0 || y < 0 || x >= w || y >= h)
+                return null;
+
+            if (levelCountdown == 0) {
+                Log.i(TAG, "Returning this at level " + this.level);
+                return this;
+            }
+
+            int q = quadrantOf(p);
+
+            if (sub[q] != null)
+                return sub[q].find(levelCountdown-1, subCoord(q, p));
+
+            return null;
+        }
+
+        void subDraw(Canvas canvas,
+                     int q)
+        {
+            if (q == -1 || sub[q] == null)
+                return;
+
+            Log.i(TAG, "subDraw 1: q=" + q + ", matrix=" + canvas.getMatrix() + ", clip=" + canvas.getClipBounds());
+
+            canvas.save();
+            canvas.scale(0.5f, 0.5f);
+
+            float[] values = new float[9];
+            canvas.getMatrix().getValues(values);
+
+            Log.i(TAG, "subDraw 2: q=" + q + ", matrix=" + canvas.getMatrix() + ", clip=" + canvas.getClipBounds() + ", translate(" +
+                  (((q == NW || q == SW) ? -w : w) /* * values[Matrix.MSCALE_X]*/) + "," +
+                  (((q == NW || q == NE) ? -h : h) /* * values[Matrix.MSCALE_X]*/) + ")");
+
+            canvas.translate(((q == NW || q == SW) ? -w : 0) /* * values[Matrix.MSCALE_X]*/,
+                             ((q == NW || q == NE) ? -h : 0) /* * values[Matrix.MSCALE_X]*/);
+
+            Log.i(TAG, "subDraw 3: q=" + q + ", matrix=" + canvas.getMatrix() + ", clip=" + canvas.getClipBounds());
+
+            sub[q].draw(canvas);
+
+            canvas.restore();
+        }
+
+        @Override
+            public void draw(Canvas canvas)
+        {
+            float[] values = new float[9];
+            canvas.getMatrix().getValues(values);
+
+            float scale = values[Matrix.MSCALE_X];
+            int zoom = zoomLevel(scale);
+
+            Log.i(TAG, "draw: level=" + level + ", scale=" + scale + ", zoom=" + zoom + ", matrix=" + canvas.getMatrix());
+            Rect bounds = new Rect();
+            if (canvas.getClipBounds(bounds))
+                Log.i(TAG, "  clip=" + bounds + ", bounds=" + getBounds());
+            else
+                Log.i(TAG, "  no clip");
+
+            int l = (int)(w/2 - values[Matrix.MTRANS_X]/scale);
+            int t = (int)(h/2 - values[Matrix.MTRANS_Y]/scale);
+            Log.i(TAG, "Unzoomed rect: " + l + ", " + t + ", " + (int)(l+w/scale) + ", " + (int)(t+h/scale));
+
+            Assert.assertTrue(values[Matrix.MSCALE_X] == values[Matrix.MSCALE_Y]);
+
+            super.draw(canvas);
+
+            if (/*zoom > 0 */ scale >= 1) {
+                subDraw(canvas, quadrantOf(l, t));
+                subDraw(canvas, quadrantOf((int)(l+w/scale)-1, t));
+                subDraw(canvas, quadrantOf((int)(l+w/scale)-1, (int)(t+h/scale)-1));
+                subDraw(canvas, quadrantOf(l, (int)(t+h/scale)-1));
+            }
+        }
+    }
+
     ByteBuffer renderPage(int number)
     {
+        return renderPage(number, 0, 0);
+    }
+
+    ByteBuffer renderPage(final int number,
+                          final int level,
+                          final int location)
+    {
         try {
-            // Use dummySmallDevice with no scale of offset just to find out
+            // Use dummySmallDevice with no scale or offset just to find out
             // the paper size of this page.
 
             PropertyValue renderProps[] = new PropertyValue[3];
@@ -294,8 +637,10 @@ public class DocumentLoader
                 device = toolkit.createScreenCompatibleDeviceUsingBuffer(flipper.getWidth(), flipper.getHeight(), 1, 1, 0, 0, wrapped_bb);
             } else {
 
-                // Scale so that it fits our device which has a resolution of 96/in (see
-                // SvpSalGraphics::GetResolution()). The page size returned from getRenderer() is in 1/mm * 100.
+                // Scale so that it fits our device which has a resolution of
+                // 96/inch (see SvpSalGraphics::GetResolution()). The page
+                // size returned from getRenderer() is in 1/mm * 100. 2540 is
+                // one inch in mm/100.
 
                 int scaleNumerator, scaleDenominator;
 
@@ -308,11 +653,40 @@ public class DocumentLoader
                     scaleNumerator = flipper.getWidth();
                     scaleDenominator = pageWidth / 2540 * 96;
                 }
-                Log.i(TAG, "Scaling with " + scaleNumerator + "/" + scaleDenominator);
+                scaleNumerator *= scaleOfZoom(level);
+
+                int xOffset = 0, yOffset = 0;
+                int hiX = pageWidth, hiY = pageHeight;
+                int lvl = level;
+                int loc = location;
+                while (lvl > 0) {
+                    int q = (loc & 0x03);
+
+                    if (q == QuadTree.NE || q == QuadTree.SE) {
+                        xOffset += (hiX - xOffset)/2;
+                    } else {
+                        hiX -= (hiX - xOffset)/2;
+                    }
+                    if (q == QuadTree.SW || q == QuadTree.SE) {
+                        yOffset += (hiY - yOffset)/2;
+                    } else {
+                        hiY -= (hiY - yOffset)/2;
+                    }
+                    lvl--;
+                    loc >>= 2;
+                }
+
+                // Seems that the offsets passed in (which get passed to
+                // MapMode::SetOrigin() in
+                // VirtualDevice::SetOutputSizePixelScaleOffsetAndBuffer()
+                // are ignored... try a random value, no effect ;(
+                xOffset = 12345; xOffset = 789;
+
+                Log.i(TAG, "Rendering page " + number + " level=" + level + " scale=" + scaleNumerator + "/" + scaleDenominator + ", offset=(" + xOffset + ", " + yOffset + ")");
 
                 device = toolkit.createScreenCompatibleDeviceUsingBuffer(flipper.getWidth(), flipper.getHeight(),
                                                                          scaleNumerator, scaleDenominator,
-                                                                         0, 0,
+                                                                         -xOffset, -yOffset,
                                                                          wrapped_bb);
             }
 
@@ -372,7 +746,7 @@ public class DocumentLoader
                     return;
 
                 GestureImageView imageView = new GestureImageView(DocumentLoader.this, gestureListener);
-                imageView.setImageBitmap(bm);
+                imageView.setImageDrawable(new QuadTree(bm, result));
 
                 imageView.setScaleY(-1);
 


More information about the Libreoffice-commits mailing list