diff dwt/graphics/GC.d @ 0:380af2bdd8e5

Upload of whole dwt tree
author Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com>
date Sat, 09 Aug 2008 17:00:02 +0200
parents
children 649b8e223d5a
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwt/graphics/GC.d	Sat Aug 09 17:00:02 2008 +0200
@@ -0,0 +1,3424 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2007 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+module dwt.graphics.GC;
+
+import dwt.dwthelper.utils;
+
+import dwt.DWT;
+import dwt.DWTError;
+import dwt.DWTException;
+import dwt.internal.cocoa.NSAffineTransform;
+import dwt.internal.cocoa.NSAffineTransformStruct;
+import dwt.internal.cocoa.NSAttributedString;
+import dwt.internal.cocoa.NSBezierPath;
+import dwt.internal.cocoa.NSColor;
+import dwt.internal.cocoa.NSFont;
+import dwt.internal.cocoa.NSGradient;
+import dwt.internal.cocoa.NSGraphicsContext;
+import dwt.internal.cocoa.NSImage;
+import dwt.internal.cocoa.NSMutableDictionary;
+import dwt.internal.cocoa.NSPoint;
+import dwt.internal.cocoa.NSRect;
+import dwt.internal.cocoa.NSSize;
+import dwt.internal.cocoa.NSString;
+import dwt.internal.cocoa.OS;
+
+/**
+ * Class <code>GC</code> is where all of the drawing capabilities that are 
+ * supported by DWT are located. Instances are used to draw on either an 
+ * <code>Image</code>, a <code>Control</code>, or directly on a <code>Display</code>.
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd>
+ * </dl>
+ * 
+ * <p>
+ * The DWT drawing coordinate system is the two-dimensional space with the origin
+ * (0,0) at the top left corner of the drawing area and with (x,y) values increasing
+ * to the right and downward respectively.
+ * </p>
+ * 
+ * <p>
+ * Application code must explicitly invoke the <code>GC.dispose()</code> 
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required. This is <em>particularly</em>
+ * important on Windows95 and Windows98 where the operating system has a limited
+ * number of device contexts available.
+ * </p>
+ * 
+ * <p>
+ * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified.
+ * </p>
+ *
+ * @see dwt.events.PaintEvent
+ */
+public final class GC extends Resource {
+    /**
+     * the handle to the OS device context
+     * (Warning: This field is platform dependent)
+     * <p>
+     * <b>IMPORTANT:</b> This field is <em>not</em> part of the DWT
+     * public API. It is marked public only so that it can be shared
+     * within the packages provided by DWT. It is not available on all
+     * platforms and should never be accessed from application code.
+     * </p>
+     */
+    public NSGraphicsContext handle;
+    
+    Drawable drawable;
+    GCData data;
+
+    static final int TAB_COUNT = 32;
+
+    final static int FOREGROUND = 1 << 0;
+    final static int BACKGROUND = 1 << 1;
+    final static int FONT = 1 << 2;
+    final static int LINE_STYLE = 1 << 3;
+    final static int LINE_CAP = 1 << 4;
+    final static int LINE_JOIN = 1 << 5;
+    final static int LINE_WIDTH = 1 << 6;
+    final static int LINE_MITERLIMIT = 1 << 7;
+    final static int FOREGROUND_FILL = 1 << 8;
+    final static int DRAW_OFFSET = 1 << 9;
+    final static int CLIPPING = 1 << 10;
+    final static int TRANSFORM = 1 << 11;
+    final static int DRAW = CLIPPING | TRANSFORM | FOREGROUND | LINE_WIDTH | LINE_STYLE  | LINE_CAP  | LINE_JOIN | LINE_MITERLIMIT | DRAW_OFFSET;
+    final static int FILL = CLIPPING | TRANSFORM | BACKGROUND;
+
+    static final float[] LINE_DOT = new float[]{1, 1};
+    static final float[] LINE_DASH = new float[]{3, 1};
+    static final float[] LINE_DASHDOT = new float[]{3, 1, 1, 1};
+    static final float[] LINE_DASHDOTDOT = new float[]{3, 1, 1, 1, 1, 1};
+    static final float[] LINE_DOT_ZERO = new float[]{3, 3};
+    static final float[] LINE_DASH_ZERO = new float[]{18, 6};
+    static final float[] LINE_DASHDOT_ZERO = new float[]{9, 6, 3, 6};
+    static final float[] LINE_DASHDOTDOT_ZERO = new float[]{9, 3, 3, 3, 3, 3};
+
+GC() {
+}
+
+/**  
+ * Constructs a new instance of this class which has been
+ * configured to draw on the specified drawable. Sets the
+ * foreground color, background color and font in the GC
+ * to match those in the drawable.
+ * <p>
+ * You must dispose the graphics context when it is no longer required. 
+ * </p>
+ * @param drawable the drawable to draw on
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the drawable is null</li>
+ *    <li>ERROR_NULL_ARGUMENT - if there is no current device</li>
+ *    <li>ERROR_INVALID_ARGUMENT
+ *          - if the drawable is an image that is not a bitmap or an icon
+ *          - if the drawable is an image or printer that is already selected
+ *            into another graphics context</li>
+ * </ul>
+ * @exception DWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
+ * </ul>
+ */
+public GC(Drawable drawable) {
+    this(drawable, 0);
+}
+
+/**  
+ * Constructs a new instance of this class which has been
+ * configured to draw on the specified drawable. Sets the
+ * foreground color, background color and font in the GC
+ * to match those in the drawable.
+ * <p>
+ * You must dispose the graphics context when it is no longer required. 
+ * </p>
+ * 
+ * @param drawable the drawable to draw on
+ * @param style the style of GC to construct
+ * 
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the drawable is null</li>
+ *    <li>ERROR_NULL_ARGUMENT - if there is no current device</li>
+ *    <li>ERROR_INVALID_ARGUMENT
+ *          - if the drawable is an image that is not a bitmap or an icon
+ *          - if the drawable is an image or printer that is already selected
+ *            into another graphics context</li>
+ * </ul>
+ * @exception DWTError <ul>
+ *    <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
+ * </ul>
+ *  
+ * @since 2.1.2
+ */
+public GC(Drawable drawable, int style) {
+    if (drawable is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    GCData data = new GCData();
+    data.style = checkStyle(style);
+    int contextId = drawable.internal_new_GC(data);
+    Device device = data.device;
+    if (device is null) device = Device.getDevice();
+    if (device is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    this.device = data.device = device;
+    init(drawable, data, contextId);
+    init();
+}
+
+static int checkStyle (int style) {
+    if ((style & DWT.LEFT_TO_RIGHT) !is 0) style &= ~DWT.RIGHT_TO_LEFT;
+    return style & (DWT.LEFT_TO_RIGHT | DWT.RIGHT_TO_LEFT);
+}
+
+/**  
+ * Invokes platform specific functionality to allocate a new graphics context.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>GC</code>. It is marked public only so that it
+ * can be shared within the packages provided by DWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param drawable the Drawable for the receiver.
+ * @param data the data for the receiver.
+ *
+ * @return a new <code>GC</code>
+ *
+ * @private
+ */
+public static GC cocoa_new(Drawable drawable, GCData data) {
+    GC gc = new GC();
+    int context = drawable.internal_new_GC(data);
+    gc.device = data.device;
+    gc.init(drawable, data, context);
+    return gc;
+}
+
+/**  
+ * Invokes platform specific functionality to wrap a graphics context.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>GC</code>. It is marked public only so that it
+ * can be shared within the packages provided by DWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param context the Quartz context.
+ * @param data the data for the receiver.
+ *
+ * @return a new <code>GC</code>
+ */
+public static GC carbon_new(int context, GCData data) {
+    GC gc = new GC();
+    gc.device = data.device;
+    gc.init(null, data, context);
+    return gc;
+}
+
+void checkGC (int mask) {
+    if ((data.state & CLIPPING) is 0 || (data.state & TRANSFORM) is 0) {
+        handle.restoreGraphicsState();
+        handle.saveGraphicsState();
+        if (data.clipPath !is null) data.clipPath.addClip();
+        if (data.transform !is null) data.transform.concat();
+        mask &= ~(TRANSFORM | CLIPPING);
+        data.state |= TRANSFORM | CLIPPING;
+        data.state &= ~(BACKGROUND | FOREGROUND);
+    }
+
+    int state = data.state;
+    if ((state & mask) is mask) return;
+    state = (state ^ mask) & mask;  
+    data.state |= mask;
+    
+    if ((state & FOREGROUND) !is 0) {
+        Pattern pattern = data.foregroundPattern;
+        if (pattern !is null) {
+            if (pattern.color !is null) pattern.color.setStroke();
+        } else {
+            float[] color = data.foreground;
+            NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f).setStroke();
+        }
+    }
+    if ((state & FOREGROUND_FILL) !is 0) {
+        Pattern pattern = data.foregroundPattern;
+        if (pattern !is null) {
+            if (pattern.color !is null) pattern.color.setFill();
+        } else {
+            float[] color = data.foreground;
+            NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f).setFill();
+        }
+        data.state &= ~BACKGROUND;
+    }
+    if ((state & BACKGROUND) !is 0) {
+        Pattern pattern = data.backgroundPattern;
+        if (pattern !is null) {
+            if (pattern.color !is null) pattern.color.setFill();
+        } else {
+            float[] color = data.background;
+            NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f).setFill();
+        }
+        data.state &= ~FOREGROUND_FILL;
+    }
+    NSBezierPath path = data.path;
+    if ((state & LINE_WIDTH) !is 0) {
+        path.setLineWidth(data.lineWidth is 0 ?  1 : data.lineWidth);
+        switch (data.lineStyle) {
+            case DWT.LINE_DOT:
+            case DWT.LINE_DASH:
+            case DWT.LINE_DASHDOT:
+            case DWT.LINE_DASHDOTDOT:
+                state |= LINE_STYLE;
+        }
+    }
+    if ((state & LINE_STYLE) !is 0) {
+        float[] dashes = null;
+        float width = data.lineWidth;
+        switch (data.lineStyle) {
+            case DWT.LINE_SOLID: break;
+            case DWT.LINE_DASH: dashes = width !is 0 ? LINE_DASH : LINE_DASH_ZERO; break;
+            case DWT.LINE_DOT: dashes = width !is 0 ? LINE_DOT : LINE_DOT_ZERO; break;
+            case DWT.LINE_DASHDOT: dashes = width !is 0 ? LINE_DASHDOT : LINE_DASHDOT_ZERO; break;
+            case DWT.LINE_DASHDOTDOT: dashes = width !is 0 ? LINE_DASHDOTDOT : LINE_DASHDOTDOT_ZERO; break;
+            case DWT.LINE_CUSTOM: dashes = data.lineDashes; break;
+        }
+        if (dashes !is null) {
+            float[] lengths = new float[dashes.length];
+            for (int i = 0; i < lengths.length; i++) {
+                lengths[i] = width is 0 || data.lineStyle is DWT.LINE_CUSTOM ? dashes[i] : dashes[i] * width;
+            }
+            path.setLineDash(lengths, lengths.length, data.lineDashesOffset);
+        } else {
+            path.setLineDash(null, 0, 0);
+        }
+    }
+    if ((state & LINE_MITERLIMIT) !is 0) {
+        path.setMiterLimit(data.lineMiterLimit);
+    }
+    if ((state & LINE_JOIN) !is 0) {
+        int joinStyle = 0;
+        switch (data.lineJoin) {
+            case DWT.JOIN_MITER: joinStyle = OS.NSMiterLineJoinStyle; break;
+            case DWT.JOIN_ROUND: joinStyle = OS.NSRoundLineJoinStyle; break;
+            case DWT.JOIN_BEVEL: joinStyle = OS.NSBevelLineJoinStyle; break;
+        }
+        path.setLineJoinStyle(joinStyle);
+    }
+    if ((state & LINE_CAP) !is 0) {
+        int capStyle = 0;
+        switch (data.lineCap) {
+            case DWT.CAP_ROUND: capStyle = OS.NSRoundLineCapStyle; break;
+            case DWT.CAP_FLAT: capStyle = OS.NSButtLineCapStyle; break;
+            case DWT.CAP_SQUARE: capStyle = OS.NSSquareLineCapStyle; break;
+        }
+        path.setLineCapStyle(capStyle);
+    }
+    if ((state & DRAW_OFFSET) !is 0) {
+        data.drawXOffset = data.drawYOffset = 0;
+        NSSize size = new NSSize();
+        size.width = size.height = 1;
+        if (data.transform !is null) {
+            size = data.transform.transformSize(size);
+        }
+        float scaling = size.width;
+        if (scaling < 0) scaling = -scaling;
+        float strokeWidth = data.lineWidth * scaling;
+        if (strokeWidth is 0 || ((int)strokeWidth % 2) is 1) {
+            data.drawXOffset = 0.5f / scaling;
+        }
+        scaling = size.height;
+        if (scaling < 0) scaling = -scaling;
+        strokeWidth = data.lineWidth * scaling;
+        if (strokeWidth is 0 || ((int)strokeWidth % 2) is 1) {
+            data.drawYOffset = 0.5f / scaling;
+        }
+    }
+}
+
+/**
+ * Copies a rectangular area of the receiver at the specified
+ * position into the image, which must be of type <code>DWT.BITMAP</code>.
+ *
+ * @param image the image to copy into
+ * @param x the x coordinate in the receiver of the area to be copied
+ * @param y the y coordinate in the receiver of the area to be copied
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the image is not a bitmap or has been disposed</li> 
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void copyArea(Image image, int x, int y) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (image is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (image.type !is DWT.BITMAP || image.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+//  if (data.image !is null) {
+//      copyArea(image, x, y, data.image.handle);
+//  } else if (data.control !is 0) {
+//      int imageHandle = image.handle;
+//      int width = OS.CGImageGetWidth(imageHandle);
+//      int height = OS.CGImageGetHeight(imageHandle);
+//      int window = OS.GetControlOwner(data.control);
+//      Rect srcRect = new Rect ();
+//      CGPoint pt = new CGPoint ();
+//      int[] contentView = new int[1];
+//      OS.HIViewFindByID(OS.HIViewGetRoot(window), OS.kHIViewWindowContentID(), contentView);
+//      OS.HIViewConvertPoint (pt, data.control, contentView[0]);
+//      x += (int) pt.x;
+//      y += (int) pt.y;
+//      Rect inset = data.insetRect;
+//      x -= inset.left;
+//      y -= inset.top;
+//      srcRect.left = (short)x;
+//      srcRect.top = (short)y;
+//      srcRect.right = (short)(x + width);
+//      srcRect.bottom = (short)(y + height);
+//      Rect destRect = new Rect();
+//      destRect.right = (short)width;
+//      destRect.bottom = (short)height;
+//      int bpl = width * 4;
+//      int[] gWorld = new int[1];
+//      int port = OS.GetWindowPort(window);        
+//      OS.NewGWorldFromPtr(gWorld, OS.k32ARGBPixelFormat, destRect, 0, 0, 0, image.data, bpl);
+//      OS.CopyBits(OS.GetPortBitMapForCopyBits(port), OS.GetPortBitMapForCopyBits(gWorld[0]), srcRect, destRect, (short)OS.srcCopy, 0);            
+//      OS.DisposeGWorld(gWorld [0]);
+//  } else if (data.window !is 0) {
+//      int imageHandle = image.handle;
+//      CGRect rect = new CGRect();
+//      rect.x = x;
+//      rect.y = y;
+//      rect.width = OS.CGImageGetWidth(imageHandle);
+//      rect.height = OS.CGImageGetHeight(imageHandle);
+//      int[] displays = new int[16];
+//      int[] count = new int[1];
+//      if (OS.CGGetDisplaysWithRect(rect, displays.length, displays, count) !is 0) return;
+//      for (int i = 0; i < count[0]; i++) {
+//          int display = displays[i];
+//          int address = OS.CGDisplayBaseAddress(display);
+//          if (address !is 0) {
+//              int width = OS.CGDisplayPixelsWide(display);
+//              int height = OS.CGDisplayPixelsHigh(display);
+//              int bpr = OS.CGDisplayBytesPerRow(display);
+//              int bpp = OS.CGDisplayBitsPerPixel(display);
+//              int bps = OS.CGDisplayBitsPerSample(display);
+//              int bitmapInfo = OS.kCGImageAlphaNoneSkipFirst;
+//              switch (bpp) {
+//                  case 16: bitmapInfo |= OS.kCGBitmapByteOrder16Host; break;
+//                  case 32: bitmapInfo |= OS.kCGBitmapByteOrder32Host; break;
+//              }
+//              int srcImage = 0;
+//              if (OS.__BIG_ENDIAN__() && OS.VERSION >= 0x1040) {
+//                  int context = OS.CGBitmapContextCreate(address, width, height, bps, bpr, data.device.colorspace, bitmapInfo);
+//                  srcImage = OS.CGBitmapContextCreateImage(context);
+//                  OS.CGContextRelease(context);
+//              } else {
+//                  int provider = OS.CGDataProviderCreateWithData(0, address, bpr * height, 0);
+//                  srcImage = OS.CGImageCreate(width, height, bps, bpp, bpr, data.device.colorspace, bitmapInfo, provider, null, true, 0);
+//                  OS.CGDataProviderRelease(provider);
+//              }
+//              copyArea(image, x, y, srcImage);
+//              if (srcImage !is 0) OS.CGImageRelease(srcImage);
+//          }
+//      }
+//  }   
+}
+
+void copyArea (Image image, int x, int y, int srcImage) {
+    if (srcImage is 0) return;
+//  int imageHandle = image.handle;
+//  int bpc = OS.CGImageGetBitsPerComponent(imageHandle);
+//  int width = OS.CGImageGetWidth(imageHandle);
+//  int height = OS.CGImageGetHeight(imageHandle);
+//  int bpr = OS.CGImageGetBytesPerRow(imageHandle);
+//  int alphaInfo = OS.CGImageGetAlphaInfo(imageHandle);
+//  int context = OS.CGBitmapContextCreate(image.data, width, height, bpc, bpr, data.device.colorspace, alphaInfo);
+//  if (context !is 0) {
+//      CGRect rect = new CGRect();
+//      rect.x = -x;
+//      rect.y = y;
+//      rect.width = OS.CGImageGetWidth(srcImage);
+//      rect.height = OS.CGImageGetHeight(srcImage);
+//      OS.CGContextTranslateCTM(context, 0, -(rect.height - height));
+//      OS.CGContextDrawImage(context, rect, srcImage);
+//      OS.CGContextRelease(context);
+//  }
+}
+
+/**
+ * Copies a rectangular area of the receiver at the source
+ * position onto the receiver at the destination position.
+ *
+ * @param srcX the x coordinate in the receiver of the area to be copied
+ * @param srcY the y coordinate in the receiver of the area to be copied
+ * @param width the width of the area to copy
+ * @param height the height of the area to copy
+ * @param destX the x coordinate in the receiver of the area to copy to
+ * @param destY the y coordinate in the receiver of the area to copy to
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY) {
+    copyArea(srcX, srcY, width, height, destX, destY, true);
+}
+/**
+ * Copies a rectangular area of the receiver at the source
+ * position onto the receiver at the destination position.
+ *
+ * @param srcX the x coordinate in the receiver of the area to be copied
+ * @param srcY the y coordinate in the receiver of the area to be copied
+ * @param width the width of the area to copy
+ * @param height the height of the area to copy
+ * @param destX the x coordinate in the receiver of the area to copy to
+ * @param destY the y coordinate in the receiver of the area to copy to
+ * @param paint if <code>true</code> paint events will be generated for old and obscured areas
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1 
+ */
+public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY, bool paint) {
+//  if (handle is 0) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+//  if (data.updateClip) setCGClipping();
+//  if (width <= 0 || height <= 0) return;
+//  int deltaX = destX - srcX, deltaY = destY - srcY;
+//  if (deltaX is 0 && deltaY is 0) return;
+//  if (data.image !is null) {
+//      OS.CGContextSaveGState(handle);
+//      OS.CGContextScaleCTM(handle, 1, -1);
+//      OS.CGContextTranslateCTM(handle, 0, -(height + 2 * destY));
+//      CGRect rect = new CGRect();
+//      rect.x = destX;
+//      rect.y = destY;
+//      rect.width = width;
+//      rect.height = height;
+//      int h = OS.CGImageGetHeight(data.image.handle);
+//      int bpr = OS.CGImageGetBytesPerRow(data.image.handle);
+//      int provider = OS.CGDataProviderCreateWithData(0, data.image.data, bpr * h, 0);
+//      if (provider !is 0) {
+//          int colorspace = device.colorspace;
+//          int img = OS.CGImageCreate(width, height, 8, 32, bpr, colorspace, OS.kCGImageAlphaNoneSkipFirst, provider, null, true, 0);
+//          OS.CGDataProviderRelease(provider);
+//          OS.CGContextDrawImage(handle, rect, img);
+//          OS.CGImageRelease(img);
+//      }
+//      OS.CGContextRestoreGState(handle);
+//      return;
+//  }
+//  if (data.control !is 0) {
+//      int port = data.port;
+//      int window = OS.GetControlOwner(data.control);
+//      if (port is 0) port = OS.GetWindowPort(window);
+//
+//      /* Calculate src and dest rectangles/regions */
+//      Rect rect = new Rect();
+//      OS.GetControlBounds(data.control, rect);
+//      int convertX = 0, convertY = 0;
+//      CGPoint pt = new CGPoint ();
+//      int[] contentView = new int[1];
+//      OS.HIViewFindByID(OS.HIViewGetRoot(window), OS.kHIViewWindowContentID(), contentView);
+//      OS.HIViewConvertPoint(pt, OS.HIViewGetSuperview(data.control), contentView[0]);
+//      convertX = rect.left + (int) pt.x;
+//      convertY = rect.top + (int) pt.y;
+//      rect.left += (int) pt.x;
+//      rect.top += (int) pt.y;
+//      rect.right += (int) pt.x;
+//      rect.bottom += (int) pt.y;
+//      Rect srcRect = new Rect();
+//      int left = rect.left + srcX;
+//      int top = rect.top + srcY;
+//      OS.SetRect(srcRect, (short)left, (short)top, (short)(left + width), (short)(top + height));
+//      int srcRgn = OS.NewRgn();
+//      OS.RectRgn(srcRgn, srcRect);
+//      OS.SectRect(rect, srcRect, srcRect);
+//      Rect destRect = new Rect ();
+//      OS.SetRect(destRect, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom);
+//      OS.OffsetRect(destRect, (short)deltaX, (short)deltaY);
+//      int destRgn = OS.NewRgn();
+//      OS.RectRgn(destRgn, destRect);
+//      
+//      /* Copy bits with appropriated clipping region */
+//      if (!OS.EmptyRect(srcRect)) {
+//          if (data.visibleRgn is 0 || OS.RectInRgn(srcRect, data.visibleRgn)) {
+//              int clipRgn = data.visibleRgn;
+//              if (data.clipRgn !is 0) {
+//                  clipRgn = OS.NewRgn();
+//                  OS.SectRgn(data.clipRgn, data.visibleRgn, clipRgn);
+//              }
+//  
+//              /*
+//              * Feature in the Macintosh.  ScrollRect() only copies bits
+//              * that are inside the specified rectangle.  This means that
+//              * it is not possible to copy non overlaping bits without
+//              * copying the bits in between the source and destination
+//              * rectangles.  The fix is to check if the source and
+//              * destination rectangles are disjoint and use CopyBits()
+//              * instead.
+//              */
+//              if (!OS.EmptyRgn(clipRgn)) {
+//                  bool disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY);
+//                  if (!disjoint && (deltaX is 0 || deltaY is 0)) {
+//                      int[] currentPort = new int[1];
+//                      OS.GetPort(currentPort);
+//                      OS.SetPort(port);
+//                      int oldClip = OS.NewRgn();
+//                      OS.GetClip(oldClip);
+//                      OS.SetClip(clipRgn);
+//                      OS.UnionRect(srcRect, destRect, rect);
+//                      OS.ScrollRect(rect, (short)deltaX, (short)deltaY, 0);
+//                      OS.SetClip(oldClip);
+//                      OS.DisposeRgn(oldClip);
+//                      OS.SetPort(currentPort[0]);
+//                  } else {
+//                      int portBitMap = OS.GetPortBitMapForCopyBits (port);
+//                      OS.CopyBits(portBitMap, portBitMap, srcRect, destRect, (short)OS.srcCopy, clipRgn);
+//                      OS.QDFlushPortBuffer(port, destRgn);
+//                  }
+//              }
+//              
+//              if (clipRgn !is data.visibleRgn) OS.DisposeRgn(clipRgn);
+//          }
+//      }
+//      
+//      /* Invalidate src and obscured areas */
+//      if (paint) {
+//          int invalRgn = OS.NewRgn();
+//          OS.DiffRgn(srcRgn, data.visibleRgn, invalRgn);
+//          OS.OffsetRgn(invalRgn, (short)deltaX, (short)deltaY);
+//          OS.DiffRgn(srcRgn, destRgn, srcRgn);
+//          OS.UnionRgn(srcRgn, invalRgn, invalRgn);
+//          OS.SectRgn(data.visibleRgn, invalRgn, invalRgn);
+//          OS.OffsetRgn(invalRgn, (short)-convertX, (short)-convertY);
+//          OS.HIViewSetNeedsDisplayInRegion(data.control, invalRgn, true);
+//          OS.DisposeRgn(invalRgn);
+//      }
+//      
+//      /* Dispose src and dest regions */
+//      OS.DisposeRgn(destRgn);
+//      OS.DisposeRgn(srcRgn);
+//  }
+}
+
+NSAttributedString createString(String string, int flags) {
+    NSMutableDictionary dict = NSMutableDictionary.dictionaryWithCapacity(4);
+    float[] foreground = data.foreground;
+    NSColor color = NSColor.colorWithDeviceRed(foreground[0], foreground[1], foreground[2], data.alpha / 255f);
+    dict.setObject(color, OS.NSForegroundColorAttributeName());
+    dict.setObject(data.font.handle, OS.NSFontAttributeName());
+    if ((flags & DWT.DRAW_TRANSPARENT) is 0) {
+        float[] background = data.background;
+        color = NSColor.colorWithDeviceRed(background[0], background[1], background[2], data.alpha / 255f);
+        dict.setObject(color, OS.NSBackgroundColorAttributeName());
+    }
+    int length = string.length();
+    char[] chars = new char[length];
+    string.getChars(0, length, chars, 0);
+//  int breakCount = 0;
+//  int[] breaks = null;
+//  if ((flags & (DWT.DRAW_MNEMONIC | DWT.DRAW_DELIMITER)) !is 0) {
+//      int i=0, j=0;
+//      while (i < chars.length) {
+//          char c = chars [j++] = chars [i++];
+//          switch (c) {
+//              case '&': {
+//                  if ((flags & DWT.DRAW_MNEMONIC) !is 0) {
+//                      if (i is chars.length) {continue;}
+//                      if (chars [i] is '&') {i++; continue;}
+//                      j--;
+//                  }
+//                  break;
+//              }
+//              case '\r':
+//              case '\n': {
+//                  if ((flags & DWT.DRAW_DELIMITER) !is 0) {
+//                      if (c is '\r' && i !is chars.length && chars[i] is '\n') i++;
+//                      j--;
+//                      if (breaks is null) {
+//                          breaks = new int[4];
+//                      } else if (breakCount is breaks.length) {
+//                          int[] newBreaks = new int[breaks.length + 4];
+//                          System.arraycopy(breaks, 0, newBreaks, 0, breaks.length);
+//                          breaks = newBreaks;
+//                      }
+//                      breaks[breakCount++] = j;
+//                  }
+//                  break;
+//              }
+//          }
+//      }
+//      length = j;
+//  }
+    NSString str = NSString.stringWithCharacters(chars, length);
+    return ((NSAttributedString)new NSAttributedString().alloc()).initWithString_attributes_(str, dict);
+}
+
+void destroy() {
+    /* Free resources */
+    Image image = data.image;
+    if (image !is null) {
+        image.memGC = null;
+        image.createAlpha();
+    }
+    if (data.clipPath !is null) data.clipPath.release();
+    if (data.transform !is null) data.transform.release();
+    if (data.inverseTransform !is null) data.inverseTransform.release();
+    data.path = data.clipPath = null;
+    data.transform = data.inverseTransform = null;
+    
+    /* Dispose the GC */
+    if (drawable !is null) drawable.internal_dispose_GC(handle.id, data);
+    handle.restoreGraphicsState();
+    handle.release();
+
+    drawable = null;
+    data.image = null;
+    data = null;
+    handle = null;
+}
+
+/**
+ * Draws the outline of a circular or elliptical arc 
+ * within the specified rectangular area.
+ * <p>
+ * The resulting arc begins at <code>startAngle</code> and extends  
+ * for <code>arcAngle</code> degrees, using the current color.
+ * Angles are interpreted such that 0 degrees is at the 3 o'clock
+ * position. A positive value indicates a counter-clockwise rotation
+ * while a negative value indicates a clockwise rotation.
+ * </p><p>
+ * The center of the arc is the center of the rectangle whose origin 
+ * is (<code>x</code>, <code>y</code>) and whose size is specified by the 
+ * <code>width</code> and <code>height</code> arguments. 
+ * </p><p>
+ * The resulting arc covers an area <code>width + 1</code> pixels wide
+ * by <code>height + 1</code> pixels tall.
+ * </p>
+ *
+ * @param x the x coordinate of the upper-left corner of the arc to be drawn
+ * @param y the y coordinate of the upper-left corner of the arc to be drawn
+ * @param width the width of the arc to be drawn
+ * @param height the height of the arc to be drawn
+ * @param startAngle the beginning angle
+ * @param arcAngle the angular extent of the arc, relative to the start angle
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(DRAW);
+    if (width < 0) {
+        x = x + width;
+        width = -width;
+    }
+    if (height < 0) {
+        y = y + height;
+        height = -height;
+    }
+    if (width is 0 || height is 0 || arcAngle is 0) return;
+    handle.saveGraphicsState();
+    NSAffineTransform transform = NSAffineTransform.transform();
+    float xOffset = data.drawXOffset, yOffset = data.drawYOffset;
+    transform.translateXBy(x + xOffset + width / 2f, y + yOffset + height / 2f);
+    transform.scaleXBy(width / 2f, height / 2f);
+    NSBezierPath path = data.path;
+    NSPoint center = new NSPoint();
+    float sAngle = -startAngle;
+    float eAngle = -(startAngle + arcAngle);
+    path.appendBezierPathWithArcWithCenter_radius_startAngle_endAngle_clockwise_(center, 1, sAngle,  eAngle, arcAngle>0);
+    path.transformUsingAffineTransform(transform);
+    path.stroke();
+    path.removeAllPoints();
+    handle.restoreGraphicsState();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Draws a rectangle, based on the specified arguments, which has
+ * the appearance of the platform's <em>focus rectangle</em> if the
+ * platform supports such a notion, and otherwise draws a simple
+ * rectangle in the receiver's foreground color.
+ *
+ * @param x the x coordinate of the rectangle
+ * @param y the y coordinate of the rectangle
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void drawFocus(int x, int y, int width, int height) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(CLIPPING | TRANSFORM);
+//  int[] metric = new int[1];
+//  OS.GetThemeMetric(OS.kThemeMetricFocusRectOutset, metric);
+//  CGRect rect = new CGRect ();
+//  rect.x = x + metric[0];
+//  rect.y = y + metric[0];
+//  rect.width = width - metric[0] * 2;
+//  rect.height = height - metric[0] * 2;
+//  OS.HIThemeDrawFocusRect(rect, true, handle, OS.kHIThemeOrientationNormal);
+//  flush();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/**
+ * Draws the given image in the receiver at the specified
+ * coordinates.
+ *
+ * @param image the image to draw
+ * @param x the x coordinate of where to draw
+ * @param y the y coordinate of where to draw
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the given coordinates are outside the bounds of the image</li>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception DWTError <ul>
+ *    <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li>
+ * </ul>
+ */
+public void drawImage(Image image, int x, int y) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (image is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (image.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    drawImage(image, 0, 0, -1, -1, x, y, -1, -1, true);
+}
+
+/**
+ * Copies a rectangular area from the source image into a (potentially
+ * different sized) rectangular area in the receiver. If the source
+ * and destination areas are of differing sizes, then the source
+ * area will be stretched or shrunk to fit the destination area
+ * as it is copied. The copy fails if any part of the source rectangle
+ * lies outside the bounds of the source image, or if any of the width
+ * or height arguments are negative.
+ *
+ * @param image the source image
+ * @param srcX the x coordinate in the source image to copy from
+ * @param srcY the y coordinate in the source image to copy from
+ * @param srcWidth the width in pixels to copy from the source
+ * @param srcHeight the height in pixels to copy from the source
+ * @param destX the x coordinate in the destination to copy to
+ * @param destY the y coordinate in the destination to copy to
+ * @param destWidth the width in pixels of the destination rectangle
+ * @param destHeight the height in pixels of the destination rectangle
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if any of the width or height arguments are negative.
+ *    <li>ERROR_INVALID_ARGUMENT - if the source rectangle is not contained within the bounds of the source image</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception DWTError <ul>
+ *    <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li>
+ * </ul>
+ */
+public void drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (srcWidth is 0 || srcHeight is 0 || destWidth is 0 || destHeight is 0) return;
+    if (srcX < 0 || srcY < 0 || srcWidth < 0 || srcHeight < 0 || destWidth < 0 || destHeight < 0) {
+        DWT.error (DWT.ERROR_INVALID_ARGUMENT);
+    }
+    if (image is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (image.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    drawImage(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, false);
+}
+
+void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, bool simple) {
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(CLIPPING | TRANSFORM);
+    NSImage imageHandle = srcImage.handle;
+    NSSize size = imageHandle.size();
+    int imgWidth = (int)size.width;
+    int imgHeight = (int)size.height;
+    if (simple) {
+        srcWidth = destWidth = imgWidth;
+        srcHeight = destHeight = imgHeight;
+    } else {
+        simple = srcX is 0 && srcY is 0 &&
+            srcWidth is destWidth && destWidth is imgWidth &&
+            srcHeight is destHeight && destHeight is imgHeight;
+        if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) {
+            NSGraphicsContext.setCurrentContext(context);
+            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+        }
+    }
+    if (srcImage.memGC !is null) srcImage.createAlpha();
+    handle.saveGraphicsState();
+    NSAffineTransform transform = NSAffineTransform.transform();
+    transform.scaleXBy(1, -1);
+    transform.translateXBy(0, -(destHeight + 2 * destY));
+    transform.concat();
+    NSRect srcRect = new NSRect();
+    srcRect.x = srcX;
+    srcRect.y = srcY;
+    srcRect.width = srcWidth;
+    srcRect.height = srcHeight;
+    NSRect destRect = new NSRect();
+    destRect.x = destX;
+    destRect.y = destY;
+    destRect.width = destWidth;
+    destRect.height = destHeight;
+    imageHandle.drawInRect(destRect, srcRect, OS.NSCompositeSourceOver, 1);
+    handle.restoreGraphicsState();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Draws a line, using the foreground color, between the points 
+ * (<code>x1</code>, <code>y1</code>) and (<code>x2</code>, <code>y2</code>).
+ *
+ * @param x1 the first point's x coordinate
+ * @param y1 the first point's y coordinate
+ * @param x2 the second point's x coordinate
+ * @param y2 the second point's y coordinate
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawLine(int x1, int y1, int x2, int y2) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(DRAW);
+    NSBezierPath path = data.path;
+    NSPoint pt = new NSPoint();
+    pt.x = x1 + data.drawXOffset;
+    pt.y = y1 + data.drawYOffset;
+    path.moveToPoint(pt);
+    pt.x = x2 + data.drawXOffset;
+    pt.y = y2 + data.drawYOffset;
+    path.lineToPoint(pt);
+    path.stroke();
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Draws the outline of an oval, using the foreground color,
+ * within the specified rectangular area.
+ * <p>
+ * The result is a circle or ellipse that fits within the 
+ * rectangle specified by the <code>x</code>, <code>y</code>, 
+ * <code>width</code>, and <code>height</code> arguments. 
+ * </p><p> 
+ * The oval covers an area that is <code>width + 1</code> 
+ * pixels wide and <code>height + 1</code> pixels tall.
+ * </p>
+ *
+ * @param x the x coordinate of the upper left corner of the oval to be drawn
+ * @param y the y coordinate of the upper left corner of the oval to be drawn
+ * @param width the width of the oval to be drawn
+ * @param height the height of the oval to be drawn
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawOval(int x, int y, int width, int height) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(DRAW);
+    if (width < 0) {
+        x = x + width;
+        width = -width;
+    }
+    if (height < 0) {
+        y = y + height;
+        height = -height;
+    }
+    NSBezierPath path = data.path;
+    NSRect rect = new NSRect();
+    rect.x = x + data.drawXOffset;
+    rect.y = y + data.drawXOffset;
+    rect.width = width;
+    rect.height = height;
+    path.appendBezierPathWithOvalInRect(rect);
+    path.stroke();
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Draws the path described by the parameter.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * 
+ * @param path the path to draw
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see Path
+ * 
+ * @since 3.1
+ */
+public void drawPath(Path path) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (path is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (path.handle is null) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(DRAW);
+    handle.saveGraphicsState();
+    NSAffineTransform transform = NSAffineTransform.transform();
+    transform.translateXBy(data.drawXOffset, data.drawYOffset);
+    transform.concat();
+    NSBezierPath drawPath = data.path;
+    drawPath.appendBezierPath(path.handle);
+    drawPath.stroke();
+    drawPath.removeAllPoints();
+    handle.restoreGraphicsState();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Draws a pixel, using the foreground color, at the specified
+ * point (<code>x</code>, <code>y</code>).
+ * <p>
+ * Note that the receiver's line attributes do not affect this
+ * operation.
+ * </p>
+ *
+ * @param x the point's x coordinate
+ * @param y the point's y coordinate
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *  
+ * @since 3.0
+ */
+public void drawPoint(int x, int y) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(FOREGROUND_FILL);
+    NSRect rect = new NSRect();
+    rect.x = x;
+    rect.y = y;
+    rect.width = 1;
+    rect.height = 1;
+    NSBezierPath path = data.path;
+    path.appendBezierPathWithRect(rect);
+    path.fill();
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Draws the closed polygon which is defined by the specified array
+ * of integer coordinates, using the receiver's foreground color. The array 
+ * contains alternating x and y values which are considered to represent
+ * points which are the vertices of the polygon. Lines are drawn between
+ * each consecutive pair, and between the first pair and last pair in the
+ * array.
+ *
+ * @param pointArray an array of alternating x and y values which are the vertices of the polygon
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT if pointArray is null</li>
+ * </ul>    
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawPolygon(int[] pointArray) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (pointArray is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(DRAW);
+    if (pointArray.length < 4) return;
+    float xOffset = data.drawXOffset, yOffset = data.drawYOffset;
+    NSBezierPath path = data.path;
+    NSPoint pt = new NSPoint();
+    pt.x = pointArray[0] + xOffset;
+    pt.y = pointArray[1] + yOffset;
+    path.moveToPoint(pt);
+    int end = pointArray.length / 2 * 2;
+    for (int i = 2; i < end; i+=2) {
+        pt.x = pointArray[i] + xOffset;
+        pt.y = pointArray[i+1] + yOffset;
+        path.lineToPoint(pt);
+    }
+    path.closePath();
+    path.stroke();
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Draws the polyline which is defined by the specified array
+ * of integer coordinates, using the receiver's foreground color. The array 
+ * contains alternating x and y values which are considered to represent
+ * points which are the corners of the polyline. Lines are drawn between
+ * each consecutive pair, but not between the first pair and last pair in
+ * the array.
+ *
+ * @param pointArray an array of alternating x and y values which are the corners of the polyline
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the point array is null</li>
+ * </ul>    
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawPolyline(int[] pointArray) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (pointArray is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(DRAW);
+    if (pointArray.length < 4) return;
+    float xOffset = data.drawXOffset, yOffset = data.drawYOffset;
+    NSBezierPath path = data.path;
+    NSPoint pt = new NSPoint();
+    pt.x = pointArray[0] + xOffset;
+    pt.y = pointArray[1] + yOffset;
+    path.moveToPoint(pt);
+    int end = pointArray.length / 2 * 2;
+    for (int i = 2; i < end; i+=2) {
+        pt.x = pointArray[i] + xOffset;
+        pt.y = pointArray[i+1] + yOffset;
+        path.lineToPoint(pt);
+    }
+    path.stroke();
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Draws the outline of the rectangle specified by the arguments,
+ * using the receiver's foreground color. The left and right edges
+ * of the rectangle are at <code>x</code> and <code>x + width</code>. 
+ * The top and bottom edges are at <code>y</code> and <code>y + height</code>. 
+ *
+ * @param x the x coordinate of the rectangle to be drawn
+ * @param y the y coordinate of the rectangle to be drawn
+ * @param width the width of the rectangle to be drawn
+ * @param height the height of the rectangle to be drawn
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawRectangle(int x, int y, int width, int height) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(DRAW);
+    if (width < 0) {
+        x = x + width;
+        width = -width;
+    }
+    if (height < 0) {
+        y = y + height;
+        height = -height;
+    }
+    NSRect rect = new NSRect();
+    rect.x = x + data.drawXOffset;
+    rect.y = y + data.drawYOffset;
+    rect.width = width;
+    rect.height = height;
+    NSBezierPath path = data.path;
+    path.appendBezierPathWithRect(rect);
+    path.stroke();
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Draws the outline of the specified rectangle, using the receiver's
+ * foreground color. The left and right edges of the rectangle are at
+ * <code>rect.x</code> and <code>rect.x + rect.width</code>. The top 
+ * and bottom edges are at <code>rect.y</code> and 
+ * <code>rect.y + rect.height</code>. 
+ *
+ * @param rect the rectangle to draw
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
+ * </ul>    
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawRectangle(Rectangle rect) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (rect is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    drawRectangle (rect.x, rect.y, rect.width, rect.height);
+}
+
+/** 
+ * Draws the outline of the round-cornered rectangle specified by 
+ * the arguments, using the receiver's foreground color. The left and
+ * right edges of the rectangle are at <code>x</code> and <code>x + width</code>. 
+ * The top and bottom edges are at <code>y</code> and <code>y + height</code>.
+ * The <em>roundness</em> of the corners is specified by the 
+ * <code>arcWidth</code> and <code>arcHeight</code> arguments, which
+ * are respectively the width and height of the ellipse used to draw
+ * the corners.
+ *
+ * @param x the x coordinate of the rectangle to be drawn
+ * @param y the y coordinate of the rectangle to be drawn
+ * @param width the width of the rectangle to be drawn
+ * @param height the height of the rectangle to be drawn
+ * @param arcWidth the width of the arc
+ * @param arcHeight the height of the arc
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawRoundRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(DRAW);
+    if (arcWidth is 0 || arcHeight is 0) {
+        drawRectangle(x, y, width, height);
+        NSGraphicsContext.setCurrentContext(context);
+        return;
+    }
+    NSBezierPath path = data.path;
+    NSRect rect = new NSRect();
+    rect.x = x + data.drawXOffset;
+    rect.y = y + data.drawYOffset;
+    rect.width = width;
+    rect.height = height;
+    path.appendBezierPathWithRoundedRect(rect, arcWidth, arcHeight);
+    path.stroke();
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Draws the given string, using the receiver's current font and
+ * foreground color. No tab expansion or carriage return processing
+ * will be performed. The background of the rectangular area where
+ * the string is being drawn will be filled with the receiver's
+ * background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>    
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawString (String string, int x, int y) {
+    drawString(string, x, y, false);
+}
+
+/** 
+ * Draws the given string, using the receiver's current font and
+ * foreground color. No tab expansion or carriage return processing
+ * will be performed. If <code>isTransparent</code> is <code>true</code>,
+ * then the background of the rectangular area where the string is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn
+ * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>    
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawString(String string, int x, int y, bool isTransparent) {
+    drawText(string, x, y, isTransparent ? DWT.DRAW_TRANSPARENT : 0);
+}
+
+/** 
+ * Draws the given string, using the receiver's current font and
+ * foreground color. Tab expansion and carriage return processing
+ * are performed. The background of the rectangular area where
+ * the text is being drawn will be filled with the receiver's
+ * background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>    
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawText(String string, int x, int y) {
+    drawText(string, x, y, DWT.DRAW_DELIMITER | DWT.DRAW_TAB);
+}
+
+/** 
+ * Draws the given string, using the receiver's current font and
+ * foreground color. Tab expansion and carriage return processing
+ * are performed. If <code>isTransparent</code> is <code>true</code>,
+ * then the background of the rectangular area where the text is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>    
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawText(String string, int x, int y, bool isTransparent) {
+    int flags = DWT.DRAW_DELIMITER | DWT.DRAW_TAB;
+    if (isTransparent) flags |= DWT.DRAW_TRANSPARENT;
+    drawText(string, x, y, flags);
+}
+
+/** 
+ * Draws the given string, using the receiver's current font and
+ * foreground color. Tab expansion, line delimiter and mnemonic
+ * processing are performed according to the specified flags. If
+ * <code>flags</code> includes <code>DRAW_TRANSPARENT</code>,
+ * then the background of the rectangular area where the text is being
+ * drawn will not be modified, otherwise it will be filled with the
+ * receiver's background color.
+ * <p>
+ * The parameter <code>flags</code> may be a combination of:
+ * <dl>
+ * <dt><b>DRAW_DELIMITER</b></dt>
+ * <dd>draw multiple lines</dd>
+ * <dt><b>DRAW_TAB</b></dt>
+ * <dd>expand tabs</dd>
+ * <dt><b>DRAW_MNEMONIC</b></dt>
+ * <dd>underline the mnemonic character</dd>
+ * <dt><b>DRAW_TRANSPARENT</b></dt>
+ * <dd>transparent background</dd>
+ * </dl>
+ * </p>
+ *
+ * @param string the string to be drawn
+ * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
+ * @param flags the flags specifying how to process the text
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>    
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawText (String string, int x, int y, int flags) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (string is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(CLIPPING | TRANSFORM | FONT | FOREGROUND_FILL);
+    NSAttributedString str = createString(string, flags);
+    if (data.paintRect is null) {
+        handle.saveGraphicsState();
+        NSAffineTransform transform = NSAffineTransform.transform();
+        transform.scaleXBy(1, -1);
+        transform.translateXBy(0, -(str.size().height + 2 * y));
+        transform.concat();
+    }
+    NSPoint pt = new NSPoint();
+    pt.x = x;
+    pt.y = y;
+    str.drawAtPoint(pt);
+    str.release();
+    if (data.paintRect is null) {
+        handle.restoreGraphicsState();
+    }
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/**
+ * Compares the argument to the receiver, and returns true
+ * if they represent the <em>same</em> object using a class
+ * specific comparison.
+ *
+ * @param object the object to compare with this object
+ * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
+ *
+ * @see #hashCode
+ */
+public bool equals(Object object) {
+    if (object is this) return true;
+    if (!(object instanceof GC)) return false;
+    return handle is ((GC)object).handle;
+}
+
+/**
+ * Fills the interior of a circular or elliptical arc within
+ * the specified rectangular area, with the receiver's background
+ * color.
+ * <p>
+ * The resulting arc begins at <code>startAngle</code> and extends  
+ * for <code>arcAngle</code> degrees, using the current color.
+ * Angles are interpreted such that 0 degrees is at the 3 o'clock
+ * position. A positive value indicates a counter-clockwise rotation
+ * while a negative value indicates a clockwise rotation.
+ * </p><p>
+ * The center of the arc is the center of the rectangle whose origin 
+ * is (<code>x</code>, <code>y</code>) and whose size is specified by the 
+ * <code>width</code> and <code>height</code> arguments. 
+ * </p><p>
+ * The resulting arc covers an area <code>width + 1</code> pixels wide
+ * by <code>height + 1</code> pixels tall.
+ * </p>
+ *
+ * @param x the x coordinate of the upper-left corner of the arc to be filled
+ * @param y the y coordinate of the upper-left corner of the arc to be filled
+ * @param width the width of the arc to be filled
+ * @param height the height of the arc to be filled
+ * @param startAngle the beginning angle
+ * @param arcAngle the angular extent of the arc, relative to the start angle
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawArc
+ */
+public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(FILL);
+    if (width < 0) {
+        x = x + width;
+        width = -width;
+    }
+    if (height < 0) {
+        y = y + height;
+        height = -height;
+    }
+    if (width is 0 || height is 0 || arcAngle is 0) return;
+    handle.saveGraphicsState();
+    NSAffineTransform transform = NSAffineTransform.transform();
+    float xOffset = data.drawXOffset, yOffset = data.drawYOffset;
+    transform.translateXBy(x + xOffset + width / 2f, y + yOffset + height / 2f);
+    transform.scaleXBy(width / 2f, height / 2f);
+    NSBezierPath path = data.path;
+    NSPoint center = new NSPoint();
+    path.moveToPoint(center);
+    float sAngle = -startAngle;
+    float eAngle = -(startAngle + arcAngle);
+    path.appendBezierPathWithArcWithCenter_radius_startAngle_endAngle_clockwise_(center, 1, sAngle,  eAngle, arcAngle>0);
+    path.closePath();
+    path.transformUsingAffineTransform(transform);
+    path.fill();
+    path.removeAllPoints();
+    handle.restoreGraphicsState();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/**
+ * Fills the interior of the specified rectangle with a gradient
+ * sweeping from left to right or top to bottom progressing
+ * from the receiver's foreground color to its background color.
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled, may be negative
+ *        (inverts direction of gradient if horizontal)
+ * @param height the height of the rectangle to be filled, may be negative
+ *        (inverts direction of gradient if vertical)
+ * @param vertical if true sweeps from top to bottom, else 
+ *        sweeps from left to right
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void fillGradientRectangle(int x, int y, int width, int height, bool vertical) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(CLIPPING | TRANSFORM);
+    if ((width is 0) || (height is 0)) return;
+
+    RGB backgroundRGB, foregroundRGB;
+    backgroundRGB = getBackground().getRGB();
+    foregroundRGB = getForeground().getRGB();
+
+    RGB fromRGB, toRGB;
+    fromRGB = foregroundRGB;
+    toRGB   = backgroundRGB;
+    bool swapColors = false;
+    if (width < 0) {
+        x += width; width = -width;
+        if (! vertical) swapColors = true;
+    }
+    if (height < 0) {
+        y += height; height = -height;
+        if (vertical) swapColors = true;
+    }
+    if (swapColors) {
+        fromRGB = backgroundRGB;
+        toRGB   = foregroundRGB;
+    }
+    if (fromRGB.equals(toRGB)) {
+        fillRectangle(x, y, width, height);
+    } else {
+        NSColor startingColor = NSColor.colorWithDeviceRed(fromRGB.red / 255f, fromRGB.green / 255f, fromRGB.blue / 255f, data.alpha / 255f);
+        NSColor endingColor = NSColor.colorWithDeviceRed(toRGB.red / 255f, toRGB.green / 255f, toRGB.blue / 255f, data.alpha / 255f);
+        NSGradient gradient = ((NSGradient)new NSGradient().alloc()).initWithStartingColor(startingColor, endingColor);
+        NSRect rect = new NSRect();
+        rect.x = x;
+        rect.y = y;
+        rect.width = width;
+        rect.height = height;
+        gradient.drawInRect_angle_(rect, vertical ? 90 : 0);
+        gradient.release();
+    }
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Fills the interior of an oval, within the specified
+ * rectangular area, with the receiver's background
+ * color.
+ *
+ * @param x the x coordinate of the upper left corner of the oval to be filled
+ * @param y the y coordinate of the upper left corner of the oval to be filled
+ * @param width the width of the oval to be filled
+ * @param height the height of the oval to be filled
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawOval
+ */
+public void fillOval(int x, int y, int width, int height) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(FILL);
+    if (width < 0) {
+        x = x + width;
+        width = -width;
+    }
+    if (height < 0) {
+        y = y + height;
+        height = -height;
+    }
+    NSBezierPath path = data.path;
+    NSRect rect = new NSRect();
+    rect.x = x;
+    rect.y = y;
+    rect.width = width;
+    rect.height = height;
+    path.appendBezierPathWithOvalInRect(rect);
+    Pattern pattern = data.backgroundPattern;
+    if (pattern !is null && pattern.gradient !is null) {
+        fillPattern(path, pattern);
+    } else {
+        path.fill();
+    }
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+void fillPattern(NSBezierPath path, Pattern pattern) {
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    path.addClip();
+    pattern.gradient.drawFromPoint(pattern.pt1, pattern.pt2, OS.NSGradientDrawsAfterEndingLocation | OS.NSGradientDrawsBeforeStartingLocation);
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Fills the path described by the parameter.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param path the path to fill
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see Path
+ * 
+ * @since 3.1
+ */
+public void fillPath(Path path) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (path is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (path.handle is null) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(FILL);
+    NSBezierPath drawPath = data.path;
+    drawPath.appendBezierPath(path.handle);
+    Pattern pattern = data.backgroundPattern;
+    if (pattern !is null && pattern.gradient !is null) {
+        fillPattern(drawPath, pattern);
+    } else {
+        drawPath.fill();
+    }
+    drawPath.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Fills the interior of the closed polygon which is defined by the
+ * specified array of integer coordinates, using the receiver's
+ * background color. The array contains alternating x and y values
+ * which are considered to represent points which are the vertices of
+ * the polygon. Lines are drawn between each consecutive pair, and
+ * between the first pair and last pair in the array.
+ *
+ * @param pointArray an array of alternating x and y values which are the vertices of the polygon
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT if pointArray is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawPolygon    
+ */
+public void fillPolygon(int[] pointArray) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (pointArray is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(FILL);
+    if (pointArray.length < 4) return;
+    NSBezierPath path = data.path;
+    NSPoint pt = new NSPoint();
+    pt.x = pointArray[0];
+    pt.y = pointArray[1];
+    path.moveToPoint(pt);
+    int end = pointArray.length / 2 * 2;
+    for (int i = 2; i < end; i+=2) {
+        pt.x = pointArray[i];
+        pt.y = pointArray[i+1];
+        path.lineToPoint(pt);
+    }
+    path.closePath();
+    Pattern pattern = data.backgroundPattern;
+    if (pattern !is null && pattern.gradient !is null) {
+        fillPattern(path, pattern);
+    } else {
+        path.fill();
+    }
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Fills the interior of the rectangle specified by the arguments,
+ * using the receiver's background color. 
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled
+ * @param height the height of the rectangle to be filled
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void fillRectangle(int x, int y, int width, int height) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(FILL);
+    if (width < 0) {
+        x = x + width;
+        width = -width;
+    }
+    if (height < 0) {
+        y = y + height;
+        height = -height;
+    }
+    NSRect rect = new NSRect();
+    rect.x = x;
+    rect.y = y;
+    rect.width = width;
+    rect.height = height;
+    NSBezierPath path = data.path;
+    path.appendBezierPathWithRect(rect);
+    Pattern pattern = data.backgroundPattern;
+    if (pattern !is null && pattern.gradient !is null) {
+        fillPattern(path, pattern);
+    } else {
+        path.fill();
+    }
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+/** 
+ * Fills the interior of the specified rectangle, using the receiver's
+ * background color. 
+ *
+ * @param rect the rectangle to be filled
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRectangle(int, int, int, int)
+ */
+public void fillRectangle(Rectangle rect) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (rect is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    fillRectangle(rect.x, rect.y, rect.width, rect.height);
+}
+
+/** 
+ * Fills the interior of the round-cornered rectangle specified by 
+ * the arguments, using the receiver's background color. 
+ *
+ * @param x the x coordinate of the rectangle to be filled
+ * @param y the y coordinate of the rectangle to be filled
+ * @param width the width of the rectangle to be filled
+ * @param height the height of the rectangle to be filled
+ * @param arcWidth the width of the arc
+ * @param arcHeight the height of the arc
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawRoundRectangle
+ */
+public void fillRoundRectangle(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSGraphicsContext context = NSGraphicsContext.currentContext();
+    NSGraphicsContext.setCurrentContext(handle);
+    checkGC(FILL);
+    if (arcWidth is 0 || arcHeight is 0) {
+        fillRectangle(x, y, width, height);
+        return;
+    }
+    NSBezierPath path = data.path;
+    NSRect rect = new NSRect();
+    rect.x = x;
+    rect.y = y;
+    rect.width = width;
+    rect.height = height;
+    path.appendBezierPathWithRoundedRect(rect, arcWidth, arcHeight);
+    Pattern pattern = data.backgroundPattern;
+    if (pattern !is null && pattern.gradient !is null) {
+        fillPattern(path, pattern);
+    } else {
+        path.fill();
+    }
+    path.removeAllPoints();
+    NSGraphicsContext.setCurrentContext(context);
+}
+
+void flush () {
+}
+
+/**
+ * Returns the <em>advance width</em> of the specified character in
+ * the font which is currently selected into the receiver.
+ * <p>
+ * The advance width is defined as the horizontal distance the cursor
+ * should move after printing the character in the selected font.
+ * </p>
+ *
+ * @param ch the character to measure
+ * @return the distance in the x direction to move past the character before painting the next
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getAdvanceWidth(char ch) {   
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    //NOT DONE
+    return stringExtent(new String(new char[]{ch})).x;
+}
+
+/** 
+ * Returns the background color.
+ *
+ * @return the receiver's background color
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getBackground() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return Color.cocoa_new (data.device, data.background);
+}
+
+/** 
+ * Returns the background pattern. The default value is
+ * <code>null</code>.
+ *
+ * @return the receiver's background pattern
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @see Pattern
+ * 
+ * @since 3.1
+ */
+public Pattern getBackgroundPattern() { 
+    if (handle is null) DWT.error(DWT.ERROR_WIDGET_DISPOSED);
+    return data.backgroundPattern;  
+}
+
+/**
+ * Returns <code>true</code> if receiver is using the operating system's
+ * advanced graphics subsystem.  Otherwise, <code>false</code> is returned
+ * to indicate that normal graphics are in use.
+ * <p>
+ * Advanced graphics may not be installed for the operating system.  In this
+ * case, <code>false</code> is always returned.  Some operating system have
+ * only one graphics subsystem.  If this subsystem supports advanced graphics,
+ * then <code>true</code> is always returned.  If any graphics operation such
+ * as alpha, antialias, patterns, interpolation, paths, clipping or transformation
+ * has caused the receiver to switch from regular to advanced graphics mode,
+ * <code>true</code> is returned.  If the receiver has been explicitly switched
+ * to advanced mode and this mode is supported, <code>true</code> is returned.
+ * </p>
+ *
+ * @return the advanced value
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @see #setAdvanced
+ * 
+ * @since 3.1
+ */
+public bool getAdvanced() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return true;
+}
+
+/**
+ * Returns the receiver's alpha value.
+ *
+ * @return the alpha value
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1
+ */
+public int getAlpha() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.alpha;
+}
+
+/**
+ * Returns the receiver's anti-aliasing setting value, which will be
+ * one of <code>DWT.DEFAULT</code>, <code>DWT.OFF</code> or
+ * <code>DWT.ON</code>. Note that this controls anti-aliasing for all
+ * <em>non-text drawing</em> operations.
+ *
+ * @return the anti-aliasing setting
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @see #getTextAntialias
+ * 
+ * @since 3.1
+ */
+public int getAntialias() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.antialias;
+}
+
+/**
+ * Returns the width of the specified character in the font
+ * selected into the receiver. 
+ * <p>
+ * The width is defined as the space taken up by the actual
+ * character, not including the leading and tailing whitespace
+ * or overhang.
+ * </p>
+ *
+ * @param ch the character to measure
+ * @return the width of the character
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getCharWidth(char ch) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    //NOT DONE
+    return stringExtent(new String(new char[]{ch})).x;
+}
+
+/** 
+ * Returns the bounding rectangle of the receiver's clipping
+ * region. If no clipping region is set, the return value
+ * will be a rectangle which covers the entire bounds of the
+ * object the receiver is drawing on.
+ *
+ * @return the bounding rectangle of the clipping region
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getClipping() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    NSRect rect = null;
+    if (data.view !is null) {
+        rect = data.view.bounds();
+    } else {
+        rect = new NSRect();
+        if (data.image !is null) {
+            NSSize size = data.image.handle.size();
+            rect.width = size.width;
+            rect.height = size.height;
+        } else if (data.size !is null) {
+            rect.width = data.size.width;
+            rect.height = data.size.height;
+        }
+    }
+    if (data.paintRect !is null || data.clipPath !is null || data.inverseTransform !is null) {
+        if (data.paintRect !is null) {
+            OS.NSIntersectionRect(rect, rect, data.paintRect);
+        }
+        if (data.clipPath !is null) {
+            NSRect clip = data.clipPath.bounds();
+            OS.NSIntersectionRect(rect, rect, clip);
+        }
+        if (data.inverseTransform !is null && rect.width > 0 && rect.height > 0) {
+            NSPoint pt = new NSPoint();
+            pt.x = rect.x;
+            pt.y = rect.y;
+            NSSize size = new NSSize();
+            size.width = rect.width;
+            size.height = rect.height;
+            pt = data.inverseTransform.transformPoint(pt);
+            size =  data.inverseTransform.transformSize(size);
+            rect.x = pt.x;
+            rect.y = pt.y;
+            rect.width = size.width;
+            rect.height = size.height;
+        }
+    }
+    return new Rectangle((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
+}
+
+/** 
+ * Sets the region managed by the argument to the current
+ * clipping region of the receiver.
+ *
+ * @param region the region to fill with the clipping region
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the region is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the region is disposed</li>
+ * </ul>    
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void getClipping(Region region) {    
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (region is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (region.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    region.subtract(region);
+    NSRect rect = null;
+    if (data.view !is null) {
+        rect = data.view.bounds();
+    } else {
+        rect = new NSRect();
+        if (data.image !is null) {
+            NSSize size = data.image.handle.size();
+            rect.width = size.width;
+            rect.height = size.height;
+        } else if (data.size !is null) {
+            rect.width = data.size.width;
+            rect.height = data.size.height;
+        }
+    }
+    region.add((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
+    NSRect paintRect = data.paintRect;
+    if (paintRect !is null) {
+        region.intersect((int)paintRect.x, (int)paintRect.y, (int)paintRect.width, (int)paintRect.height);
+    }
+    if (data.clipPath !is null) {
+        NSBezierPath clip = data.clipPath.bezierPathByFlatteningPath();
+        int count = clip.elementCount();
+        int pointCount = 0;
+        Region clipRgn = new Region(device);
+        int[] pointArray = new int[count * 2];
+        int points = OS.malloc(NSPoint.sizeof);
+        if (points is 0) DWT.error(DWT.ERROR_NO_HANDLES);
+        NSPoint pt = new NSPoint();
+        for (int i = 0; i < count; i++) {
+            int element = clip.elementAtIndex_associatedPoints_(i, points);
+            switch (element) {
+                case OS.NSMoveToBezierPathElement:
+                    if (pointCount !is 0) clipRgn.add(pointArray, pointCount);
+                    pointCount = 0;
+                    OS.memmove(pt, points, NSPoint.sizeof);
+                    pointArray[pointCount++] = (int)pt.x;
+                    pointArray[pointCount++] = (int)pt.y;
+                    break;
+                case OS.NSLineToBezierPathElement:
+                    OS.memmove(pt, points, NSPoint.sizeof);
+                    pointArray[pointCount++] = (int)pt.x;
+                    pointArray[pointCount++] = (int)pt.y;
+                    break;
+                case OS.NSClosePathBezierPathElement:
+                    if (pointCount !is 0) clipRgn.add(pointArray, pointCount);
+                    pointCount = 0;
+                    break;
+            }
+        }
+        if (pointCount !is 0) clipRgn.add(pointArray, pointCount);
+        OS.free(points);
+        region.intersect(clipRgn);
+        clipRgn.dispose();
+    }
+    if (data.inverseTransform !is null) {
+        region.convertRgn(data.inverseTransform);
+    }
+}
+
+/** 
+ * Returns the receiver's fill rule, which will be one of
+ * <code>DWT.FILL_EVEN_ODD</code> or <code>DWT.FILL_WINDING</code>.
+ *
+ * @return the receiver's fill rule
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1
+ */
+public int getFillRule() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.fillRule;
+}
+
+/** 
+ * Returns the font currently being used by the receiver
+ * to draw and measure text.
+ *
+ * @return the receiver's font
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Font getFont() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.font;
+}
+
+/**
+ * Returns a FontMetrics which contains information
+ * about the font currently being used by the receiver
+ * to draw and measure text.
+ *
+ * @return font metrics for the receiver's font
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontMetrics getFontMetrics() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    checkGC(FONT);
+    NSFont font = data.font.handle;
+    int ascent = (int)(0.5f + font.ascender());
+    int descent = (int)(0.5f + (-font.descender() + font.leading()));   
+    String s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 
+    int averageCharWidth = stringExtent(s).x / s.length();
+    return FontMetrics.cocoa_new(ascent, descent, averageCharWidth, 0, ascent + descent);
+}
+
+/** 
+ * Returns the receiver's foreground color.
+ *
+ * @return the color used for drawing foreground things
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getForeground() {  
+    if (handle is null) DWT.error(DWT.ERROR_WIDGET_DISPOSED);
+    return Color.cocoa_new(data.device, data.foreground);   
+}
+
+/** 
+ * Returns the foreground pattern. The default value is
+ * <code>null</code>.
+ *
+ * @return the receiver's foreground pattern
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @see Pattern
+ * 
+ * @since 3.1
+ */
+public Pattern getForegroundPattern() { 
+    if (handle is null) DWT.error(DWT.ERROR_WIDGET_DISPOSED);
+    return data.foregroundPattern;  
+}
+
+/** 
+ * Returns the GCData.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>GC</code>. It is marked public only so that it
+ * can be shared within the packages provided by DWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @return the receiver's GCData
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @see GCData
+ * 
+ * @since 3.2
+ */
+public GCData getGCData() { 
+    if (handle is null) DWT.error(DWT.ERROR_WIDGET_DISPOSED);
+    return data;    
+}
+
+/** 
+ * Returns the receiver's interpolation setting, which will be one of
+ * <code>DWT.DEFAULT</code>, <code>DWT.NONE</code>, 
+ * <code>DWT.LOW</code> or <code>DWT.HIGH</code>.
+ *
+ * @return the receiver's interpolation setting
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1
+ */
+public int getInterpolation() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    int interpolation = handle.imageInterpolation();
+    switch (interpolation) {
+        case OS.NSImageInterpolationDefault: return DWT.DEFAULT;
+        case OS.NSImageInterpolationNone: return DWT.NONE;
+        case OS.NSImageInterpolationLow: return DWT.LOW;
+        case OS.NSImageInterpolationHigh: return DWT.HIGH;
+    }
+    return DWT.DEFAULT;
+}
+
+/** 
+ * Returns the receiver's line attributes.
+ *
+ * @return the line attributes used for drawing lines
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.3 
+ */
+public LineAttributes getLineAttributes() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    float[] dashes = null;
+    if (data.lineDashes !is null) {
+        dashes = new float[data.lineDashes.length];
+        System.arraycopy(data.lineDashes, 0, dashes, 0, dashes.length);
+    }
+    return new LineAttributes(data.lineWidth, data.lineCap, data.lineJoin, data.lineStyle, dashes, data.lineDashesOffset, data.lineMiterLimit);
+}
+
+/** 
+ * Returns the receiver's line cap style, which will be one
+ * of the constants <code>DWT.CAP_FLAT</code>, <code>DWT.CAP_ROUND</code>,
+ * or <code>DWT.CAP_SQUARE</code>.
+ *
+ * @return the cap style used for drawing lines
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1 
+ */
+public int getLineCap() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.lineCap;
+}
+
+/** 
+ * Returns the receiver's line dash style. The default value is
+ * <code>null</code>.
+ *
+ * @return the line dash style used for drawing lines
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1 
+ */
+public int[] getLineDash() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (data.lineDashes is null) return null;
+    int[] lineDashes = new int[data.lineDashes.length];
+    for (int i = 0; i < lineDashes.length; i++) {
+        lineDashes[i] = (int)data.lineDashes[i];
+    }
+    return lineDashes;  
+}
+
+/** 
+ * Returns the receiver's line join style, which will be one
+ * of the constants <code>DWT.JOIN_MITER</code>, <code>DWT.JOIN_ROUND</code>,
+ * or <code>DWT.JOIN_BEVEL</code>.
+ *
+ * @return the join style used for drawing lines
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1 
+ */
+public int getLineJoin() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.lineJoin;
+}
+
+/** 
+ * Returns the receiver's line style, which will be one
+ * of the constants <code>DWT.LINE_SOLID</code>, <code>DWT.LINE_DASH</code>,
+ * <code>DWT.LINE_DOT</code>, <code>DWT.LINE_DASHDOT</code> or
+ * <code>DWT.LINE_DASHDOTDOT</code>.
+ *
+ * @return the style used for drawing lines
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineStyle() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.lineStyle;
+}
+
+/** 
+ * Returns the width that will be used when drawing lines
+ * for all of the figure drawing operations (that is,
+ * <code>drawLine</code>, <code>drawRectangle</code>, 
+ * <code>drawPolyline</code>, and so forth.
+ *
+ * @return the receiver's line width 
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineWidth() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return (int)data.lineWidth;
+}
+
+/**
+ * Returns the receiver's style information.
+ * <p>
+ * Note that the value which is returned by this method <em>may
+ * not match</em> the value which was provided to the constructor
+ * when the receiver was created. This can occur when the underlying
+ * operating system does not support a particular combination of
+ * requested styles. 
+ * </p>
+ *
+ * @return the style bits
+ *  
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *   
+ * @since 2.1.2
+ */
+public int getStyle () {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.style;
+}
+
+/**
+ * Returns the receiver's text drawing anti-aliasing setting value,
+ * which will be one of <code>DWT.DEFAULT</code>, <code>DWT.OFF</code> or
+ * <code>DWT.ON</code>. Note that this controls anti-aliasing
+ * <em>only</em> for text drawing operations.
+ *
+ * @return the anti-aliasing setting
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @see #getAntialias
+ * 
+ * @since 3.1
+ */
+public int getTextAntialias() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.textAntialias;
+}
+
+/** 
+ * Sets the parameter to the transform that is currently being
+ * used by the receiver.
+ *
+ * @param transform the destination to copy the transform into
+ * 
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @see Transform
+ * 
+ * @since 3.1
+ */
+public void getTransform (Transform transform) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (transform is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (transform.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    NSAffineTransform cmt = data.transform;
+    if (cmt !is null) {
+        NSAffineTransformStruct struct = cmt.transformStruct();
+        transform.handle.setTransformStruct(struct);
+    } else {
+        transform.setElements(1, 0, 0, 1, 0, 0);
+    }
+}
+
+/** 
+ * Returns <code>true</code> if this GC is drawing in the mode
+ * where the resulting color in the destination is the
+ * <em>exclusive or</em> of the color values in the source
+ * and the destination, and <code>false</code> if it is
+ * drawing in the mode where the destination color is being
+ * replaced with the source color value.
+ *
+ * @return <code>true</code> true if the receiver is in XOR mode, and false otherwise
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public bool getXORMode() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.xorMode;
+}
+
+/**
+ * Returns an integer hash code for the receiver. Any two 
+ * objects that return <code>true</code> when passed to 
+ * <code>equals</code> must return the same value for this
+ * method.
+ *
+ * @return the receiver's hash
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #equals
+ */
+public int hashCode() {
+    return handle !is null ? handle.id : 0;
+}
+
+void init(Drawable drawable, GCData data, int context) {
+    if (data.foreground !is null) data.state &= ~(FOREGROUND | FOREGROUND_FILL);
+    if (data.background !is null)  data.state &= ~BACKGROUND;
+    if (data.font !is null) data.state &= ~FONT;
+    data.state &= ~DRAW_OFFSET;
+
+    Image image = data.image;
+    if (image !is null) image.memGC = this;
+    this.drawable = drawable;
+    this.data = data;
+    handle = new NSGraphicsContext(context);
+    handle.retain();
+    handle.saveGraphicsState();
+    data.path = NSBezierPath.bezierPath();
+    data.path.setWindingRule(data.fillRule is DWT.FILL_WINDING ? OS.NSNonZeroWindingRule : OS.NSEvenOddWindingRule);
+    data.path.retain();
+}
+
+/**
+ * Returns <code>true</code> if the receiver has a clipping
+ * region set into it, and <code>false</code> otherwise.
+ * If this method returns false, the receiver will draw on all
+ * available space in the destination. If it returns true, 
+ * it will draw only in the area that is covered by the region
+ * that can be accessed with <code>getClipping(region)</code>.
+ *
+ * @return <code>true</code> if the GC has a clipping region, and <code>false</code> otherwise
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public bool isClipped() {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    return data.clipPath !is null;
+}
+
+/**
+ * Returns <code>true</code> if the GC has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the GC.
+ * When a GC has been disposed, it is an error to
+ * invoke any other method using the GC.
+ *
+ * @return <code>true</code> when the GC is disposed and <code>false</code> otherwise
+ */
+public bool isDisposed() {
+    return handle is null;
+}
+
+bool isIdentity(float[] transform) {
+    return transform[0] is 1 && transform[1] is 0 && transform[2] is 0
+        && transform[3] is 1 && transform[4] is 0 && transform[5] is 0;
+}
+
+/**
+ * Sets the receiver to always use the operating system's advanced graphics
+ * subsystem for all graphics operations if the argument is <code>true</code>.
+ * If the argument is <code>false</code>, the advanced graphics subsystem is 
+ * no longer used, advanced graphics state is cleared and the normal graphics
+ * subsystem is used from now on.
+ * <p>
+ * Normally, the advanced graphics subsystem is invoked automatically when
+ * any one of the alpha, antialias, patterns, interpolation, paths, clipping
+ * or transformation operations in the receiver is requested.  When the receiver
+ * is switched into advanced mode, the advanced graphics subsystem performs both
+ * advanced and normal graphics operations.  Because the two subsystems are
+ * different, their output may differ.  Switching to advanced graphics before
+ * any graphics operations are performed ensures that the output is consistent.
+ * </p><p>
+ * Advanced graphics may not be installed for the operating system.  In this
+ * case, this operation does nothing.  Some operating system have only one
+ * graphics subsystem, so switching from normal to advanced graphics does
+ * nothing.  However, switching from advanced to normal graphics will always
+ * clear the advanced graphics state, even for operating systems that have
+ * only one graphics subsystem.
+ * </p>
+ *
+ * @param advanced the new advanced graphics state
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @see #setAlpha
+ * @see #setAntialias
+ * @see #setBackgroundPattern
+ * @see #setClipping(Path)
+ * @see #setForegroundPattern
+ * @see #setLineAttributes
+ * @see #setInterpolation
+ * @see #setTextAntialias
+ * @see #setTransform
+ * @see #getAdvanced
+ * 
+ * @since 3.1
+ */
+public void setAdvanced(bool advanced) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (!advanced) {
+        setAlpha(0xFF);
+        setAntialias(DWT.DEFAULT);
+        setBackgroundPattern(null);
+        setClipping((Rectangle)null);
+        setForegroundPattern(null);
+        setInterpolation(DWT.DEFAULT);
+        setTextAntialias(DWT.DEFAULT);
+        setTransform(null);
+    }
+}
+
+/**
+ * Sets the receiver's alpha value.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * @param alpha the alpha value
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * 
+ * @since 3.1
+ */
+public void setAlpha(int alpha) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    data.alpha = alpha & 0xFF;
+    data.state &= ~(BACKGROUND | FOREGROUND | FOREGROUND_FILL);
+    
+}
+
+/**
+ * Sets the receiver's anti-aliasing value to the parameter, 
+ * which must be one of <code>DWT.DEFAULT</code>, <code>DWT.OFF</code>
+ * or <code>DWT.ON</code>. Note that this controls anti-aliasing for all
+ * <em>non-text drawing</em> operations.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param antialias the anti-aliasing setting
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>DWT.DEFAULT</code>,
+ *                                 <code>DWT.OFF</code> or <code>DWT.ON</code></li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * @see #setTextAntialias
+ * 
+ * @since 3.1
+ */
+public void setAntialias(int antialias) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    bool mode = true;
+    switch (antialias) {
+        case DWT.DEFAULT:
+            /* Printer is off by default */
+//          if (data.window is 0 && data.control is 0 && data.image is null) mode = false;
+            mode = true;
+            break;
+        case DWT.OFF: mode = false; break;
+        case DWT.ON: mode = true; break;
+        default:
+            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    data.antialias = antialias;
+    handle.setShouldAntialias(mode);
+}
+
+/**
+ * Sets the background color. The background color is used
+ * for fill operations and as the background color when text
+ * is drawn.
+ *
+ * @param color the new background color for the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the color is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setBackground(Color color) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (color is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (color.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    data.background = color.handle;
+    data.backgroundPattern = null;
+    data.state &= ~BACKGROUND;
+}
+
+/** 
+ * Sets the background pattern. The default value is <code>null</code>.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * 
+ * @param pattern the new background pattern
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see Pattern
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * 
+ * @since 3.1
+ */
+public void setBackgroundPattern(Pattern pattern) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (pattern !is null && pattern.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    if (data.backgroundPattern is pattern) return;
+    data.backgroundPattern = pattern;
+    data.state &= ~BACKGROUND;
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the rectangular area specified
+ * by the arguments.
+ *
+ * @param x the x coordinate of the clipping rectangle
+ * @param y the y coordinate of the clipping rectangle
+ * @param width the width of the clipping rectangle
+ * @param height the height of the clipping rectangle
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping(int x, int y, int width, int height) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (width < 0) {
+        x = x + width;
+        width = -width;
+    }
+    if (height < 0) {
+        y = y + height;
+        height = -height;
+    }
+    NSRect rect = new NSRect();
+    rect.x = x;
+    rect.y = y;
+    rect.width = width;
+    rect.height = height;
+    NSBezierPath path = NSBezierPath.bezierPathWithRect(rect);
+    path.retain();
+    setClipping(path);
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the path specified
+ * by the argument.  
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * 
+ * @param path the clipping path.
+ * 
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the path has been disposed</li>
+ * </ul> 
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see Path
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * 
+ * @since 3.1
+ */
+public void setClipping(Path path) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (path !is null && path.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    setClipping(new NSBezierPath(path.handle.copy().id));
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the rectangular area specified
+ * by the argument.  Specifying <code>null</code> for the
+ * rectangle reverts the receiver's clipping area to its
+ * original value.
+ *
+ * @param rect the clipping rectangle or <code>null</code>
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping(Rectangle rect) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (rect is null) {
+        setClipping((NSBezierPath)null);
+    } else {
+        setClipping(rect.x, rect.y, rect.width, rect.height);
+    }
+}
+
+/**
+ * Sets the area of the receiver which can be changed
+ * by drawing operations to the region specified
+ * by the argument.  Specifying <code>null</code> for the
+ * region reverts the receiver's clipping area to its
+ * original value.
+ *
+ * @param region the clipping region or <code>null</code>
+ * 
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li>
+ * </ul> 
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping(Region region) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (region !is null && region.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    setClipping(region !is null ? region.getPath() : null);
+}
+
+void setClipping(NSBezierPath path) {
+    if (data.clipPath !is null) {
+        data.clipPath.release();
+        data.clipPath = null;
+    }
+    if (path !is null) {
+        data.clipPath = path;
+        if (data.transform !is null) {
+            data.clipPath.transformUsingAffineTransform(data.transform);
+        }
+    }
+    data.state &= ~CLIPPING;
+}
+
+/** 
+ * Sets the receiver's fill rule to the parameter, which must be one of
+ * <code>DWT.FILL_EVEN_ODD</code> or <code>DWT.FILL_WINDING</code>.
+ *
+ * @param rule the new fill rule
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>DWT.FILL_EVEN_ODD</code>
+ *                                 or <code>DWT.FILL_WINDING</code></li>
+ * </ul> 
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1
+ */
+public void setFillRule(int rule) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    switch (rule) {
+        case DWT.FILL_WINDING:
+        case DWT.FILL_EVEN_ODD: break;
+        default:
+            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    data.fillRule = rule;
+    data.path.setWindingRule(rule is DWT.FILL_WINDING ? OS.NSNonZeroWindingRule : OS.NSEvenOddWindingRule);
+}
+
+/** 
+ * Sets the font which will be used by the receiver
+ * to draw and measure text to the argument. If the
+ * argument is null, then a default font appropriate
+ * for the platform will be used instead.
+ *
+ * @param font the new font for the receiver, or null to indicate a default font
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setFont(Font font) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (font !is null && font.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    data.font = font !is null ? font : data.device.systemFont;
+    data.state &= ~FONT;
+}
+
+/**
+ * Sets the foreground color. The foreground color is used
+ * for drawing operations including when text is drawn.
+ *
+ * @param color the new foreground color for the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the color is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setForeground(Color color) {    
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (color is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    if (color.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    data.foreground = color.handle;
+    data.foregroundPattern = null;
+    data.state &= ~(FOREGROUND | FOREGROUND_FILL);
+}
+
+/** 
+ * Sets the foreground pattern. The default value is <code>null</code>.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * @param pattern the new foreground pattern
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see Pattern
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * 
+ * @since 3.1
+ */
+public void setForegroundPattern(Pattern pattern) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (pattern !is null && pattern.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    if (data.foregroundPattern is pattern) return;
+    data.foregroundPattern = pattern;
+    data.state &= ~(FOREGROUND | FOREGROUND_FILL);
+}
+
+/** 
+ * Sets the receiver's interpolation setting to the parameter, which
+ * must be one of <code>DWT.DEFAULT</code>, <code>DWT.NONE</code>, 
+ * <code>DWT.LOW</code> or <code>DWT.HIGH</code>.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * 
+ * @param interpolation the new interpolation setting
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>DWT.DEFAULT</code>, 
+ *                                 <code>DWT.NONE</code>, <code>DWT.LOW</code> or <code>DWT.HIGH</code>
+ * </ul> 
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * 
+ * @since 3.1
+ */
+public void setInterpolation(int interpolation) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    int quality = 0;
+    switch (interpolation) {
+        case DWT.DEFAULT: quality = OS.NSImageInterpolationDefault; break;
+        case DWT.NONE: quality = OS.NSImageInterpolationNone; break;
+        case DWT.LOW: quality = OS.NSImageInterpolationLow; break;
+        case DWT.HIGH: quality = OS.NSImageInterpolationHigh; break;
+        default:
+            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    handle.setImageInterpolation(quality);
+}
+
+/**
+ * Sets the receiver's line attributes.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * @param attributes the line attributes
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the attributes is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if any of the line attributes is not valid</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see LineAttributes
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * 
+ * @since 3.3
+ */
+public void setLineAttributes(LineAttributes attributes) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (attributes is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    int mask = 0;
+    float lineWidth = attributes.width;
+    if (lineWidth !is data.lineWidth) {
+        mask |= LINE_WIDTH | DRAW_OFFSET;
+    }
+    int lineStyle = attributes.style;
+    if (lineStyle !is data.lineStyle) {
+        mask |= LINE_STYLE;
+        switch (lineStyle) {
+            case DWT.LINE_SOLID:
+            case DWT.LINE_DASH:
+            case DWT.LINE_DOT:
+            case DWT.LINE_DASHDOT:
+            case DWT.LINE_DASHDOTDOT:
+                break;
+            case DWT.LINE_CUSTOM:
+                if (attributes.dash is null) lineStyle = DWT.LINE_SOLID;
+                break;
+            default:
+                DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+        }
+    }
+    int join = attributes.join;
+    if (join !is data.lineJoin) {
+        mask |= LINE_JOIN;
+        switch (join) {
+            case DWT.CAP_ROUND:
+            case DWT.CAP_FLAT:
+            case DWT.CAP_SQUARE:
+                break;
+            default:
+                DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+        }
+    }
+    int cap = attributes.cap;
+    if (cap !is data.lineCap) {
+        mask |= LINE_CAP;
+        switch (cap) {
+            case DWT.JOIN_MITER:
+            case DWT.JOIN_ROUND:
+            case DWT.JOIN_BEVEL:
+                break;
+            default:
+                DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+        }
+    }
+    float[] dashes = attributes.dash;
+    float[] lineDashes = data.lineDashes;
+    if (dashes !is null && dashes.length > 0) {
+        bool changed = lineDashes is null || lineDashes.length !is dashes.length;
+        for (int i = 0; i < dashes.length; i++) {
+            float dash = dashes[i];
+            if (dash <= 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+            if (!changed && lineDashes[i] !is dash) changed = true;
+        }
+        if (changed) {
+            float[] newDashes = new float[dashes.length];
+            System.arraycopy(dashes, 0, newDashes, 0, dashes.length);
+            dashes = newDashes;
+            mask |= LINE_STYLE;
+        } else {
+            dashes = lineDashes;
+        }
+    } else {
+        if (lineDashes !is null && lineDashes.length > 0) {
+            mask |= LINE_STYLE;
+        } else {
+            dashes = lineDashes;
+        }
+    }
+    float dashOffset = attributes.dashOffset;
+    if (dashOffset !is data.lineDashesOffset) {
+        mask |= LINE_STYLE;     
+    }
+    float miterLimit = attributes.miterLimit;
+    if (miterLimit !is data.lineMiterLimit) {
+        mask |= LINE_MITERLIMIT;        
+    }
+    if (mask is 0) return;
+    data.lineWidth = lineWidth;
+    data.lineStyle = lineStyle;
+    data.lineCap = cap;
+    data.lineJoin = join;
+    data.lineDashes = dashes;
+    data.lineDashesOffset = dashOffset;
+    data.lineMiterLimit = miterLimit;
+    data.state &= ~mask;
+}
+
+/** 
+ * Sets the receiver's line cap style to the argument, which must be one
+ * of the constants <code>DWT.CAP_FLAT</code>, <code>DWT.CAP_ROUND</code>,
+ * or <code>DWT.CAP_SQUARE</code>.
+ *
+ * @param cap the cap style to be used for drawing lines
+ * 
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
+ * </ul> 
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1 
+ */
+public void setLineCap(int cap) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (data.lineCap is cap) return;
+    switch (cap) {
+        case DWT.CAP_ROUND:
+        case DWT.CAP_FLAT:
+        case DWT.CAP_SQUARE:
+            break;
+        default:
+            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    data.lineCap = cap;
+    data.state &= ~LINE_CAP;
+}
+
+/** 
+ * Sets the receiver's line dash style to the argument. The default
+ * value is <code>null</code>. If the argument is not <code>null</code>,
+ * the receiver's line style is set to <code>DWT.LINE_CUSTOM</code>, otherwise
+ * it is set to <code>DWT.LINE_SOLID</code>.
+ *
+ * @param dashes the dash style to be used for drawing lines
+ * 
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if any of the values in the array is less than or equal 0</li>
+ * </ul> 
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1 
+ */
+public void setLineDash(int[] dashes) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    float[] lineDashes = data.lineDashes;
+    if (dashes !is null && dashes.length > 0) {
+        bool changed = data.lineStyle !is DWT.LINE_CUSTOM || lineDashes is null || lineDashes.length !is dashes.length;
+        for (int i = 0; i < dashes.length; i++) {
+            int dash = dashes[i];
+            if (dash <= 0) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+            if (!changed && lineDashes[i] !is dash) changed = true;
+        }
+        if (!changed) return;
+        data.lineDashes = new float[dashes.length];
+        for (int i = 0; i < dashes.length; i++) {
+            data.lineDashes[i] = dashes[i];
+        }
+        data.lineStyle = DWT.LINE_CUSTOM;
+    } else {
+        if (data.lineStyle is DWT.LINE_SOLID && (lineDashes is null || lineDashes.length is 0)) return;
+        data.lineDashes = null;
+        data.lineStyle = DWT.LINE_SOLID;
+    }
+    data.state &= ~LINE_STYLE;
+}
+
+/** 
+ * Sets the receiver's line join style to the argument, which must be one
+ * of the constants <code>DWT.JOIN_MITER</code>, <code>DWT.JOIN_ROUND</code>,
+ * or <code>DWT.JOIN_BEVEL</code>.
+ *
+ * @param join the join style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @since 3.1 
+ */
+public void setLineJoin(int join) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (data.lineJoin is join) return;
+    switch (join) {
+        case DWT.JOIN_MITER:
+        case DWT.JOIN_ROUND:
+        case DWT.JOIN_BEVEL:
+            break;
+        default:
+            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    data.lineJoin = join;
+    data.state &= ~LINE_JOIN;
+}
+
+/** 
+ * Sets the receiver's line style to the argument, which must be one
+ * of the constants <code>DWT.LINE_SOLID</code>, <code>DWT.LINE_DASH</code>,
+ * <code>DWT.LINE_DOT</code>, <code>DWT.LINE_DASHDOT</code> or
+ * <code>DWT.LINE_DASHDOTDOT</code>.
+ *
+ * @param lineStyle the style to be used for drawing lines
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setLineStyle(int lineStyle) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (data.lineStyle is lineStyle) return;
+    switch (lineStyle) {
+        case DWT.LINE_SOLID:
+        case DWT.LINE_DASH:
+        case DWT.LINE_DOT:
+        case DWT.LINE_DASHDOT:
+        case DWT.LINE_DASHDOTDOT:
+            break;
+        case DWT.LINE_CUSTOM:
+            if (data.lineDashes is null) lineStyle = DWT.LINE_SOLID;
+            break;
+        default:
+            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    data.lineStyle = lineStyle;
+    data.state &= ~LINE_STYLE;
+}
+
+/** 
+ * Sets the width that will be used when drawing lines
+ * for all of the figure drawing operations (that is,
+ * <code>drawLine</code>, <code>drawRectangle</code>, 
+ * <code>drawPolyline</code>, and so forth.
+ * <p>
+ * Note that line width of zero is used as a hint to
+ * indicate that the fastest possible line drawing
+ * algorithms should be used. This means that the
+ * output may be different from line width one.
+ * </p>
+ *
+ * @param lineWidth the width of a line
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setLineWidth(int lineWidth) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (data.lineWidth is lineWidth) return;
+    data.lineWidth = lineWidth;
+    data.state &= ~(LINE_WIDTH | DRAW_OFFSET);  
+}
+
+/** 
+ * If the argument is <code>true</code>, puts the receiver
+ * in a drawing mode where the resulting color in the destination
+ * is the <em>exclusive or</em> of the color values in the source
+ * and the destination, and if the argument is <code>false</code>,
+ * puts the receiver in a drawing mode where the destination color
+ * is replaced with the source color value.
+ * <p>
+ * Note that this mode in fundamentally unsupportable on certain
+ * platforms, notably Carbon (Mac OS X). Clients that want their
+ * code to run on all platforms need to avoid this method.
+ * </p>
+ *
+ * @param xor if <code>true</code>, then <em>xor</em> mode is used, otherwise <em>source copy</em> mode is used
+ *
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * 
+ * @deprecated this functionality is not supported on some platforms
+ */
+public void setXORMode(bool xor) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    data.xorMode = xor;
+}
+
+/**
+ * Sets the receiver's text anti-aliasing value to the parameter, 
+ * which must be one of <code>DWT.DEFAULT</code>, <code>DWT.OFF</code>
+ * or <code>DWT.ON</code>. Note that this controls anti-aliasing only
+ * for all <em>text drawing</em> operations.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * 
+ * @param antialias the anti-aliasing setting
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>DWT.DEFAULT</code>,
+ *                                 <code>DWT.OFF</code> or <code>DWT.ON</code></li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * @see #setAntialias
+ * 
+ * @since 3.1
+ */
+public void setTextAntialias(int antialias) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    switch (antialias) {
+        case DWT.DEFAULT:
+        case DWT.OFF:
+        case DWT.ON:
+            break;
+        default:
+            DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    }
+    data.textAntialias = antialias;
+}
+
+/**
+ * Sets the transform that is currently being used by the receiver. If
+ * the argument is <code>null</code>, the current transform is set to
+ * the identity transform.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ * 
+ * @param transform the transform to set
+ * 
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * 
+ * @see Transform
+ * @see #getAdvanced
+ * @see #setAdvanced
+ * 
+ * @since 3.1
+ */
+public void setTransform(Transform transform) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (transform !is null && transform.isDisposed()) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
+    if (transform !is null) {
+        if (data.transform !is null) data.transform.release();
+        if (data.inverseTransform !is null) data.inverseTransform.release();
+        data.transform = ((NSAffineTransform)new NSAffineTransform().alloc()).initWithTransform(transform.handle);
+        data.inverseTransform = ((NSAffineTransform)new NSAffineTransform().alloc()).initWithTransform(transform.handle);
+        NSAffineTransformStruct struct = data.inverseTransform.transformStruct();
+        if ((struct.m11 * struct.m22 - struct.m12 * struct.m21) !is 0) {
+            data.inverseTransform.invert();
+        }
+    } else {
+        data.transform = data.inverseTransform = null;
+    }
+    data.state &= ~(TRANSFORM | DRAW_OFFSET);
+}
+
+/**
+ * Returns the extent of the given string. No tab
+ * expansion or carriage return processing will be performed.
+ * <p>
+ * The <em>extent</em> of a string is the width and height of
+ * the rectangular area it would cover if drawn in a particular
+ * font (in this case, the current font in the receiver).
+ * </p>
+ *
+ * @param string the string to measure
+ * @return a point containing the extent of the string
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point stringExtent(String string) {
+    return textExtent(string, 0);
+}
+
+/**
+ * Returns the extent of the given string. Tab expansion and
+ * carriage return processing are performed.
+ * <p>
+ * The <em>extent</em> of a string is the width and height of
+ * the rectangular area it would cover if drawn in a particular
+ * font (in this case, the current font in the receiver).
+ * </p>
+ *
+ * @param string the string to measure
+ * @return a point containing the extent of the string
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point textExtent(String string) {
+    return textExtent(string, DWT.DRAW_DELIMITER | DWT.DRAW_TAB);
+}
+
+/**
+ * Returns the extent of the given string. Tab expansion, line
+ * delimiter and mnemonic processing are performed according to
+ * the specified flags, which can be a combination of:
+ * <dl>
+ * <dt><b>DRAW_DELIMITER</b></dt>
+ * <dd>draw multiple lines</dd>
+ * <dt><b>DRAW_TAB</b></dt>
+ * <dd>expand tabs</dd>
+ * <dt><b>DRAW_MNEMONIC</b></dt>
+ * <dd>underline the mnemonic character</dd>
+ * <dt><b>DRAW_TRANSPARENT</b></dt>
+ * <dd>transparent background</dd>
+ * </dl>
+ * <p>
+ * The <em>extent</em> of a string is the width and height of
+ * the rectangular area it would cover if drawn in a particular
+ * font (in this case, the current font in the receiver).
+ * </p>
+ *
+ * @param string the string to measure
+ * @param flags the flags specifying how to process the text
+ * @return a point containing the extent of the string
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the string is null</li>
+ * </ul>
+ * @exception DWTException <ul>
+ *    <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point textExtent(String string, int flags) {
+    if (handle is null) DWT.error(DWT.ERROR_GRAPHIC_DISPOSED);
+    if (string is null) DWT.error(DWT.ERROR_NULL_ARGUMENT);
+    checkGC(FONT);
+    NSAttributedString str = createString(string, flags);
+    NSSize size = str.size();
+    return new Point((int)size.width, (int)size.height);
+}
+
+/**
+ * Returns a string containing a concise, human-readable
+ * description of the receiver.
+ *
+ * @return a string representation of the receiver
+ */
+public String toString () {
+    if (isDisposed()) return "GC {*DISPOSED*}";
+    return "GC {" + handle + "}";
+}
+
+}