javauis/lcdui_qt/src/javax/microedition/lcdui/Graphics.java
changeset 21 2a9601315dfc
child 23 98ccebc37403
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_qt/src/javax/microedition/lcdui/Graphics.java	Mon May 03 12:27:20 2010 +0300
@@ -0,0 +1,1447 @@
+/*
+* 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;
+    }
+
+}