javauis/lcdui_qt/src/javax/microedition/lcdui/Graphics.java
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 14 May 2010 15:47:24 +0300
changeset 23 98ccebc37403
parent 21 2a9601315dfc
child 26 dc7c549001d5
permissions -rw-r--r--
Revision: v2.1.24 Kit: 201019

/*
* Copyright (c) 2009 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 org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Internal_GfxPackageSupport;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.internal.qt.graphics.GraphicsContext;
import org.eclipse.swt.internal.qt.graphics.JavaCommandBuffer;
import org.eclipse.swt.internal.qt.graphics.FontUtils;

import com.nokia.mid.ui.DirectGraphics;

/**
 * Implementation of LCDUI <code>Graphics</code> class.
 */
public class Graphics
{

    /**
     * Constant for horizontal center alignment of the text.
     */
    public static final int HCENTER = 1;

    /**
     * Constant for vertical alignment of the image.
     */
    public static final int VCENTER = 2;

    /**
     * Constant for horizontal left alignment of the text.
     */
    public static final int LEFT = 4;

    /**
     * Constant for horizontal right alignment of the text.
     */
    public static final int RIGHT = 8;

    /**
     * Constant for vertical top alignment of the text.
     */
    public static final int TOP = 16;

    /**
     * Constant for vertical bottom alignment of the text.
     */
    public static final int BOTTOM = 32;

    /**
     * Constant for vertical baseline alignment of the text.
     */
    public static final int BASELINE = 64;

    /**
     * Constant for solid stroke style.
     */
    public static final int SOLID = 0;

    /**
     * Constant for dotted stroke style.
     */
    public static final int DOTTED = 1;

    static final int RGB_MASK = 0x00FFFFFF;

    static final int COMPONENT_MASK = 0xFF;

    private DirectGraphics directGraphics;

    // Graphics rectangle (off-screen buffer rectangle).
    // private Rectangle graphicsClientArea;

    // Graphics context for drawing to off-screen buffer.
    private GraphicsContext gc;

    // Off-screen buffer.
    //private org.eclipse.swt.internal.qt.graphics.Image frameBuffer;

    // Current font for rendering texts.
    private Font currentFont;
    private int currentColor;
    private int translateX;
    private int translateY;
    private int[] currentClip = new int[4];
    private int currentStrokeSyle;

    // Image owning the Graphics if the Graphics object belongs to an Image.
    private Image parentImage;

    // Flag indicating that we are in Canvas.paint() callback,
    // thus inside UI thread
    private boolean paintCallBack;
    private boolean buffered;
    private JavaCommandBuffer cmdBuffer;
    private com.nokia.mj.impl.rt.support.Finalizer finalizer;
    // serialization lock for command buffering and flush
    private final Object flushLock = new Object();
    private Canvas canvasParent;
    private CustomItem customItemParent;

    //Constructor
    Graphics()
    {
        finalizer = ((finalizer != null) ? finalizer
                     : new com.nokia.mj.impl.rt.support.Finalizer()
        {
            public void finalizeImpl()
            {
                if(finalizer != null)
                {
                    finalizer = null;
                    if(!ESWTUIThreadRunner.isDisposed())
                    {
                        ESWTUIThreadRunner.safeSyncExec(new Runnable()
                        {
                            public void run()
                            {
                                dispose();
                            }
                        });

                    }
                }
            }
        });
    }
    /**
     * Set the parent image of this Graphics.
     *
     * @param image an image
     */
    void eswtSetParentImage(final Image image)
    {
        if(buffered)
        {
            return;
        }
        if(parentImage != image)
        {
            parentImage = image;

            if(gc == null)
            {
                gc = new GraphicsContext();
            }
            else
            {
                gc.releaseTarget();
            }
            ESWTUIThreadRunner.safeSyncExec(new Runnable()
            {
                public void run()
                {
                    org.eclipse.swt.graphics.Image eswtImage = Image.getESWTImage(image);

                    if(eswtImage != null)
                    {
                        gc.bindTarget(Internal_GfxPackageSupport.getImage(eswtImage));
                        Rectangle clipRect = eswtImage.getBounds();
                        setClip(0, 0, clipRect.width, clipRect.height);
                    }
                    reset();
                }
            });
        }
    }

    /**
     * Initializes this instance of Graphics to use command buffer.
     *
     * Can be called in a non-UI thread. Not thread-safe.
     *
     * @param x The x-coordinate of clip
     * @param y The y-coordinate of clip
     * @param width The width of clip
     * @param height The height of clip
     */
    void initBuffered(final Canvas parent, final int x, final int y, final int width, final int height)
    {
        ESWTUIThreadRunner.safeSyncExec(new Runnable()
        {
            public void run()
            {
                cmdBuffer = new JavaCommandBuffer();
                if(gc == null)
                {
                    gc = new GraphicsContext();
                }
                gc.bindTarget(cmdBuffer);
                setClip(x, y, width, height);
                reset();
                buffered = true;
                javax.microedition.lcdui.Graphics.this.canvasParent = parent;
            }
        });
    }

