javauis/lcdui_akn/javalcdui/javasrc/javax/microedition/lcdui/Image.java
branchRCL_3
changeset 14 04becd199f91
child 18 9ac0a0a7da70
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_akn/javalcdui/javasrc/javax/microedition/lcdui/Image.java	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,745 @@
+/*
+* Copyright (c) 1999 - 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+package javax.microedition.lcdui;
+
+
+import java.io.InputStream;
+import java.io.IOException;
+import javax.microedition.lcdui.game.Sprite;
+
+import com.nokia.mj.impl.rt.legacy.MemoryUtil;
+
+import com.nokia.mj.impl.rt.legacy.NativeError;
+import com.nokia.mj.impl.rt.support.Finalizer;
+
+/**
+ * Image API class.
+ */
+public class Image
+{
+    private static final int ATTRIB_WIDTH  = 0;
+    private static final int ATTRIB_HEIGHT = 1;
+    private static final int ATTRIB_TYPE   = 2;
+    private static final int ATTRIB_SIZE   = 3;
+    private static final int ATTRIB_COUNT  = 4;
+
+    static final int TRANSPARENCY_NONE  = 0;
+    static final int TRANSPARENCY_MASK  = 1;
+    static final int TRANSPARENCY_ALPHA = 2;
+
+    /**
+     * Image width, 0 if unknown
+     */
+    private int     iWidth;
+
+    /**
+     * Image height 0 if unknown
+     */
+    private int     iHeight;
+
+    /**
+     * true if image is mutable
+     */
+    private boolean iMutable;
+
+    /**
+     * true if image has transparency
+     */
+    private int     iTransparency;
+
+    /**
+     *
+     */
+    private int     iSizeBytes;
+
+    /**
+     * Peer handle
+     */
+    int iHandle;
+
+    /**
+     * The owning MIDlets toolkit
+     */
+    Toolkit iToolkit;
+
+    private Finalizer mFinalizer = new Finalizer()
+    {
+        public void finalizeImpl()
+        {
+            doFinalize();
+        }
+    };
+
+    private Image()
+    {
+        iToolkit = Toolkit.getToolkit();
+    }
+
+    /**
+     * Create an image wrapping a canvas native frame buffer.
+     */
+    Image(Canvas aCanvas)
+    {
+        this();
+        checkToolkit(aCanvas.iToolkit);
+        final int[] attribs = new int[ATTRIB_COUNT];
+        synchronized (iToolkit)
+        {
+            final int toolkit = iToolkit.getHandle();
+            iHandle = Toolkit.checkHandle(_createFromCanvas(toolkit, aCanvas.getContentHandle(), attribs));
+        }
+        setAttributes(attribs, true);
+    }
+
+    private Image(int aWidth, int aHeight, int aColor)
+    {
+        this();
+        final int[] attribs = new int[ATTRIB_COUNT];
+        synchronized (iToolkit)
+        {
+            final int toolkit = iToolkit.getHandle();
+            iHandle = Toolkit.checkHandle(_createMutable(toolkit, aWidth, aHeight, aColor, attribs));
+        }
+        setAttributes(attribs, true);
+    }
+
+    private Image(ImageLoader aLoader)
+    {
+        this();
+        checkToolkit(aLoader.iToolkit);
+        final int[] attribs = new int[ATTRIB_COUNT];
+        synchronized (iToolkit)
+        {
+            final int toolkit = iToolkit.getHandle();
+            iHandle = Toolkit.checkHandle(_createImmutable(toolkit, aLoader.getHandle(), attribs));
+        }
+        setAttributes(attribs, false);
+    }
+
+    /**
+     *
+     */
+    private Image(Image aSource, int aX, int aY, int aWidth, int aHeight, int aTransform)
+    {
+        this();
+        checkToolkit(aSource.iToolkit);
+        final int[] attribs = new int[ATTRIB_COUNT];
+        synchronized (iToolkit)
+        {
+            final int toolkit = iToolkit.getHandle();
+            final int source  = aSource.getHandle(true);
+            iHandle = Toolkit.checkHandle(_createRegion(toolkit, source, aX, aY, aWidth, aHeight, aTransform,attribs));
+        }
+        setAttributes(attribs, false);
+    }
+
+    private Image(int[] aRgbArray, int aWidth, int aHeight, boolean aProcessAlpha)
+    {
+        this();
+        final int[] attribs = new int[ATTRIB_COUNT];
+        synchronized (iToolkit)
+        {
+            final int toolkit = iToolkit.getHandle();
+            iHandle = Toolkit.checkHandle(_createRGB(toolkit, aRgbArray, aWidth, aHeight, aProcessAlpha, attribs));
+        }
+        setAttributes(attribs, false);
+    }
+
+    //
+    // API
+    //
+    public static Image createImage(byte[] aData,int aOffset,int aLength)
+    {
+        final int space = aData.length - aOffset; // throws NullPointerException
+
+        if ((aOffset < 0) || (space < aLength) || (aLength < 0))
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        final Toolkit toolkit = Toolkit.getToolkit();
+        ImageLoader loader = new ImageLoader(toolkit);
+        try
+        {
+            loader.append(aData, aOffset, aLength);
+            return loadImage(loader);
+        }
+        catch (Throwable t)
+        {
+            if (t instanceof OutOfMemoryError)
+            {
+                throw(OutOfMemoryError)t;
+            }
+            throw new IllegalArgumentException("bad image format");
+        }
+        finally
+        {
+            loader.dispose();
+        }
+    }
+
+    //
+    // API
+    //
+    public static Image createImage(Image aImage)
+    {
+        return createImage(aImage, 0, 0, aImage.getWidth(), aImage.getHeight(), 0);
+    }
+
+    //
+    // API
+    //
+    public static Image createImage(Image aImage, int aX, int aY, int aWidth, int aHeight, int aTransform)
+    {
+        final int width  = aImage.getWidth();   // throws NullPointerException
+        final int height = aImage.getHeight();
+
+        if (aWidth <= 0 || aHeight <= 0)
+        {
+            throw new IllegalArgumentException("invalid width or height");
+        }
+
+        final int sx1  = aX;            // left column
+        final int sx2  = aX + aWidth;   // right column
+
+        final int sy1  = aY;            // top row (inclusive)
+        final int sy2  = aY + aHeight;  // bottom row (exclusive)
+
+        //
+        // Check source x range lies within source image
+        //
+        final boolean xRangeError = (sx1 < 0) || (sx1 >= width) || (sx2 < 0) || (sx2 > width);
+        final boolean yRangeError = (sy1 < 0) || (sy1 >= height) || (sy2 < 0) || (sy2 > height);
+
+        if (xRangeError || yRangeError)
+        {
+            final String info = "args=("+aX+','+aY+','+aWidth+','+aHeight+"), rect=("+sx1 +','+sy1+','+sx2+','+sy2+"), image width="+width+",height="+height;
+            throw new IllegalArgumentException("createImage: Exceeding bounds of source image: " + info);
+        }
+
+        if (aTransform < Sprite.TRANS_NONE || aTransform > Sprite.TRANS_MIRROR_ROT90)
+        {
+            throw new IllegalArgumentException("invalid transform");
+        }
+
+        //
+        // Check for trival case for immutable images.
+        //
+        if ((!aImage.isMutable()) && (aWidth == width) && (aHeight == height) && (aTransform == Sprite.TRANS_NONE))
+        {
+            return aImage;
+        }
+
+        try
+        {
+            return new Image(aImage, aX, aY, aWidth, aHeight, aTransform);
+        }
+        catch (OutOfMemoryError oom)
+        {
+            MemoryUtil.freeNativeMemory();
+            return new Image(aImage, aX, aY, aWidth, aHeight, aTransform);
+        }
+    }
+
+    //
+    // API
+    //
+    public static Image createImage(InputStream aStream) throws java.io.IOException
+    {
+        if (null == aStream)
+        {
+            throw new NullPointerException();
+        }
+
+        return createImageFromStream(aStream);
+    }
+
+    //
+    // API
+    //
+    public static Image createImage(int aWidth,int aHeight)
+    {
+        if (aWidth <= 0 || aHeight <= 0)
+        {
+            throw new IllegalArgumentException();
+        }
+
+        try
+        {
+            return new Image(aWidth, aHeight, 0xffffffff);
+        }
+        catch (OutOfMemoryError oom)
+        {
+            MemoryUtil.freeNativeMemory();
+            return new Image(aWidth, aHeight, 0xffffffff);
+        }
+    }
+
+    //
+    // API
+    //
+    public static Image createImage(String aName) throws java.io.IOException
+    {
+        if (aName == null)
+        {
+            throw new NullPointerException();
+        }
+
+        final Toolkit toolkit = Toolkit.getToolkit();
+
+        InputStream stream = toolkit.getResourceAsStream(aName);
+        if (stream == null)
+        {
+            // Retry that allows using relative name when image is in root level
+            stream = toolkit.getResourceAsStream("/"+aName);
+            if (stream == null)
+            {
+                throw new IOException();
+            }
+        }
+
+        try
+        {
+            return createImageFromStream(stream);
+        }
+        finally
+        {
+            stream.close();
+        }
+    }
+
+    public static Image createRGBImage(int[] aRgb, int aWidth, int aHeight, boolean aProcessAlpha)
+    {
+        if (aRgb.length < (aWidth * aHeight))
+        {
+            throw new ArrayIndexOutOfBoundsException();
+        }
+
+        if (aWidth <= 0 || aHeight <= 0)
+        {
+            throw new IllegalArgumentException();
+        }
+
+        try
+        {
+            return new Image(aRgb, aWidth, aHeight, aProcessAlpha);
+        }
+        catch (OutOfMemoryError oom)
+        {
+            MemoryUtil.freeNativeMemory();
+            return new Image(aRgb, aWidth, aHeight, aProcessAlpha);
+        }
+    }
+
+
+    private static Image createImageFromStream(InputStream aStream) throws java.io.IOException
+    {
+        //
+        // maximum size of blocks to read from stream
+        //
+        final int    blocksize = 4096;
+        final byte[] buffer    = new byte[blocksize];
+
+        //
+        // create image loader to accept encoded image data.
+        //
+        final ImageLoader loader = new ImageLoader(Toolkit.getToolkit());
+        try
+        {
+            int bytesRead = 0;
+
+            //
+            // read blocks from stream and append to decoder buffer
+            //
+            while ((bytesRead = aStream.read(buffer, 0, buffer.length)) != -1)
+            {
+                if (loader.append(buffer, 0, bytesRead) == false)
+                    throw new IOException("loader.iHandle null: can't append more data");
+            }
+
+            return loadImage(loader);
+        }
+        catch (Throwable t)
+        {
+            if (t instanceof OutOfMemoryError)
+            {
+                throw(OutOfMemoryError)t;
+            }
+            throw new IOException();
+        }
+        finally
+        {
+            loader.dispose();
+        }
+    }
+
+    private static Image loadImage(ImageLoader aLoader)
+    {
+        //
+        // This is where the image is first decoded and a native representation allocated.
+        // It is more likely to fail than the image instantiation, but more risky to retry.
+        //
+
+        //
+        // REMOVED  RETRY around the following line as it caused performance unit test
+        // to panic.
+        //
+        aLoader.decode();
+
+        //
+        // This is where device specific bitmaps are created if the image was decoded in
+        // the wrong format. This is less likely to OOM than the decode above - but can
+        // be retried.
+        //
+        try
+        {
+            return new Image(aLoader);
+        }
+        catch (OutOfMemoryError oom)
+        {
+            MemoryUtil.freeNativeMemory();
+            return new Image(aLoader);
+        }
+    }
+
+    public void getRGB(int[] aRgbData,int aOffset,int aScanLength,int aX,int aY,int aWidth,int aHeight)
+    {
+        //
+        // Image bounds
+        //
+        if (aWidth <= 0 || aHeight <= 0)
+        {
+            return;
+        }
+
+        //
+        // Array bounds
+        //
+        final long limit = (long)(aRgbData.length) - 1; // throws NullPointerException
+
+        //
+        // aScanLength may be negative in which case rows are written
+        // into the buffer in reverse order.
+        //
+        long start;
+        long end;
+
+        if (aScanLength > 0)
+        {
+            start = (long)aOffset;
+            end   = (long)aOffset + (long)aScanLength*((long)aHeight-1) + (long)aWidth - 1;
+        }
+        else
+        {
+            end   = (long)aOffset + (long)aWidth - 1;
+            start = (long)aOffset + (long)aScanLength*((long)aHeight-1);
+        }
+
+        //
+        // aScanLength may be < 0, hence end < start is valid.
+        //
+        if ((start < 0) || (start > limit) || (end < 0) || (end > limit))
+        {
+            throw new ArrayIndexOutOfBoundsException("destination range exceeds array bounds");
+        }
+
+        final int width  = iWidth;
+        final int height = iHeight;
+
+        final int sx1  = aX;            // left column
+        final int sx2  = aX + aWidth;   // right column
+
+        final int sy1  = aY;            // top row (exclusive)
+        final int sy2  = aY + aHeight;  // bottom row (exclusive)
+
+        //
+        // Check source x range lies within source image
+        //
+        final boolean xRangeError = (sx1 < 0) || (sx1 >= width) || (sx2 < 0) || (sx2 > width);
+        final boolean yRangeError = (sy1 < 0) || (sy1 >= height) || (sy2 < 0) || (sy2 > height);
+
+        if (xRangeError || yRangeError)
+        {
+            final String info = "args=("+aX+','+aY+','+aWidth+','+aHeight+"), rect=("+sx1 +','+sy1+','+sx2+','+sy2+"), image width="+width+",height="+height;
+            throw new IllegalArgumentException("getRGB: Exceeding bounds of source image: " + info);
+        }
+        final int scanLength = Math.abs(aScanLength);
+
+        if (scanLength < aWidth)
+        {
+            throw new IllegalArgumentException("abs(Scanlength) should be >= width");
+        }
+        synchronized (iToolkit)
+        {
+            final int toolkit = iToolkit.getHandle();
+            final int handle  = getHandle(true);
+
+            NativeError.check(_getPixels(toolkit, handle, aRgbData, aOffset, aScanLength, aX, aY, aWidth, aHeight));
+        }
+    }
+
+    /**
+     *@returns a newly allocated thread-safe Graphics instance.
+     */
+    public Graphics getGraphics()
+    {
+        if (!isMutable())
+        {
+            throw new IllegalStateException();
+        }
+        return new Graphics(iToolkit, this, getHandle(false), iWidth, iHeight);
+    }
+
+    public int getWidth()
+    {
+        return iWidth;
+    }
+
+    public int getHeight()
+    {
+        return iHeight;
+    }
+
+    public boolean isMutable()
+    {
+        return iMutable;
+    }
+
+    /**
+     *@return true if this image has transparent pixels.
+     *
+     * May be used in game package to avoid native calls in collision
+     * detection.
+     */
+    final boolean hasTransparency()
+    {
+        return (TRANSPARENCY_NONE != iTransparency);
+    }
+
+    /**
+     * Set the image transparency type.
+     *
+     * Added to support invalid requirement of Nokia UI API - infact API only
+     * requires construction of mutable images with transparency - not after
+     * the fact transformation of image transparency type.
+     */
+    void setTransparency(int aTransparency)
+    {
+        if (aTransparency != TRANSPARENCY_ALPHA)
+        {
+            throw new IllegalArgumentException();
+        }
+        synchronized (iToolkit)
+        {
+            NativeError.check(_setTransparencyType(iToolkit.getHandle(), getHandle(true), aTransparency));
+            iTransparency = aTransparency;
+        }
+    }
+
+    /**
+     *@return the peer handle, optionally flushing and syncing the graphics buffer.
+     *
+     * If pixel data from mutable images is accessed natively without syncing the
+     * graphics buffer there is a chance that commands that would effect the
+     * pixels read have not yet been executed.
+     */
+    final int getHandle(boolean aSync)
+    {
+        if (aSync && isMutable())
+        {
+            iToolkit.sync();
+        }
+        return iHandle;
+    }
+
+    /**
+     * destroy native image.
+     */
+    private void dispose()
+    {
+        boolean freed = false;
+        synchronized (iToolkit)
+        {
+            if (iHandle != 0)
+            {
+                iToolkit.disposeObject(iHandle);
+                iHandle = 0;
+                freed   = true;
+            }
+        }
+        if (freed)
+        {
+            MemoryUtil.nativeMemoryFreed(iSizeBytes);
+        }
+    }
+
+    private void doFinalize()
+    {
+        if (mFinalizer != null)
+        {
+            registeredFinalize();
+            mFinalizer = null;
+        }
+    }
+
+    void registeredFinalize()
+    {
+        dispose();
+    }
+
+    static boolean collision
+    (
+        Image aImage1, int aS1X1, int aS1Y1, int aS1X2, int aS1Y2, int aTransform1, int aD1X, int aD1Y,
+        Image aImage2, int aS2X1, int aS2Y1, int aS2X2, int aS2Y2, int aTransform2, int aD2X, int aD2Y
+    )
+    {
+        final int result;
+        synchronized (aImage1.iToolkit)
+        {
+            final int toolkit = aImage1.iToolkit.getHandle();
+            final int image1 = aImage1.getHandle(false);
+            final int image2 = aImage2.getHandle(false);
+            result = _collision(
+                         toolkit,
+                         image1, aS1X1, aS1Y1, aS1X2, aS1Y2, aTransform1, aD1X, aD1Y,
+                         image2, aS2X1, aS2Y1, aS2X2, aS2Y2, aTransform2, aD2X, aD2Y
+                     );
+        }
+        return (result > 0);
+    }
+
+
+    /**
+     * copies pixels from source image to destination image, transforming as required.
+     */
+    private void copyRegion(Image aSource, int aX, int aY, int aWidth, int aHeight, int aTransform)
+    {
+        synchronized (iToolkit)
+        {
+            final int toolkit = iToolkit.getHandle();
+            final int target = getHandle(false);
+            final int source = aSource.getHandle(true);
+            NativeError.check(_copyRegion(toolkit, target, source, aX, aY, aWidth, aHeight, aTransform));
+        }
+    }
+
+    /**
+     * writes pixels from aArray[0..(aWidth*aHeight-1)] into image, converting from
+     * ARGB format to the image pixel format.
+     */
+    private void setRGB(int[] aRgbArray, int aOffset, int aScanLength, int aX, int aY, int aWidth, int aHeight, boolean aAlpha)
+    {
+        synchronized (iToolkit)
+        {
+            final int toolkit = iToolkit.getHandle();
+            final int handle  = getHandle(false);
+            NativeError.check(_setPixels(toolkit, handle, aRgbArray, aOffset, aScanLength, aX, aY ,aWidth, aHeight, aAlpha));
+        }
+    }
+
+    private void setAttributes(int[] aAttribs, boolean aMutable)
+    {
+        iWidth        = aAttribs[ATTRIB_WIDTH];
+        iHeight       = aAttribs[ATTRIB_HEIGHT];
+        iTransparency = aAttribs[ATTRIB_TYPE];
+        iSizeBytes    = aAttribs[ATTRIB_SIZE];
+        iMutable      = aMutable;
+        MemoryUtil.nativeMemoryAllocated(iSizeBytes);
+    }
+
+    private void checkToolkit(Toolkit aToolkit)
+    {
+        if (aToolkit != iToolkit)
+        {
+            throw new RuntimeException("Toolkit mismatch");
+        }
+    }
+
+    /**
+     * Native constructor.
+     *@param aToolkit   pointer to native toolkit instance
+     *@param aWidth     image width, may be zero if unknown
+     *@param aHeight    image height, may be zero if unknown
+     *@param aColor     image initial color, may be (semi) transparent
+     *@param aAttribs returns image attribs [width, height, transparency]
+     */
+    private native int _createMutable(int aToolkit, int aWidth, int aHeight, int aColor, int[] aAttribs);
+
+    /**
+     *@param aToolkit handle to native toolkit instance
+     *@param aLoader handle to image loader containing decoded pixel data.
+     *@param aAttribs returns image attribs [width, height, transparency]
+     */
+    private native int _createImmutable(int aToolkit, int aLoader, int[] aAttribs);
+
+    /**
+     *@param aToolkit handle
+     *@param aCanvas handle of canvas with framebuffer bitmap
+     *@param aAttribs returns image attribs [width, height, transparency]
+     */
+    private native int _createFromCanvas(int aToolkit, int aCanvas, int[] aAttribs);
+
+    /**
+     *@param aToolkit toolkit handle
+     *@param aSource  source image handle
+     *@param aX       source region x
+     *@param aY       source region y
+     *@param aWidth   source region width
+     *@param aHeight  source region height
+     *@param aTransform transform to apply to source region
+     *@param aAttribs returns image attribs [width, height, transparency]
+     */
+    private native int _createRegion(int aToolkit, int aSource, int aX, int aY, int aWidth, int aHeight, int aTransform, int[] aAttribs);
+
+    /**
+     *@param aToolkit toolkit handle
+     *@param aArray   pixel data array
+     *@param aWidth   pixel data width
+     *@param aHeight  pixel data height
+     *@param aAlpha   true if alpha component of pixel data is to be interpreted.
+     *@param aAttribs returns image attribs [width, height, transparency]
+     */
+    private native int _createRGB(int aToolkit, int[] aArray, int aWidth, int aHeight, boolean aAlpha, int[] aAttribs);
+
+    /**
+     *
+     */
+    private native int _copyRegion(int aToolkit, int aTarget,  int aSource, int aX, int aY, int aWidth, int aHeight, int aTransform);
+
+    /**
+     *
+     */
+    private native int _setPixels(int aToolkit, int aHandle, int[] aRgbArray, int aOffset, int aScanLength, int aX, int aY, int aWidth, int aHeight, boolean aAlpha);
+
+    /**
+     *
+     */
+    private native int _getPixels(int aToolkit, int aHandle, int[] aRgbArray, int aOffset, int aScanlength, int aX, int aY, int aWidth, int aHeight);
+
+    /**
+     *@return -ve on error, 1 for true 0 for false.
+     */
+    private static native int _collision
+    (
+        int aToolkit,
+        int aImage1, int aS1X1, int aS1Y1, int aS1X2, int aS1Y2, int aTransform1, int aD1X, int aD1Y,
+        int aImage2, int aS2X1, int aS2Y1, int aS2X2, int aS2Y2, int aTransform2, int aD2X, int aD2Y
+    );
+
+    private native int _setTransparencyType(int aToolkit, int aImage, int aType);
+}