diff options
author | Tor Lillqvist <tlillqvist@suse.com> | 2012-06-05 17:05:56 +0300 |
---|---|---|
committer | Tor Lillqvist <tlillqvist@suse.com> | 2012-06-05 17:17:41 +0300 |
commit | 8ae077379edcdbf7bf106121593361d2486aacb7 (patch) | |
tree | 207e4b9d516a56e2ebbf500cd80baca2d275894c | |
parent | 92f23297c93dc105e2ffd9ff09c0dafff1ee0fd3 (diff) |
Use 32bpp bitmaps on Android (and iOS)
Modify DocumentLoader correspondingly. Take Android bug 32588 into
account.
Ideal would be to extend the XDevice stuff, or something, so that one
could hand it a pre-allocated RGBA buffer into which the
drawing/rendering would go. Then one could get rid of the silly
convert-to-BMP phase, which prefixes the bitmap data with BMP and DIB
headers (and thus, I guess, has to copy and allocate another
copy). Will see.
Change-Id: I4597cd933db8faa8105dc8f19638d712d5d2238a
-rw-r--r-- | android/Bootstrap/src/org/libreoffice/android/Bootstrap.java | 2 | ||||
-rw-r--r-- | android/experimental/DocumentLoader/Makefile | 2 | ||||
-rw-r--r-- | android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java | 195 | ||||
-rw-r--r-- | sal/android/lo-bootstrap.c | 23 | ||||
-rw-r--r-- | vcl/android/androidinst.cxx | 2 | ||||
-rw-r--r-- | vcl/headless/svpbmp.cxx | 1 | ||||
-rw-r--r-- | vcl/headless/svpframe.cxx | 5 | ||||
-rw-r--r-- | vcl/headless/svpvd.cxx | 6 |
8 files changed, 150 insertions, 86 deletions
diff --git a/android/Bootstrap/src/org/libreoffice/android/Bootstrap.java b/android/Bootstrap/src/org/libreoffice/android/Bootstrap.java index 47366a22f46d..1f0c14ef5f98 100644 --- a/android/Bootstrap/src/org/libreoffice/android/Bootstrap.java +++ b/android/Bootstrap/src/org/libreoffice/android/Bootstrap.java @@ -116,6 +116,8 @@ public class Bootstrap extends NativeActivity // documentation sucks. public static native void twiddle_BGR_to_RGBA(byte[] source, int offset, int width, int height, ByteBuffer destination); + public static native void force_full_alpha(byte[] source, int offset, int size); + // This setup() method is called 1) in apps that use *this* class as their activity from onCreate(), // and 2) should be called from other kinds of LO code using apps. public static void setup(Activity activity) diff --git a/android/experimental/DocumentLoader/Makefile b/android/experimental/DocumentLoader/Makefile index 1e9cebcbe8be..8129948b2e76 100644 --- a/android/experimental/DocumentLoader/Makefile +++ b/android/experimental/DocumentLoader/Makefile @@ -262,8 +262,10 @@ uninstall: $(ANDROID_SDK_HOME)/platform-tools/adb uninstall $(APP_PACKAGE) run: +# /data/local/tmp/sample-document.odt adb shell am start -n org.libreoffice.android.examples/.DocumentLoader -e input /assets/test1.odt + clean: properties $(ANT) clean rm -rf assets libs $(SODEST) $(OBJLOCAL) 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 8ead7a96240d..4f027ecf7c1a 100644 --- a/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java +++ b/android/experimental/DocumentLoader/src/org/libreoffice/android/examples/DocumentLoader.java @@ -150,18 +150,21 @@ public class DocumentLoader Log.i(TAG, " " + t.getTypeName()); } - static void dumpBytes(String imageName, byte[] image) + static void dumpBytes(String name, byte[] bytes, int offset) { - if (image == null) { - Log.i(TAG, imageName + " is null"); + if (bytes == null) { + Log.i(TAG, name + " is null"); return; } - Log.i(TAG, imageName + " is " + image.length + " bytes"); + Log.i(TAG, name + ":"); - for (int i = 0; i < Math.min(image.length, 160); i += 16) { + if (offset != 0) + Log.i(TAG, " (offset " + offset + ")"); + + for (int i = offset; i < Math.min(bytes.length, offset+160); i += 16) { String s = ""; - for (int j = i; j < Math.min(image.length, i+16); j++) - s = s + String.format(" %02x", image[j]); + for (int j = i; j < Math.min(bytes.length, i+16); j++) + s = s + String.format(" %02x", bytes[j]); Log.i(TAG, s); } @@ -185,8 +188,8 @@ public class DocumentLoader Bootstrap.dlopen("libswdlo.so"); Bootstrap.dlopen("libswlo.so"); - Log.i(TAG, "Sleeping NOW"); - Thread.sleep(20000); + // Log.i(TAG, "Sleeping NOW"); + // Thread.sleep(20000); XComponentContext xContext = null; @@ -225,113 +228,137 @@ public class DocumentLoader Log.i(TAG, "xCompLoader is" + (xCompLoader!=null ? " not" : "") + " null"); - // Load the wanted document(s) - String[] inputs = input.split(":"); - for (int i = 0; i < inputs.length; i++) { - PropertyValue loadProps[] = new PropertyValue[3]; - loadProps[0] = new PropertyValue(); - loadProps[0].Name = "Hidden"; - loadProps[0].Value = new Boolean(true); - loadProps[1] = new PropertyValue(); - loadProps[1].Name = "ReadOnly"; - loadProps[1].Value = new Boolean(true); - loadProps[2] = new PropertyValue(); - loadProps[2].Name = "Preview"; - loadProps[2].Value = new Boolean(true); + // Load the wanted document - String sUrl = "file://" + inputs[i]; + PropertyValue loadProps[] = new PropertyValue[3]; + loadProps[0] = new PropertyValue(); + loadProps[0].Name = "Hidden"; + loadProps[0].Value = new Boolean(true); + loadProps[1] = new PropertyValue(); + loadProps[1].Name = "ReadOnly"; + loadProps[1].Value = new Boolean(true); + loadProps[2] = new PropertyValue(); + loadProps[2].Name = "Preview"; + loadProps[2].Value = new Boolean(true); - Log.i(TAG, "Attempting to load " + sUrl); + String sUrl = "file://" + input; - Object oDoc = - xCompLoader.loadComponentFromURL - (sUrl, "_blank", 0, loadProps); + Log.i(TAG, "Attempting to load " + sUrl); - dumpUNOObject("oDoc", oDoc); + Object oDoc = + xCompLoader.loadComponentFromURL + (sUrl, "_blank", 0, loadProps); - Object toolkit = xMCF.createInstanceWithContext - ("com.sun.star.awt.Toolkit", xContext); + dumpUNOObject("oDoc", oDoc); - dumpUNOObject("toolkit", toolkit); + Object toolkit = xMCF.createInstanceWithContext + ("com.sun.star.awt.Toolkit", xContext); - XToolkit xToolkit = (XToolkit) - UnoRuntime.queryInterface(XToolkit.class, toolkit); + dumpUNOObject("toolkit", toolkit); - XDevice device = xToolkit.createScreenCompatibleDevice(1024, 1024); + XToolkit xToolkit = (XToolkit) + UnoRuntime.queryInterface(XToolkit.class, toolkit); - dumpUNOObject("device", device); + XDevice device = xToolkit.createScreenCompatibleDevice(1024, 1024); - // I guess the XRenderable thing might be what we want to use, - // having the code pretend it is printing? + dumpUNOObject("device", device); - XRenderable renderBabe = (XRenderable) - UnoRuntime.queryInterface(XRenderable.class, oDoc); + XRenderable renderBabe = (XRenderable) + UnoRuntime.queryInterface(XRenderable.class, oDoc); - PropertyValue renderProps[] = - new PropertyValue[3]; - renderProps[0] = new PropertyValue(); - renderProps[0].Name = "IsPrinter"; - renderProps[0].Value = new Boolean(true); - renderProps[1] = new PropertyValue(); - renderProps[1].Name = "RenderDevice"; - renderProps[1].Value = device; - renderProps[2] = new PropertyValue(); - renderProps[2].Name = "View"; - renderProps[2].Value = new MyXController(); + PropertyValue renderProps[] = + new PropertyValue[3]; + renderProps[0] = new PropertyValue(); + renderProps[0].Name = "IsPrinter"; + renderProps[0].Value = new Boolean(true); + renderProps[1] = new PropertyValue(); + renderProps[1].Name = "RenderDevice"; + renderProps[1].Value = device; + renderProps[2] = new PropertyValue(); + renderProps[2].Name = "View"; + renderProps[2].Value = new MyXController(); - Log.i(TAG, "getRendererCount: " + renderBabe.getRendererCount(oDoc, renderProps)); + Log.i(TAG, "getRendererCount: " + renderBabe.getRendererCount(oDoc, renderProps)); - renderBabe.render(0, oDoc, renderProps); + renderBabe.render(0, oDoc, renderProps); - XBitmap bitmap = device.createBitmap(0, 0, 1024, 1024); + XBitmap bitmap = device.createBitmap(0, 0, 1024, 1024); - byte[] image = bitmap.getDIB(); + byte[] image = bitmap.getDIB(); - dumpBytes("image", image); + dumpBytes("image", image, 0); - byte[] mask = bitmap.getMaskDIB(); + if (image[0] != 'B' || image[1] != 'M') { + Log.wtf(TAG, "getDIB() didn't return a BMP file"); + return; + } - dumpBytes("mask", mask); + ByteBuffer imagebb = ByteBuffer.wrap(image); + imagebb.order(ByteOrder.LITTLE_ENDIAN); - if (image[0] != 'B' || image[1] != 'M') { - Log.e(TAG, "getDIB() didn't return a BMP file"); - return; - } + if (imagebb.getInt(0x0e) != 40) { + Log.wtf(TAG, "getDIB() didn't return a DIB with BITMAPINFOHEADER"); + return; + } - ByteBuffer imagebb = ByteBuffer.wrap(image); - imagebb.order(ByteOrder.LITTLE_ENDIAN); + if (imagebb.getShort(0x1c) != 32) { + Log.wtf(TAG, "getDIB() didn't return a 32 bpp DIB"); + return; + } - if (imagebb.getInt(0x0e) != 40) { - Log.e(TAG, "getDIB() didn't return a DIB with BITMAPINFOHEADER"); - return; - } + if (imagebb.getInt(0x1e) != 3) { + Log.wtf(TAG, "getDIB() didn't return a BI_BITFIELDS DIB"); + return; + } - if (imagebb.getShort(0x1c) != 24) { - Log.e(TAG, "getDIB() didn't return a 24 bpp DIB"); - return; - } + int offset = imagebb.getInt(0x0a); + int width = imagebb.getInt(0x12); + int height = imagebb.getInt(0x16); + + Log.i(TAG, String.format("offset: %d (%x), width: %d, height: %d", offset, offset, width, height)); + + Bootstrap.force_full_alpha(image, offset, width * height * 4); - if (imagebb.getInt(0x1e) != 0) { - Log.e(TAG, "getDIB() didn't return a BI_RGB DIB"); - return; + Log.i(TAG, "after force_full_alpha:"); + dumpBytes("image", image, 0); + + for (int i = offset; i < offset + width * height * 4; i++) { + if (image[i] != -1) { + int o = offset + (((i-offset) - 4) / 4) * 4; + dumpBytes("First non-ones bytes", image, o); + o += 160; + dumpBytes("...", image, o); + o += 160; + dumpBytes("...", image, o); + o += 160; + dumpBytes("...", image, o); + break; } + } - int width = imagebb.getInt(0x12); - int height = imagebb.getInt(0x16); + ImageView imageView = new GestureImageView(this); + imageView.setScaleY(-1); - ByteBuffer argb = ByteBuffer.allocateDirect(width * height * 4); + Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + imagebb.position(offset); - Bootstrap.twiddle_BGR_to_RGBA(image, imagebb.getInt(0x0a), width, height, argb); + // Thanks to Android bug 32588, the above is not enough to get the + // below copyPixelsFromBuffer() to start copying at offset, it + // will (as of Android 4.0.3) copy from position zero anyway. So + // instead have to shift (compact) the bloody buffer. + imagebb.compact(); - ImageView imageView = new GestureImageView(this); + // I don't understand what the compact() documentation says about + // the new position; so explicitly put it at zero, in case + // runnning on an Android where copyPixelsFromBuffer() *does* take + // the position into account. + imagebb.position(0); - Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - bm.copyPixelsFromBuffer(argb); + bm.copyPixelsFromBuffer(imagebb); - imageView.setImageBitmap(bm); + imageView.setImageBitmap(bm); - setContentView(imageView); - } + setContentView(imageView); } catch (Exception e) { e.printStackTrace(System.err); diff --git a/sal/android/lo-bootstrap.c b/sal/android/lo-bootstrap.c index fed7a4d5e271..b6e29baf13e3 100644 --- a/sal/android/lo-bootstrap.c +++ b/sal/android/lo-bootstrap.c @@ -1906,6 +1906,29 @@ Java_org_libreoffice_android_Bootstrap_twiddle_1BGR_1to_1RGBA(JNIEnv* env, } __attribute__ ((visibility("default"))) +void +Java_org_libreoffice_android_Bootstrap_force_1full_1alpha(JNIEnv* env, + jobject clazz, + jbyteArray array, + jint offset, + jint size) +{ + void *a = (*env)->GetPrimitiveArrayCritical(env, array, NULL); + jbyte *p = ((jbyte *) a) + offset; + + int i; + + (void) clazz; + + for (i = 0; i < size; i += 4) { + p[3] = 0xFF; + p += 4; + } + + (*env)->ReleasePrimitiveArrayCritical(env, array, a, 0); +} + +__attribute__ ((visibility("default"))) JavaVM * lo_get_javavm(void) { diff --git a/vcl/android/androidinst.cxx b/vcl/android/androidinst.cxx index 7c0968cd780d..ac08ac5c3926 100644 --- a/vcl/android/androidinst.cxx +++ b/vcl/android/androidinst.cxx @@ -702,7 +702,7 @@ public: sal_uLong nSalFrameStyle, SystemParentData *pSysParent ) : SvpSalFrame( pInstance, pParent, nSalFrameStyle, - true, basebmp::Format::TWENTYFOUR_BIT_TC_MASK, + true, basebmp::Format::THIRTYTWO_BIT_TC_MASK, // FIXME: Or THIRTYTWO_BIT_TC_MASK_ARGB? pSysParent ) { enableDamageTracker(); diff --git a/vcl/headless/svpbmp.cxx b/vcl/headless/svpbmp.cxx index d27b7654c56f..f1d8d49f6c66 100644 --- a/vcl/headless/svpbmp.cxx +++ b/vcl/headless/svpbmp.cxx @@ -59,6 +59,7 @@ bool SvpSalBitmap::Create( const Size& rSize, case 16: nFormat = Format::SIXTEEN_BIT_LSB_TC_MASK; break; #endif case 24: nFormat = Format::TWENTYFOUR_BIT_TC_MASK; break; + // FIXME: Should this for Android be THIRTYTWO_BIT_TC_MASK_ARGB? case 32: nFormat = Format::THIRTYTWO_BIT_TC_MASK; break; } B2IVector aSize( rSize.Width(), rSize.Height() ); diff --git a/vcl/headless/svpframe.cxx b/vcl/headless/svpframe.cxx index 63f4a49ac978..208313de99c3 100644 --- a/vcl/headless/svpframe.cxx +++ b/vcl/headless/svpframe.cxx @@ -92,8 +92,13 @@ SvpSalFrame::SvpSalFrame( SvpSalInstance* pInstance, m_aSystemChildData.nSize = sizeof( SystemChildData ); #if defined( UNX ) // FIXME: prolly redundant m_aSystemChildData.pSalFrame = this; +#if defined(ANDROID) || defined(IOS) + // We want 32-bit RGBA bitmaps + m_aSystemChildData.nDepth = 32; +#else m_aSystemChildData.nDepth = 24; #endif +#endif if( m_pParent ) m_pParent->m_aChildren.push_back( this ); diff --git a/vcl/headless/svpvd.cxx b/vcl/headless/svpvd.cxx index 8b90d648d5d5..285eeafc9b15 100644 --- a/vcl/headless/svpvd.cxx +++ b/vcl/headless/svpvd.cxx @@ -80,9 +80,13 @@ sal_Bool SvpSalVirtualDevice::SetSize( long nNewDX, long nNewDY ) #else case 16: nFormat = Format::SIXTEEN_BIT_LSB_TC_MASK; break; #endif - case 0: case 24: nFormat = Format::TWENTYFOUR_BIT_TC_MASK; break; case 32: nFormat = Format::THIRTYTWO_BIT_TC_MASK; break; +#if defined(ANDROID) || defined(IOS) + case 0: nFormat = Format::THIRTYTWO_BIT_TC_MASK; break; +#else + case 0: nFormat = Format::TWENTYFOUR_BIT_TC_MASK; break; +#endif } m_aDevice = aDevPal.empty() ? createBitmapDevice( aDevSize, false, nFormat ) |