    /**
     * Initializes this instance of Graphics to use command buffer.
     *
     * Can be called in a non-UI thread. Not thread-safe.
     *
     * @param x The x-coordinate of clip
     * @param y The y-coordinate of clip
     * @param width The width of clip
     * @param height The height of clip
     */
    void initBuffered(CustomItem parent, int x, int y, int width, int height)
    {
        cmdBuffer = new JavaCommandBuffer();
        if(gc == null)
        {
            gc = new GraphicsContext();
        }
        gc.bindTarget(cmdBuffer);
        setClip(x, y, width, height);
        reset();
        buffered = true;
        this.customItemParent = parent;
    }

    /**
     * Resets the command buffer contents.
     *
     * This is safe to call only in the UI thread.
     */
    void resetCommandBuffer()
    {
        gc.releaseTarget();
        cmdBuffer.reset();
        gc.bindTarget(cmdBuffer);
        // write settings which were active before flush
        // if they are not the same as defaults
        gc.setFont(Font.getESWTFont(currentFont).handle);
        gc.setBackgroundColor(currentColor, false);
        gc.setForegroundColor(currentColor, false);
        if((translateX != 0) || (translateY != 0))
        {
            gc.translate(translateX, translateY);
        }

        // Note that if called in a non-UI thread then the size of the
        // Canvas or CustomItem can change between getting the height and
        // getting the width. Those are modified by the UI thread and there
        // is no synchronization.
        int w = 0;
        int h = 0;
        if(canvasParent != null)
        {
            w = canvasParent.getWidth();
            h = canvasParent.getHeight();
        }
        else
        {
            w = customItemParent.getContentWidth();
            h = customItemParent.getContentHeight();
        }

        if((currentClip[0] != 0) && (currentClip[1] != 0) &&
                (currentClip[2] != w) && (currentClip[2] != h))
        {
            gc.setClip(currentClip[0], currentClip[1], currentClip[2], currentClip[3], false);
        }
        if(currentStrokeSyle != SOLID)
        {
            gc.setStrokeStyle(GraphicsContext.STROKE_DOT);
        }
    }

    /**
     * Returns the current command buffer or null.
     *
     * This method is thread-safe.
     */
    JavaCommandBuffer getCommandBuffer()
    {
        return cmdBuffer;
    }

    /**
     * Get the parent image of this Graphics.
     */
    Image getParentImage()
    {
        return parentImage;
    }

    /**
     * Set Graphics context to a target - the GC is coming from paint event.
     *
     * @param eswtGC
     */
    void eswtSetGC(final GC eswtGC)
    {
        if(buffered)
        {
            return;
        }
        gc = eswtGC.getGCData().internalGc;
        ESWTUIThreadRunner.safeSyncExec(new Runnable()
        {
            public void run()
            {
                Rectangle clipRect = eswtGC.getClipping();
                setClip(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
                reset();
            }
        });
    }

    /**
     * Disposes Graphics context resources.
     */
    void dispose()
    {
        if(parentImage != null)
        {
            parentImage = null;
        }
        if(gc != null)
        {
            ESWTUIThreadRunner.safeSyncExec(new Runnable()
            {
                public void run()
                {
                    gc.dispose();
                }
            });
            gc = null;
        }
        if(cmdBuffer != null)
        {
            cmdBuffer = null;
        }
    }

    /**
     * Resets Graphics state to initial.
     */
    void reset()
    {
        setColor(0, 0, 0);
        setFont(Font.getDefaultFont());
        setStrokeStyle(Graphics.SOLID);
        this.translateX = 0;
        this.translateY = 0;
    }

    /**
     * Cleans the Canvas background.
     */
    void cleanBackground(Rectangle area)
    {
        int savedColor = currentColor;
        setColor(255, 255, 255);
        fillRect(area.x, area.y, area.width, area.height);
        setColor(savedColor);
    }

    /**
     * Cleans the Canvas background.
     */
    void cleanBackground(int x, int y, int w, int h)
    {
        int savedColor = currentColor;
        setColor(255, 255, 255);
        fillRect(x, y, w, h);
        setColor(savedColor);
    }

    /**
     * Sets flag indicating that we are in Canvas.paint() callback
     */
    void beginPaint()
    {
        paintCallBack = true;
    }

    /**
     * Sets flag indicating that we are exiting Canvas.paint() callback
     */
    void endPaint()
    {
        paintCallBack = false;
    }

    /**
     * Provides the serialization lock for buffer writing and flushing
     * @return lock used for synchronizing command buffer access
     */
    Object getLock()
    {
        return flushLock;
    }

    /**
     * Sets coordinate translation. Translations are cumulative.
     *
     * @param xDelta x-shift for coordinates.
     * @param yDelta y-shift for coordinates.
     */
    public void translate(int xDelta, int yDelta)
    {
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int xDelta_ = xDelta;
                final int yDelta_ = yDelta;
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.translate(xDelta_, yDelta_);
                    }
                });
            }
            else
            {
                gc.translate(xDelta, yDelta);
            }
        }
        translateX += xDelta;
        translateY += yDelta;
    }

    /**
     * Returns current X-shift of coordinate translation.
     *
     * @return Current X-shift of coordinate translation.
     */
    public int getTranslateX()
    {
        return translateX;
    }

    /**
     * Returns current Y-shift of coordinate translation.
     *
     * @return current Y-shift of coordinate translation.
     */
    public int getTranslateY()
    {
        return translateY;
    }

    /**
     * Returns current color in 0x00RRGGBB format.
     *
     * @return Current color in 0x00RRGGBB format.
     */
    public int getColor()
    {
        return currentColor;
    }

    /**
     * Returns red component of current color.
     *
     * @return Red component of current color in the range of 0-255.
     */
    public int getRedComponent()
    {
        return currentColor >> 16;
    }

    /**
     * Returns green component of current color.
     *
     * @return Green component of current color in the range of 0-255.
     */
    public int getGreenComponent()
    {
        return (currentColor >> 8) & COMPONENT_MASK;
    }

    /**
     * Returns blue component of current color.
     *
     * @return Blue component of current color in the range of 0-255.
     */
    public int getBlueComponent()
    {
        return currentColor & COMPONENT_MASK;
    }

    /**
     * Returns current grayscale color.
     *
     * @return Returns current grayscale color in the range 0-255.
     */
    public int getGrayScale()
    {
        return (getRedComponent() + getGreenComponent() + getBlueComponent()) / 3;
    }

    /**
     * Sets the current color by color components for red, green and blue.
     *
     * @param r - red component of the color to be set.
     * @param g - green component of the color to be set.
     * @param b - blue component of the color to be set.
     */
    public void setColor(int r, int g, int b)
    {
        if(r < 0 || r > 255 ||
                g < 0 || g > 255 ||
                b < 0 || b > 255)
        {
            throw new IllegalArgumentException();
        }
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int r_ = r;
                final int g_ = g;
                final int b_ = b;
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.setForegroundColor(r_, g_, b_);
                        gc.setBackgroundColor(r_, g_, b_);
                    }
                });
            }
            else
            {
                gc.setForegroundColor(r, g, b);
                gc.setBackgroundColor(r, g, b);
            }
        }
        currentColor = ((r << 16) | (g << 8) | b) & RGB_MASK;
    }

    /**
     * Sets the current color.
     *
     * @param RGB - color to be set in the form of 0x00RRGGBB.
     */
    public void setColor(int RGB)
    {
        int maskedRGB = RGB & RGB_MASK;
        final int r = maskedRGB >> 16;
        final int g = (maskedRGB >> 8) & COMPONENT_MASK;
        final int b = maskedRGB & COMPONENT_MASK;
        synchronized(flushLock)
        {
            if(!buffered)
            {
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.setForegroundColor(r, g, b);
                        gc.setBackgroundColor(r, g, b);
                    }
                });
            }
            else
            {
                gc.setForegroundColor(r, g, b);
                gc.setBackgroundColor(r, g, b);
            }
        }
        currentColor = maskedRGB;
    }

    /**
     * Sets gray-scale color.
     *
     * @param val - gray-scale value to be set in the range of 0-255.
     */
    public void setGrayScale(int val)
    {
        if((val < 0) || (val > 255))
        {
            throw new IllegalArgumentException();
        }
        final int col = val & COMPONENT_MASK;
        synchronized(flushLock)
        {
            if(!buffered)
            {
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.setForegroundColor(col, col, col);
                        gc.setBackgroundColor(col, col, col);
                    }
                });
            }
            else
            {
                gc.setForegroundColor(col, col, col);
                gc.setBackgroundColor(col, col, col);
            }
        }
        currentColor = ((col << 16) | (col << 8) | col) & RGB_MASK;
    }

    /**
     * Returns the current font.
     *
     * @return Current font.
     */
    public Font getFont()
    {
        return currentFont;
    }

    /**
     * Sets the font to be used for string rendering.
     *
     * @param newFont - the font to be used for string rendering.
     */
    public void setFont(Font newFont)
    {
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final Font newFont_ = newFont;
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.setFont(Font.getESWTFont(newFont_).handle);
                    }
                });
            }
            else
            {
                gc.setFont(Font.getESWTFont(newFont).handle);
            }
        }
        currentFont = newFont;
    }

    /**
     * Returns left bound of clip rectangle.
     *
     * @return Left bound of clip rectangle.
     */
    public int getClipX()
    {
        return currentClip[0];
    }

    /**
     * Returns top bound of clip rectangle.
     *
     * @return Top bound of clip rectangle.
     */
    public int getClipY()
    {
        return currentClip[1];
    }

    /**
     * Returns width of clip rectangle.
     *
     * @return Width of clip rectangle.
     */
    public int getClipWidth()
    {
        return currentClip[2];
    }

    /**
     * Returns height of clip rectangle.
     *
     * @return Height of clip rectangle.
     */
    public int getClipHeight()
    {
        return currentClip[3];
    }

    /**
     * Intersects current clip rectangle with the specified one.
     *
     * @param x - left bound of the clip rectangle to intersect with the
     *            current one.
     * @param y - top bound of the clip rectangle to intersect with the
     *            current one.
     * @param w - width of the clip rectangle to intersect with the current one.
     * @param h - height of the clip rectangle to intersect with the current
     *            one.
     */
    public void clipRect(int x, int y, int w, int h)
    {
        final int cx2 = Math.min(currentClip[0] + currentClip[2], x + w);
        final int cy2 = Math.min(currentClip[1] + currentClip[3], y + h);
        // setting of clip to Java Graphics
        currentClip[0] = Math.max(x, currentClip[0]);
        currentClip[1] = Math.max(y, currentClip[1]);
        currentClip[2] = cx2 - currentClip[0];
        currentClip[3] = cy2 - currentClip[1];
        synchronized(flushLock)
        {
            if(!buffered)
            {
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.setClip(currentClip[0], currentClip[1], currentClip[2], currentClip[3], false);
                    }
                });
            }
            else
            {
                gc.setClip(currentClip[0], currentClip[1], currentClip[2], currentClip[3], false);
            }
        }
    }

    /**
     * Sets the clip rectangle.
     *
     * @param x - left bound of the new clip rectangle.
     * @param y - top bound of the new clip rectangle.
     * @param w - width of the new clip rectangle.
     * @param h - height of the new clip rectangle.
     */
    public void setClip(int x, int y, int w, int h)
    {
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int x_ = x;
                final int y_ = y;
                final int w_ = w;
                final int h_ = h;

                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.setClip(x_, y_, w_, h_, false);
                    }
                });
            }
            else
            {
                gc.setClip(x, y, w, h, false);
            }
        }
        currentClip[0] = x;
        currentClip[1] = y;
        currentClip[2] = w;
        currentClip[3] = h;
    }

    /**
     * Draws a line with current color and current stroke style.
     *
     * @param xStart - X-coordinate of line starting point.
     * @param yStart - Y-coordinate of line starting point.
     * @param xEnd - X-coordinate of line end point.
     * @param yEnd - Y-coordinate of line end point.
     */
    public void drawLine(int xStart, int yStart, int xEnd, int yEnd)
    {
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int xs_ = xStart;
                final int ys_ = yStart;
                final int xe_ = xEnd;
                final int ye_ = yEnd;

                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.drawLine(xs_, ys_, xe_, ye_);
                    }
                });
            }
            else
            {
                gc.drawLine(xStart, yStart, xEnd, yEnd);
            }
        }
    }

    /**
     * Fills a rectangle with current color.
     *
     * @param x - x coordinate of top left corner
     * @param y - y coordinate of top left corner
     * @param w - width of the rectangle
     * @param h - height of the rectangle
     */
    public void fillRect(int x, int y, int w, int h)
    {
        if((w < 0) || (h < 0))
        {
            return;
        }
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int x_ = x;
                final int y_ = y;
                final int w_ = w;
                final int h_ = h;

                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.fillRect(x_, y_, w_, h_);
                    }
                });
            }
            else
            {
                gc.fillRect(x, y, w, h);
            }
        }
    }

    /**
     * Draws a rectangle with specified color and stroke style.
     *
     * @param x - x coordinate of top left corner
     * @param y - y coordinate of top left corner
     * @param w - width of the rectangle
     * @param h - height of the rectangle
     */
    public void drawRect(int x, int y, int w, int h)
    {
        if((w < 0) || (h < 0))
        {
            return;
        }
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int x_ = x;
                final int y_ = y;
                final int w_ = w;
                final int h_ = h;
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.drawRect(x_, y_, w_, h_);
                    }
                });
            }
            else
            {
                gc.drawRect(x, y, w, h);
            }
        }
    }

    /**
     * Draws a rounded rectangle with specified color and stroke style.
     *
     * @param x - x coordinate of top left corner
     * @param y - y coordinate of top left corner
     * @param w - width of the rectangle
     * @param h - height of the rectangle
     * @param arcW - arc width for corner rounding.
     * @param arcH - arc height for corner rounding.
     */
    public void drawRoundRect(int x, int y, int w, int h, int arcW, int arcH)
    {
        if((w < 0) || (h < 0) || (arcW < 0) || (arcH < 0))
        {
            return;
        }
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int x_ = x;
                final int y_ = y;
                final int w_ = w;
                final int h_ = h;
                final int arcW_ = arcW;
                final int arcH_ = arcH;

                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.drawRoundRect(x_, y_, w_, h_, arcW_, arcH_);
                    }
                });
            }
            else
            {
                gc.drawRoundRect(x, y, w, h, arcW, arcH);
            }
        }
    }

    /**
     * Fills a rounded rectangle with specified color.
     *
     * @param x - x coordinate of top left corner
     * @param y - y coordinate of top left corner
     * @param w - width of the rectangle
     * @param h - height of the rectangle
     * @param arcW - arc width for corner rounding.
     * @param arcH - arc height for corner rounding.
     */
    public void fillRoundRect(int x, int y, int w, int h, int arcW, int arcH)
    {
        if((w < 0) || (h < 0) || (arcW < 0) || (arcH < 0))
        {
            return;
        }
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int x_ = x;
                final int y_ = y;
                final int w_ = w;
                final int h_ = h;
                final int arcW_ = arcW;
                final int arcH_ = arcH;

                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.fillRoundRect(x_, y_, w_, h_, arcW_, arcH_);
                    }
                });
            }
            else
            {
                gc.fillRoundRect(x, y, w, h, arcW, arcH);
            }
        }
    }

    /**
     * Fills an arc with specified color.
     *
     * @param x - X-coordinate of top left corner of the rectangle to contain
     *            the arc.
     * @param y - Y-coordinate of top left corner of the rectangle to contain
     *            the arc.
     * @param w - width of the rectangle to contain the arc.
     * @param h - height of the rectangle to contain the arc.
     * @param startAngle - starting angle of the arc in degrees.
     * @param arcAngle - angle to spread the arc in degrees.
     */
    public void fillArc(int x, int y, int w, int h, int startAngle, int arcAngle)
    {
        if((w < 0) || (h < 0))
        {
            return;
        }
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int x_ = x;
                final int y_ = y;
                final int w_ = w;
                final int h_ = h;
                final int startAngle_ = startAngle;
                final int arcAngle_ = arcAngle;

                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.fillArc(x_, y_, w_, h_, startAngle_, arcAngle_);
                    }
                });
            }
            else
            {
                gc.fillArc(x, y, w, h, startAngle, arcAngle);
            }
        }
    }

    /**
     * Draws an arc with specified color and stroke style.
     *
     * @param x - X-coordinate of top left corner of the rectangle to contain
     *            the arc.
     * @param y - Y-coordinate of top left corner of the rectangle to contain
     *            the arc.
     * @param w - width of the rectangle to contain the arc.
     * @param h - height of the rectangle to contain the arc.
     * @param startAngle - starting angle of the arc in degrees.
     * @param arcAngle - angle to spread the arc in degrees.
     */
    public void drawArc(int x, int y, int w, int h, int startAngle, int arcAngle)
    {
        if((w < 0) || (h < 0))
        {
            return;
        }
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int x_ = x;
                final int y_ = y;
                final int w_ = w;
                final int h_ = h;
                final int startAngle_ = startAngle;
                final int arcAngle_ = arcAngle;

                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.drawArc(x_, y_, w_, h_, startAngle_, arcAngle_);
                    }
                });
            }
            else
            {
                gc.drawArc(x, y, w, h, startAngle, arcAngle);
            }
        }
    }

    /**
     * Draws a string with specified color and font.
     *
     * @param string - the string to draw.
     * @param xPos - X-coordinate of the anchor point.
     * @param yPos - Y-coordinate of the anchor point
     * @param anch - anchor, specifies the way to locate the text around the anchor
     *            point. May be the combination of Graphics.TOP,
     *            Graphics.BOTTOM, Graphics.BASELINE, Graphics.LEFT,
     *            Graphics.RIGHT, Graphics.HCENTER.
     */
    public void drawString(String string, int xPos, int yPos, int anch)
    {
        if(string == null)
        {
            throw new NullPointerException(
                MsgRepository.GRAPHICS_EXCEPTION_STRING_IS_NULL);
        }

        if(!checkTextAnchors(anch))
        {
            throw new IllegalArgumentException(
                MsgRepository.GRAPHICS_EXCEPTION_INVALID_ANCHOR);
        }

        final int alignments = GraphicsContext.ALIGNMENT_TOP | GraphicsContext.ALIGNMENT_LEFT;
        final int[] boundingBox = new int[4];
        final String localStr = string;

        if(paintCallBack)
        {
            gc.getTextBoundingBox(boundingBox, string, alignments, 0);
        }
        else
        {
            ESWTUIThreadRunner.safeSyncExec(new Runnable()
            {
                public void run()
                {
                    FontUtils fu = new FontUtils(Font.getESWTFont(currentFont).handle);
                    fu.getBoundingRect(boundingBox, localStr);
                }
            });
        }

        // boundingBox[RECT_X] - top-left x of the text bounding box
        // boundingBox[RECT_Y] - top-left y of the text bounding box
        // boundingBox[RECT_WIDTH] - the width of the text bounding box
        // boundingBox[RECT_HEIGHT] - the height of the text bounding box

        // Arrange vertical alignments
        int y = yPos;
        if(isFlag(anch, Graphics.BOTTOM))
        {
            y = yPos - boundingBox[GraphicsContext.RECT_HEIGHT];
        }
        if(isFlag(anch, Graphics.BASELINE))
        {
            y = yPos - currentFont.getBaselinePosition();
        }

        // Arrange horizontal alignments
        int x = xPos;
        if(isFlag(anch, Graphics.RIGHT))
        {
            x = xPos - boundingBox[GraphicsContext.RECT_WIDTH];
        }
        if(isFlag(anch, Graphics.HCENTER))
        {
            x = xPos - boundingBox[GraphicsContext.RECT_WIDTH] / 2;
        }
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int x_ = x;
                final int y_ = y;
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.drawString(localStr, x_, y_, true);
                    }
                });
            }
            else
            {
                gc.drawString(localStr, x, y, true);
            }
        }
    }

    private static boolean isFlag(int anchor, int flag)
    {
        return (anchor & flag) != 0;
    }

    /**
     * Draws a string with specified color and font.
     *
     * @param string - the string to draw.
     * @param offset - offset of substring in the string.
     * @param length - length of substring.
     * @param xPos - X-coordinate of the anchor point.
     * @param yPos - Y-coordinate of the anchor point
     * @param anch - anchor, specifies the way to locate the text around the
     *            anchor point. May be the combination of Graphics.TOP,
     *            Graphics.BOTTOM, Graphics.BASELINE, Graphics.LEFT,
     *            Graphics.RIGHT, Graphics.HCENTER.
     */
    public void drawSubstring(java.lang.String string, int offset, int length,
                              int xPos, int yPos, int anch)
    {
        drawString(string.substring(offset, length), xPos, yPos, anch);
    }

    /**
     * Draws a character with specified color and font.
     *
     * @param c - character to draw.
     * @param xPos - X-coordinate of the anchor point.
     * @param yPos - Y-coordinate of the anchor point
     * @param anch - anchor, specifies the way to locate the text around the
     *            anchor point. May be the combination of Graphics.TOP,
     *            Graphics.BOTTOM, Graphics.BASELINE, Graphics.LEFT,
     *            Graphics.RIGHT, Graphics.HCENTER.
     */
    public void drawChar(char c, int xPos, int yPos, int anch)
    {
        drawString(String.valueOf(c), xPos, yPos, anch);
    }

    /**
     * Draws characters from array with specified color and font.
     *
     * @param ch -character array to draw.
     * @param offset - offset of the starting character in the array.
     * @param length - length of character sequence from the array to draw.
     * @param xPos - X-coordinate of the anchor point.
     * @param yPos - Y-coordinate of the anchor point
     * @param anch - anchor, specifies the way to locate the text around the
     *            anchor point. May be the combination of Graphics.TOP,
     *            Graphics.BOTTOM, Graphics.BASELINE, Graphics.LEFT,
     *            Graphics.RIGHT, Graphics.HCENTER.
     */
    public void drawChars(char[] ch, int offset, int length,
                          int xPos, int yPos, int anch)
    {
        if(ch == null)
        {
            throw new NullPointerException(
                MsgRepository.GRAPHICS_EXCEPTION_ARRAY_IS_NULL);
        }
        String str = null;
        try
        {
            str = String.valueOf(ch, offset, length);
        }
        catch(Exception e)
        {
            throw new ArrayIndexOutOfBoundsException(
                MsgRepository.GRAPHICS_EXCEPTION_ARRAY_OUT_OF_BOUNDS);
        }

        drawString(str, xPos, yPos, anch);
    }

    /**
     * Checks if anchors combination is valid.
     */
    private boolean checkTextAnchors(int anch)
    {
        boolean retVal = false;

        int vertMask = Graphics.TOP | Graphics.BASELINE | Graphics.BOTTOM;
        int horMask = Graphics.LEFT | Graphics.RIGHT | Graphics.HCENTER;

        if(anch == 0)
        {
            return true;
        }

        if((anch & ~(vertMask | horMask)) != 0)
        {
            return false;
        }

        int vertAchor = anch & vertMask;
        int horAchor = anch & horMask;

        if((vertAchor == Graphics.TOP)
                || (vertAchor == Graphics.BASELINE)
                || (vertAchor == Graphics.BOTTOM))
        {
            retVal = true;
        }

        if((horAchor == Graphics.LEFT)
                || (vertAchor == Graphics.RIGHT)
                || (vertAchor == Graphics.HCENTER))
        {
            retVal = true;
        }

        return retVal;
    }

    /**
     * Draw an Image to the graphical context.
     *
     * @param image - Image to be drawn.
     * @param xPos - X-coordinate of the anchor point.
     * @param yPos - Y-coordinate of the anchor point.
     * @param anch - anchor value.
     */
    public void drawImage(javax.microedition.lcdui.Image image, int xPos,
                          int yPos, int anch)
    {

        if(image == null)
        {
            throw new NullPointerException(
                MsgRepository.IMAGE_EXCEPTION_IS_NULL);
        }
        if(!checkImageAnchors(anch))
        {
            throw new IllegalArgumentException(
                MsgRepository.GRAPHICS_EXCEPTION_INVALID_ANCHOR);
        }

        int y = yPos;
        if(isFlag(anch, Graphics.VCENTER))
        {
            y = yPos - image.getHeight() / 2;
        }
        if(isFlag(anch, Graphics.BOTTOM))
        {
            y = yPos - image.getHeight();
        }

        int x = xPos;
        if(isFlag(anch, Graphics.HCENTER))
        {
            x = xPos - image.getWidth() / 2;
        }
        if(isFlag(anch, Graphics.RIGHT))
        {
            x = xPos - image.getWidth();
        }

        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int x_ = x;
                final int y_ = y;
                final org.eclipse.swt.internal.qt.graphics.Image image_ =
                    Internal_GfxPackageSupport.getImage(Image.getESWTImage(image));
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.drawImage(image_, x_, y_);
                    }
                });
            }
            else
            {
                gc.drawImage(Internal_GfxPackageSupport.getImage(Image.getESWTImage(image)), x, y);
            }
        }
    }

    /**
     * Checks if anchors combination is valid.
     */
    private boolean checkImageAnchors(int anch)
    {
        boolean retVal = false;

        int vertMask = Graphics.TOP | Graphics.VCENTER | Graphics.BOTTOM;
        int horMask = Graphics.LEFT | Graphics.RIGHT | Graphics.HCENTER;

        if(anch == 0)
        {
            return true;
        }

        if((anch & ~(vertMask | horMask)) != 0)
        {
            return false;
        }

        int vertAchor = anch & vertMask;
        int horAchor = anch & horMask;

        if((vertAchor == Graphics.TOP)
                || (vertAchor == Graphics.VCENTER)
                || (vertAchor == Graphics.BOTTOM))
        {
            retVal = true;
        }

        if((horAchor == Graphics.LEFT)
                || (vertAchor == Graphics.RIGHT)
                || (vertAchor == Graphics.HCENTER))
        {
            retVal = true;
        }

        return retVal;
    }

    /**
     * Sets the stroke style for drawing graphical primitives.
     *
     * @param newStyle - new style, valid values are Graphics.SOLID and
     *            Graphics.DOTTED.
     * @throws IllegalArgumentException if the new style value is invalid.
     */
    public void setStrokeStyle(int newStyle)
    {
        if(newStyle == currentStrokeSyle)
        {
            return;
        }
        if(newStyle == SOLID)
        {
            synchronized(flushLock)
            {
                if(!buffered)
                {
                    ESWTUIThreadRunner.safeSyncExec(new Runnable()
                    {
                        public void run()
                        {
                            gc.setStrokeStyle(GraphicsContext.STROKE_SOLID);
                        }
                    });
                }
                else
                {
                    gc.setStrokeStyle(GraphicsContext.STROKE_SOLID);
                }
            }
        }
        else
        {
            if(newStyle == DOTTED)
            {
                synchronized(flushLock)
                {
                    if(!buffered)
                    {
                        ESWTUIThreadRunner.safeSyncExec(new Runnable()
                        {
                            public void run()
                            {
                                gc.setStrokeStyle(GraphicsContext.STROKE_DOT);
                            }
                        });
                    }
                    else
                    {
                        gc.setStrokeStyle(GraphicsContext.STROKE_DOT);
                    }
                }
            }
            else
            {
                throw new IllegalArgumentException(
                    MsgRepository.GRAPHICS_EXCEPTION_ILLEGAL_STROKE_STYLE);
            }
        }
        currentStrokeSyle = newStyle;
    }

    /**
     * Returns current stroke style.
     *
     * @return Current stroke style.
     */
    public int getStrokeStyle()
    {
        return currentStrokeSyle;
    }

    /**
     * Returns the color that will be used if the specified color is requested.
     *
     * @param color - color to use in 0x00RRGGBB form.
     * @return Color that will be actually used in 0x00RRGGBB form.
     */
    public int getDisplayColor(int color)
    {
        return color & RGB_MASK;
    }

    /**
     * Renders 0xAARRGGBB pixels.
     *
     * @param rgb - array of ARGB values
     * @param offset - index of the first value in the array.
     * @param scanlength - relative distance in the array between. corresponding
     *            pixels of consecutive rows.
     * @param x - X-coordinate of the top-left corner of the rectangle to be
     *            rendered.
     * @param y - Y-coordinate of the top-left corner of the rectangle to be
     *            rendered.
     * @param w - width of the rectangle to be rendered.
     * @param h - height of the rectangle to be rendered.
     * @param alpha - true if alpha values should be rendered, false otherwise.
     */
    public void drawRGB(int[] rgb,
                        int offset,
                        int scanlength,
                        int x,
                        int y,
                        int w,
                        int h,
                        boolean alpha)
    {

        if(rgb == null)
        {
            throw new NullPointerException(
                MsgRepository.IMAGE_EXCEPTION_DATA_IS_NULL);
        }
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int[] rgb_ = rgb;
                final int offset_ = offset;
                final int scanlength_ = scanlength;
                final int x_ = x;
                final int y_ = y;
                final int w_ = w;
                final int h_ = h;
                final boolean alpha_ = alpha;

                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.drawRGB(rgb_, offset_, scanlength_, x_, y_, w_, h_, alpha_);
                    }
                });
            }
            else
            {
                gc.drawRGB(rgb, offset, scanlength, x, y, w, h, alpha);
            }
        }
    }

    /**
     * Fills the specified triangle with current color.
     *
     * @param xPos1 - X-coordinate of first vertex.
     * @param yPos1 - Y-coordinate of first vertex.
     * @param xPos2 - X-coordinate of second vertex.
     * @param yPos2 - Y-coordinate of second vertex.
     * @param xPos3 - X-coordinate of third vertex.
     * @param yPos3 - Y-coordinate of third vertex.
     */
    public void fillTriangle(int xPos1,
                             int yPos1,
                             int xPos2,
                             int yPos2,
                             int xPos3,
                             int yPos3)
    {
        final int[] points = {xPos1, yPos1, xPos2, yPos2, xPos3, yPos3};
        synchronized(flushLock)
        {
            if(!buffered)
            {
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.fillPolygon(points);
                    }
                });
            }
            else
            {
                gc.fillPolygon(points);
            }
        }
    }

    /**
     * Copies the specified area.
     *
     * @param xFrom - X-coordinate of the top-left corner of the region to copy.
     * @param yFrom - Y-coordinate of the top-left corner of the region to copy.
     * @param w - width of the region to copy.
     * @param h - height of the region to copy.
     * @param xTo - X-coordinate of the anchor point to copy region to.
     * @param yTo - Y-coordinate of the anchor point to copy region to.
     * @param anch - anchor point specification.
     */
    public void copyArea(int xFrom,
                         int yFrom,
                         int w,
                         int h,
                         int xTo,
                         int yTo,
                         int anch)
    {

        if(this.parentImage == null)
        {
            // this Graphics belongs to a screen device.
            throw new IllegalStateException(
                MsgRepository.GRAPHICS_EXCEPTION_DESTINATION_IS_SCREEN);
        }

        if(!javax.microedition.lcdui.Image.validateRegion(parentImage
                .getWidth(), parentImage.getHeight(), xFrom, yFrom, w, h))
        {
            throw new IllegalArgumentException(
                MsgRepository.IMAGE_EXCEPTION_INVALID_REGION);
        }

        // Arrange vertical alignments
        int destY = yTo;
        if(isFlag(anch, Graphics.BOTTOM))
        {
            destY = yTo - h;
        }
        if(isFlag(anch, Graphics.VCENTER))
        {
            destY = yTo - h / 2;
        }

        // Arrange horizontal alignments
        int destX = xTo;
        if(isFlag(anch, Graphics.RIGHT))
        {
            destX = xTo - w;
        }
        if(isFlag(anch, Graphics.HCENTER))
        {
            destX = xTo - w / 2;
        }

        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int x1 = xFrom;
                final int y1 = yFrom;
                final int width = w;
                final int height = h;
                final int x2 = destX;
                final int y2 = destY;

                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.copyArea(x1, y1, width, height, x2, y2);
                    }
                });
            }
            else
            {
                gc.copyArea(xFrom, yFrom, w, h, destX, destY);
            }
        }
    }

    /**
     * Renders a portion of source image with possible transforms.
     *
     * @param srcImage - source Image
     * @param xSrc - X-coordinate of the top-left corner of the rectangle in
     *            source image.
     * @param ySrc - Y-coordinate of the top-left corner of the rectangle in
     *            source image.
     * @param width - width of the rectangle in source image.
     * @param height - height of the rectangle in source image.
     * @param transform - transform to apply to the image before rendering.
     * @param xDst - X-coordinate of the anchor point in destination.
     * @param yDst - Y-coordinate of the anchor point in destination.
     * @param anch - anchor point definition.
     */
    public void drawRegion(javax.microedition.lcdui.Image srcImage,
                           int xSrc,
                           int ySrc,
                           int width,
                           int height,
                           int transform,
                           int xDst,
                           int yDst,
                           int anch)
    {

        if(srcImage == null)
        {
            throw new NullPointerException(
                MsgRepository.IMAGE_EXCEPTION_IS_NULL);
        }
        if(srcImage == parentImage)
        {
            throw new IllegalArgumentException(
                MsgRepository.GRAPHICS_EXCEPTION_SAME_SOURCE_AND_DESTINATION);
        }
        if(!javax.microedition.lcdui.Image.validateTransform(transform))
        {
            throw new IllegalArgumentException(
                MsgRepository.IMAGE_EXCEPTION_INVALID_TRANSFORM);
        }
        if(!checkImageAnchors(anch))
        {
            throw new IllegalArgumentException(
                MsgRepository.GRAPHICS_EXCEPTION_INVALID_ANCHOR);
        }
        if(!javax.microedition.lcdui.Image.validateRegion(srcImage.getWidth(),
                srcImage.getHeight(), xSrc, ySrc, width, height))
        {
            throw new IllegalArgumentException(
                MsgRepository.IMAGE_EXCEPTION_INVALID_REGION);
        }

        // Arrange vertical alignments
        int y = yDst;
        if(isFlag(anch, Graphics.VCENTER))
        {
            y = yDst - srcImage.getHeight() / 2;
        }
        if(isFlag(anch, Graphics.BOTTOM))
        {
            y = yDst - srcImage.getHeight();
        }

        // Arrange horizontal alignments
        int x = xDst;
        if(isFlag(anch, Graphics.HCENTER))
        {
            x = xDst - srcImage.getWidth() / 2;
        }
        if(isFlag(anch, Graphics.RIGHT))
        {
            x = xDst - srcImage.getWidth();
        }

        final int gcTransform = Image.getCgTransformValue(transform);
        synchronized(flushLock)
        {
            if(!buffered)
            {
                final int localXDst = x;
                final int localYDst = y;
                final int localW = width;
                final int localH = height;
                final int localXSrc = xSrc;
                final int localYSrc = ySrc;
                final org.eclipse.swt.internal.qt.graphics.Image localImage =
                    Internal_GfxPackageSupport.getImage(Image.getESWTImage(srcImage));
                ESWTUIThreadRunner.safeSyncExec(new Runnable()
                {
                    public void run()
                    {
                        gc.drawImage(localImage, localXDst, localYDst, localW, localH, localXSrc, localYSrc, localW, localH, gcTransform);
                    }
                });
            }
            else
            {
                gc.drawImage(Internal_GfxPackageSupport.getImage(Image.getESWTImage(srcImage)),
                             x, y, width, height, xSrc, ySrc, width, height, gcTransform);
            }
        }
    }

    /**
     * Return DirectGraphics associated with this instance.
     */
    DirectGraphics getDirectGraphics()
    {
        if(directGraphics == null)
        {
            directGraphics = new DirectGraphicsImpl(this);
        }
        return directGraphics;
    }

    /**
     * Return native graphic context.
     */
    GraphicsContext getGc()
    {
        return gc;
    }

}