summaryrefslogtreecommitdiffstats
path: root/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics
diff options
context:
space:
mode:
authorSilenio Quarti <silenio>2009-07-01 14:50:54 +0000
committerSilenio Quarti <silenio>2009-07-01 14:50:54 +0000
commit093c579a4ffd9551acb901bba9617e7aa776989d (patch)
tree71cf23798b651ef92f188390841a8d130908fb11 /bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics
parentf664d297f7bb009784868bf3fcf0b3e3bb9a646b (diff)
downloadeclipse.platform.swt-093c579a4ffd9551acb901bba9617e7aa776989d.tar.gz
eclipse.platform.swt-093c579a4ffd9551acb901bba9617e7aa776989d.tar.xz
eclipse.platform.swt-093c579a4ffd9551acb901bba9617e7aa776989d.zip
restore HEAD after accidental deletion by error in automated build script
Diffstat (limited to 'bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics')
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Color.java325
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java460
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Device.java972
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/DeviceData.java23
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Font.java258
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontData.java669
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontMetrics.java183
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java4979
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java64
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java2129
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Path.java602
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Pattern.java250
-rwxr-xr-xbundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java597
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java3328
-rw-r--r--bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Transform.java369
15 files changed, 15208 insertions, 0 deletions
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Color.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Color.java
new file mode 100755
index 0000000000..3603b53a65
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Color.java
@@ -0,0 +1,325 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class manage the operating system resources that
+ * implement SWT's RGB color model. To create a color you can either
+ * specify the individual color components as integers in the range
+ * 0 to 255 or provide an instance of an <code>RGB</code>.
+ * <p>
+ * Application code must explicitly invoke the <code>Color.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see RGB
+ * @see Device#getSystemColor
+ * @see <a href="http://www.eclipse.org/swt/snippets/#color">Color and RGB snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: PaintExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+
+public final class Color extends Resource {
+
+ /**
+ * the handle to the OS color resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int handle;
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+Color(Device device) {
+ super(device);
+}
+
+/**
+ * Constructs a new instance of this class given a device and the
+ * desired red, green and blue values expressed as ints in the range
+ * 0 to 255 (where 0 is black and 255 is full brightness). On limited
+ * color devices, the color instance created by this call may not have
+ * the same RGB values as the ones specified by the arguments. The
+ * RGB values on the returned instance will be the color values of
+ * the operating system color.
+ * <p>
+ * You must dispose the color when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param red the amount of red in the color
+ * @param green the amount of green in the color
+ * @param blue the amount of blue in the color
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the red, green or blue argument is not between 0 and 255</li>
+ * </ul>
+ *
+ * @see #dispose
+ */
+public Color (Device device, int red, int green, int blue) {
+ super(device);
+ init(red, green, blue);
+ init();
+}
+
+/**
+ * Constructs a new instance of this class given a device and an
+ * <code>RGB</code> describing the desired red, green and blue values.
+ * On limited color devices, the color instance created by this call
+ * may not have the same RGB values as the ones specified by the
+ * argument. The RGB values on the returned instance will be the color
+ * values of the operating system color.
+ * <p>
+ * You must dispose the color when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param rgb the RGB values of the desired color
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the rgb argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the red, green or blue components of the argument are not between 0 and 255</li>
+ * </ul>
+ *
+ * @see #dispose
+ */
+public Color (Device device, RGB rgb) {
+ super(device);
+ if (rgb == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(rgb.red, rgb.green, rgb.blue);
+ init();
+}
+
+void destroy() {
+ /*
+ * If this is a palette-based device,
+ * Decrease the reference count for this color.
+ * If the reference count reaches 0, the slot may
+ * be reused when another color is allocated.
+ */
+ int /*long*/ hPal = device.hPalette;
+ if (hPal != 0) {
+ int index = OS.GetNearestPaletteIndex(hPal, handle);
+ int[] colorRefCount = device.colorRefCount;
+ if (colorRefCount[index] > 0) {
+ colorRefCount[index]--;
+ }
+ }
+ handle = -1;
+}
+
+/**
+ * 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 boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Color)) return false;
+ Color color = (Color) object;
+ return device == color.device && (handle & 0xFFFFFF) == (color.handle & 0xFFFFFF);
+}
+
+/**
+ * Returns the amount of blue in the color, from 0 to 255.
+ *
+ * @return the blue component of the color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getBlue () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return (handle & 0xFF0000) >> 16;
+}
+
+/**
+ * Returns the amount of green in the color, from 0 to 255.
+ *
+ * @return the green component of the color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getGreen () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return (handle & 0xFF00) >> 8 ;
+}
+
+/**
+ * Returns the amount of red in the color, from 0 to 255.
+ *
+ * @return the red component of the color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getRed () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return handle & 0xFF;
+}
+
+/**
+ * Returns an <code>RGB</code> representing the receiver.
+ *
+ * @return the RGB for the color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public RGB getRGB () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return new RGB(handle & 0xFF, (handle & 0xFF00) >> 8, (handle & 0xFF0000) >> 16);
+}
+
+/**
+ * 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
+ *
+ * @see #equals
+ */
+public int hashCode () {
+ return handle;
+}
+
+/**
+ * Allocates the operating system resources associated
+ * with the receiver.
+ *
+ * @param device the device on which to allocate the color
+ * @param red the amount of red in the color
+ * @param green the amount of green in the color
+ * @param blue the amount of blue in the color
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the red, green or blue argument is not between 0 and 255</li>
+ * </ul>
+ *
+ * @see #dispose
+ */
+void init(int red, int green, int blue) {
+ if (red > 255 || red < 0 || green > 255 || green < 0 || blue > 255 || blue < 0) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ handle = (red & 0xFF) | ((green & 0xFF) << 8) | ((blue & 0xFF) << 16);
+
+ /* If this is not a palette-based device, return */
+ int /*long*/ hPal = device.hPalette;
+ if (hPal == 0) return;
+
+ int[] colorRefCount = device.colorRefCount;
+ /* Add this color to the default palette now */
+ /* First find out if the color already exists */
+ int index = OS.GetNearestPaletteIndex(hPal, handle);
+ /* See if the nearest color actually is the color */
+ byte[] entry = new byte[4];
+ OS.GetPaletteEntries(hPal, index, 1, entry);
+ if ((entry[0] == (byte)red) && (entry[1] == (byte)green) &&
+ (entry[2] == (byte)blue)) {
+ /* Found the color. Increment the ref count and return */
+ colorRefCount[index]++;
+ return;
+ }
+ /* Didn't find the color, allocate it now. Find the first free entry */
+ int i = 0;
+ while (i < colorRefCount.length) {
+ if (colorRefCount[i] == 0) {
+ index = i;
+ break;
+ }
+ i++;
+ }
+ if (i == colorRefCount.length) {
+ /* No free entries, use the closest one */
+ /* Remake the handle from the actual rgbs */
+ handle = (entry[0] & 0xFF) | ((entry[1] & 0xFF) << 8) |
+ ((entry[2] & 0xFF) << 16);
+ } else {
+ /* Found a free entry */
+ entry = new byte[] { (byte)(red & 0xFF), (byte)(green & 0xFF), (byte)(blue & 0xFF), 0 };
+ OS.SetPaletteEntries(hPal, index, 1, entry);
+ }
+ colorRefCount[index]++;
+}
+
+/**
+ * Returns <code>true</code> if the color has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the color.
+ * When a color has been disposed, it is an error to
+ * invoke any other method using the color.
+ *
+ * @return <code>true</code> when the color is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == -1;
+}
+
+/**
+ * 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 "Color {*DISPOSED*}"; //$NON-NLS-1$
+ return "Color {" + getRed() + ", " + getGreen() + ", " + getBlue() + "}"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new color.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Color</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param handle the handle for the color
+ * @return a new color object containing the specified device and handle
+ */
+public static Color win32_new(Device device, int handle) {
+ Color color = new Color(device);
+ color.handle = handle;
+ return color;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java
new file mode 100755
index 0000000000..6c5273cc22
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Cursor.java
@@ -0,0 +1,460 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class manage operating system resources that
+ * specify the appearance of the on-screen pointer. To create a
+ * cursor you specify the device and either a simple cursor style
+ * describing one of the standard operating system provided cursors
+ * or the image and mask data for the desired appearance.
+ * <p>
+ * Application code must explicitly invoke the <code>Cursor.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>
+ * CURSOR_ARROW, CURSOR_WAIT, CURSOR_CROSS, CURSOR_APPSTARTING, CURSOR_HELP,
+ * CURSOR_SIZEALL, CURSOR_SIZENESW, CURSOR_SIZENS, CURSOR_SIZENWSE, CURSOR_SIZEWE,
+ * CURSOR_SIZEN, CURSOR_SIZES, CURSOR_SIZEE, CURSOR_SIZEW, CURSOR_SIZENE, CURSOR_SIZESE,
+ * CURSOR_SIZESW, CURSOR_SIZENW, CURSOR_UPARROW, CURSOR_IBEAM, CURSOR_NO, CURSOR_HAND
+ * </dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the above styles may be specified.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#cursor">Cursor snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+
+public final class Cursor extends Resource {
+
+ /**
+ * the handle to the OS cursor resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int /*long*/ handle;
+
+ boolean isIcon;
+
+ /**
+ * data used to create a HAND cursor.
+ */
+ static final byte[] HAND_SOURCE = {
+ (byte)0xf9,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xf0,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xf0,(byte)0x3f,(byte)0xff,(byte)0xff,
+ (byte)0xf0,(byte)0x07,(byte)0xff,(byte)0xff,
+ (byte)0xf0,(byte)0x03,(byte)0xff,(byte)0xff,
+ (byte)0xf0,(byte)0x00,(byte)0xff,(byte)0xff,
+
+ (byte)0x10,(byte)0x00,(byte)0x7f,(byte)0xff,
+ (byte)0x00,(byte)0x00,(byte)0x7f,(byte)0xff,
+ (byte)0x80,(byte)0x00,(byte)0x7f,(byte)0xff,
+ (byte)0xc0,(byte)0x00,(byte)0x7f,(byte)0xff,
+ (byte)0xe0,(byte)0x00,(byte)0x7f,(byte)0xff,
+ (byte)0xf0,(byte)0x00,(byte)0x7f,(byte)0xff,
+ (byte)0xf8,(byte)0x00,(byte)0xff,(byte)0xff,
+ (byte)0xfc,(byte)0x01,(byte)0xff,(byte)0xff,
+
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff,
+ (byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff
+ };
+ static final byte[] HAND_MASK = {
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x06,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x06,(byte)0xc0,(byte)0x00,(byte)0x00,
+ (byte)0x06,(byte)0xd8,(byte)0x00,(byte)0x00,
+ (byte)0x06,(byte)0xd8,(byte)0x00,(byte)0x00,
+
+ (byte)0x07,(byte)0xdb,(byte)0x00,(byte)0x00,
+ (byte)0x67,(byte)0xfb,(byte)0x00,(byte)0x00,
+ (byte)0x3f,(byte)0xff,(byte)0x00,(byte)0x00,
+ (byte)0x1f,(byte)0xff,(byte)0x00,(byte)0x00,
+ (byte)0x0f,(byte)0xff,(byte)0x00,(byte)0x00,
+ (byte)0x07,(byte)0xff,(byte)0x00,(byte)0x00,
+ (byte)0x03,(byte)0xfe,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00,
+ (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x00
+ };
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+Cursor(Device device) {
+ super(device);
+}
+
+/**
+ * Constructs a new cursor given a device and a style
+ * constant describing the desired cursor appearance.
+ * <p>
+ * You must dispose the cursor when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the cursor
+ * @param style the style of cursor to allocate
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_INVALID_ARGUMENT - when an unknown style is specified</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
+ * </ul>
+ *
+ * @see SWT#CURSOR_ARROW
+ * @see SWT#CURSOR_WAIT
+ * @see SWT#CURSOR_CROSS
+ * @see SWT#CURSOR_APPSTARTING
+ * @see SWT#CURSOR_HELP
+ * @see SWT#CURSOR_SIZEALL
+ * @see SWT#CURSOR_SIZENESW
+ * @see SWT#CURSOR_SIZENS
+ * @see SWT#CURSOR_SIZENWSE
+ * @see SWT#CURSOR_SIZEWE
+ * @see SWT#CURSOR_SIZEN
+ * @see SWT#CURSOR_SIZES
+ * @see SWT#CURSOR_SIZEE
+ * @see SWT#CURSOR_SIZEW
+ * @see SWT#CURSOR_SIZENE
+ * @see SWT#CURSOR_SIZESE
+ * @see SWT#CURSOR_SIZESW
+ * @see SWT#CURSOR_SIZENW
+ * @see SWT#CURSOR_UPARROW
+ * @see SWT#CURSOR_IBEAM
+ * @see SWT#CURSOR_NO
+ * @see SWT#CURSOR_HAND
+ */
+public Cursor(Device device, int style) {
+ super(device);
+ int /*long*/ lpCursorName = 0;
+ switch (style) {
+ case SWT.CURSOR_HAND: lpCursorName = OS.IDC_HAND; break;
+ case SWT.CURSOR_ARROW: lpCursorName = OS.IDC_ARROW; break;
+ case SWT.CURSOR_WAIT: lpCursorName = OS.IDC_WAIT; break;
+ case SWT.CURSOR_CROSS: lpCursorName = OS.IDC_CROSS; break;
+ case SWT.CURSOR_APPSTARTING: lpCursorName = OS.IDC_APPSTARTING; break;
+ case SWT.CURSOR_HELP: lpCursorName = OS.IDC_HELP; break;
+ case SWT.CURSOR_SIZEALL: lpCursorName = OS.IDC_SIZEALL; break;
+ case SWT.CURSOR_SIZENESW: lpCursorName = OS.IDC_SIZENESW; break;
+ case SWT.CURSOR_SIZENS: lpCursorName = OS.IDC_SIZENS; break;
+ case SWT.CURSOR_SIZENWSE: lpCursorName = OS.IDC_SIZENWSE; break;
+ case SWT.CURSOR_SIZEWE: lpCursorName = OS.IDC_SIZEWE; break;
+ case SWT.CURSOR_SIZEN: lpCursorName = OS.IDC_SIZENS; break;
+ case SWT.CURSOR_SIZES: lpCursorName = OS.IDC_SIZENS; break;
+ case SWT.CURSOR_SIZEE: lpCursorName = OS.IDC_SIZEWE; break;
+ case SWT.CURSOR_SIZEW: lpCursorName = OS.IDC_SIZEWE; break;
+ case SWT.CURSOR_SIZENE: lpCursorName = OS.IDC_SIZENESW; break;
+ case SWT.CURSOR_SIZESE: lpCursorName = OS.IDC_SIZENWSE; break;
+ case SWT.CURSOR_SIZESW: lpCursorName = OS.IDC_SIZENESW; break;
+ case SWT.CURSOR_SIZENW: lpCursorName = OS.IDC_SIZENWSE; break;
+ case SWT.CURSOR_UPARROW: lpCursorName = OS.IDC_UPARROW; break;
+ case SWT.CURSOR_IBEAM: lpCursorName = OS.IDC_IBEAM; break;
+ case SWT.CURSOR_NO: lpCursorName = OS.IDC_NO; break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ handle = OS.LoadCursor(0, lpCursorName);
+ /*
+ * IDC_HAND is supported only on Windows 2000 and Windows 98.
+ * Create a hand cursor if running in other Windows platforms.
+ */
+ if (handle == 0 && style == SWT.CURSOR_HAND) {
+ int width = OS.GetSystemMetrics(OS.SM_CXCURSOR);
+ int height = OS.GetSystemMetrics(OS.SM_CYCURSOR);
+ if (width == 32 && height == 32) {
+ int /*long*/ hInst = OS.GetModuleHandle(null);
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ handle = OS.CreateCursor(hInst, 5, 0, 32, 32, HAND_SOURCE, HAND_MASK);
+
+ }
+ }
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+}
+
+/**
+ * Constructs a new cursor given a device, image and mask
+ * data describing the desired cursor appearance, and the x
+ * and y coordinates of the <em>hotspot</em> (that is, the point
+ * within the area covered by the cursor which is considered
+ * to be where the on-screen pointer is "pointing").
+ * <p>
+ * The mask data is allowed to be null, but in this case the source
+ * must be an ImageData representing an icon that specifies both
+ * color data and mask data.
+ * <p>
+ * You must dispose the cursor when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the cursor
+ * @param source the color data for the cursor
+ * @param mask the mask data for the cursor (or null)
+ * @param hotspotX the x coordinate of the cursor's hotspot
+ * @param hotspotY the y coordinate of the cursor's hotspot
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the source is null</li>
+ * <li>ERROR_NULL_ARGUMENT - if the mask is null and the source does not have a mask</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the source and the mask are not the same
+ * size, or if the hotspot is outside the bounds of the image</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
+ * </ul>
+ */
+public Cursor(Device device, ImageData source, ImageData mask, int hotspotX, int hotspotY) {
+ super(device);
+ if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (mask == null) {
+ if (source.getTransparencyType() != SWT.TRANSPARENCY_MASK) {
+ SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ }
+ mask = source.getTransparencyMask();
+ }
+ /* Check the bounds. Mask must be the same size as source */
+ if (mask.width != source.width || mask.height != source.height) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ /* Check the hotspots */
+ if (hotspotX >= source.width || hotspotX < 0 ||
+ hotspotY >= source.height || hotspotY < 0) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ /* Convert depth to 1 */
+ mask = ImageData.convertMask(mask);
+ source = ImageData.convertMask(source);
+
+ /* Make sure source and mask scanline pad is 2 */
+ byte[] sourceData = ImageData.convertPad(source.data, source.width, source.height, source.depth, source.scanlinePad, 2);
+ byte[] maskData = ImageData.convertPad(mask.data, mask.width, mask.height, mask.depth, mask.scanlinePad, 2);
+
+ /* Create the cursor */
+ int /*long*/ hInst = OS.GetModuleHandle(null);
+ if (OS.IsWinCE) SWT.error (SWT.ERROR_NOT_IMPLEMENTED);
+ handle = OS.CreateCursor(hInst, hotspotX, hotspotY, source.width, source.height, sourceData, maskData);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+}
+
+/**
+ * Constructs a new cursor given a device, image data describing
+ * the desired cursor appearance, and the x and y coordinates of
+ * the <em>hotspot</em> (that is, the point within the area
+ * covered by the cursor which is considered to be where the
+ * on-screen pointer is "pointing").
+ * <p>
+ * You must dispose the cursor when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the cursor
+ * @param source the image data for the cursor
+ * @param hotspotX the x coordinate of the cursor's hotspot
+ * @param hotspotY the y coordinate of the cursor's hotspot
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the image is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the hotspot is outside the bounds of the
+ * image</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a handle could not be obtained for cursor creation</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public Cursor(Device device, ImageData source, int hotspotX, int hotspotY) {
+ super(device);
+ if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ /* Check the hotspots */
+ if (hotspotX >= source.width || hotspotX < 0 ||
+ hotspotY >= source.height || hotspotY < 0) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ ImageData mask = source.getTransparencyMask();
+ int /*long*/ [] result = Image.init(this.device, null, source, mask);
+ int /*long*/ hBitmap = result[0];
+ int /*long*/ hMask = result[1];
+ /* Create the icon */
+ ICONINFO info = new ICONINFO();
+ info.fIcon = false;
+ info.hbmColor = hBitmap;
+ info.hbmMask = hMask;
+ info.xHotspot = hotspotX;
+ info.yHotspot = hotspotY;
+ handle = OS.CreateIconIndirect(info);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.DeleteObject(hBitmap);
+ OS.DeleteObject(hMask);
+ isIcon = true;
+ init();
+}
+
+void destroy () {
+ /*
+ * It is an error in Windows to destroy the current
+ * cursor. Check that the cursor that is about to
+ * be destroyed is the current cursor. If so, set
+ * the current cursor to be IDC_ARROW. Note that
+ * Windows shares predefined cursors so the call to
+ * LoadCursor() does not leak.
+ */
+ // TEMPORARY CODE
+// if (OS.GetCursor() == handle) {
+// OS.SetCursor(OS.LoadCursor(0, OS.IDC_ARROW));
+// }
+
+ if (isIcon) {
+ OS.DestroyIcon(handle);
+ } else {
+ /*
+ * The MSDN states that one should not destroy a shared
+ * cursor, that is, one obtained from LoadCursor.
+ * However, it does not appear to do any harm, so rather
+ * than keep track of how a cursor was created, we just
+ * destroy them all. If this causes problems in the future,
+ * put the flag back in.
+ */
+ if (!OS.IsWinCE) OS.DestroyCursor(handle);
+ }
+ handle = 0;
+}
+
+/**
+ * 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 boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Cursor)) return false;
+ Cursor cursor = (Cursor) object;
+ return device == cursor.device && handle == cursor.handle;
+}
+
+/**
+ * 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
+ *
+ * @see #equals
+ */
+public int hashCode () {
+ return (int)/*64*/handle;
+}
+
+/**
+ * Returns <code>true</code> if the cursor has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the cursor.
+ * When a cursor has been disposed, it is an error to
+ * invoke any other method using the cursor.
+ *
+ * @return <code>true</code> when the cursor is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * 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 "Cursor {*DISPOSED*}";
+ return "Cursor {" + handle + "}";
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new cursor.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Cursor</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param handle the handle for the cursor
+ * @return a new cursor object containing the specified device and handle
+ */
+public static Cursor win32_new(Device device, int handle) {
+ Cursor cursor = new Cursor(device);
+ cursor.handle = handle;
+ return cursor;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Device.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Device.java
new file mode 100755
index 0000000000..7745d9088a
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Device.java
@@ -0,0 +1,972 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+
+/**
+ * This class is the abstract superclass of all device objects,
+ * such as the Display device and the Printer device. Devices
+ * can have a graphics context (GC) created for them, and they
+ * can be drawn on by sending messages to the associated GC.
+ *
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public abstract class Device implements Drawable {
+
+ /* Debugging */
+ public static boolean DEBUG;
+ boolean debug = DEBUG;
+ boolean tracking = DEBUG;
+ Error [] errors;
+ Object [] objects;
+ Object trackingLock;
+
+ /**
+ * Palette
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int /*long*/ hPalette = 0;
+ int [] colorRefCount;
+
+ /* System Font */
+ Font systemFont;
+
+ /* Font Enumeration */
+ int nFonts = 256;
+ LOGFONT [] logFonts;
+ TEXTMETRIC metrics;
+ int[] pixels;
+
+ /* Scripts */
+ int /*long*/ [] scripts;
+
+ /* Advanced Graphics */
+ int /*long*/ [] gdipToken;
+ int /*long*/ fontCollection;
+ String[] loadedFonts;
+
+ boolean disposed;
+
+ /*
+ * TEMPORARY CODE. When a graphics object is
+ * created and the device parameter is null,
+ * the current Display is used. This presents
+ * a problem because SWT graphics does not
+ * reference classes in SWT widgets. The correct
+ * fix is to remove this feature. Unfortunately,
+ * too many application programs rely on this
+ * feature.
+ */
+ protected static Device CurrentDevice;
+ protected static Runnable DeviceFinder;
+ static {
+ try {
+ Class.forName ("org.eclipse.swt.widgets.Display"); //$NON-NLS-1$
+ } catch (ClassNotFoundException e) {}
+ }
+
+/*
+* TEMPORARY CODE.
+*/
+static synchronized Device getDevice () {
+ if (DeviceFinder != null) DeviceFinder.run();
+ Device device = CurrentDevice;
+ CurrentDevice = null;
+ return device;
+}
+
+/**
+ * Constructs a new instance of this class.
+ * <p>
+ * You must dispose the device when it is no longer required.
+ * </p>
+ *
+ * @see #create
+ * @see #init
+ *
+ * @since 3.1
+ */
+public Device() {
+ this(null);
+}
+
+/**
+ * Constructs a new instance of this class.
+ * <p>
+ * You must dispose the device when it is no longer required.
+ * </p>
+ *
+ * @param data the DeviceData which describes the receiver
+ *
+ * @see #create
+ * @see #init
+ * @see DeviceData
+ */
+public Device(DeviceData data) {
+ synchronized (Device.class) {
+ if (data != null) {
+ debug = data.debug;
+ tracking = data.tracking;
+ }
+ if (tracking) {
+ errors = new Error [128];
+ objects = new Object [128];
+ trackingLock = new Object ();
+ }
+ create (data);
+ init ();
+ }
+}
+
+void addFont (String font) {
+ if (loadedFonts == null) loadedFonts = new String [4];
+ int length = loadedFonts.length;
+ for (int i=0; i<length; i++) {
+ if (font.equals(loadedFonts [i])) return;
+ }
+ int index = 0;
+ while (index < length) {
+ if (loadedFonts [index] == null) break;
+ index++;
+ }
+ if (index == length) {
+ String [] temp = new String [length + 4];
+ System.arraycopy (loadedFonts, 0, temp, 0, length);
+ loadedFonts = temp;
+ }
+ loadedFonts [index] = font;
+}
+
+/**
+ * Throws an <code>SWTException</code> if the receiver can not
+ * be accessed by the caller. This may include both checks on
+ * the state of the receiver and more generally on the entire
+ * execution context. This method <em>should</em> be called by
+ * device implementors to enforce the standard SWT invariants.
+ * <p>
+ * Currently, it is an error to invoke any method (other than
+ * <code>isDisposed()</code> and <code>dispose()</code>) on a
+ * device that has had its <code>dispose()</code> method called.
+ * </p><p>
+ * In future releases of SWT, there may be more or fewer error
+ * checks and exceptions may be thrown for different reasons.
+ * <p>
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+protected void checkDevice () {
+ if (disposed) SWT.error(SWT.ERROR_DEVICE_DISPOSED);
+}
+
+void checkGDIP() {
+ if (gdipToken != null) return;
+ int oldErrorMode = 0;
+ if (!OS.IsWinCE) oldErrorMode = OS.SetErrorMode (OS.SEM_FAILCRITICALERRORS);
+ try {
+ int /*long*/ [] token = new int /*long*/ [1];
+ GdiplusStartupInput input = new GdiplusStartupInput ();
+ input.GdiplusVersion = 1;
+ if (Gdip.GdiplusStartup (token, input, 0) == 0) {
+ gdipToken = token;
+ if (loadedFonts != null) {
+ fontCollection = Gdip.PrivateFontCollection_new();
+ if (fontCollection == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ for (int i = 0; i < loadedFonts.length; i++) {
+ String path = loadedFonts[i];
+ if (path == null) break;
+ int length = path.length();
+ char [] buffer = new char [length + 1];
+ path.getChars(0, length, buffer, 0);
+ Gdip.PrivateFontCollection_AddFontFile(fontCollection, buffer);
+ }
+ loadedFonts = null;
+ }
+ }
+ } catch (Throwable t) {
+ SWT.error (SWT.ERROR_NO_GRAPHICS_LIBRARY, t, " [GDI+ is required]"); //$NON-NLS-1$
+ } finally {
+ if (!OS.IsWinCE) OS.SetErrorMode (oldErrorMode);
+ }
+}
+
+/**
+ * Creates the device in the operating system. If the device
+ * does not have a handle, this method may do nothing depending
+ * on the device.
+ * <p>
+ * This method is called before <code>init</code>.
+ * </p><p>
+ * Subclasses are supposed to reimplement this method and not
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @param data the DeviceData which describes the receiver
+ *
+ * @see #init
+ */
+protected void create (DeviceData data) {
+}
+
+int computePixels(float height) {
+ int /*long*/ hDC = internal_new_GC (null);
+ int pixels = -(int)(0.5f + (height * OS.GetDeviceCaps(hDC, OS.LOGPIXELSY) / 72f));
+ internal_dispose_GC (hDC, null);
+ return pixels;
+}
+
+float computePoints(LOGFONT logFont, int /*long*/ hFont) {
+ int /*long*/ hDC = internal_new_GC (null);
+ int logPixelsY = OS.GetDeviceCaps(hDC, OS.LOGPIXELSY);
+ int pixels = 0;
+ if (logFont.lfHeight > 0) {
+ /*
+ * Feature in Windows. If the lfHeight of the LOGFONT structure
+ * is positive, the lfHeight measures the height of the entire
+ * cell, including internal leading, in logical units. Since the
+ * height of a font in points does not include the internal leading,
+ * we must subtract the internal leading, which requires a TEXTMETRIC.
+ */
+ int /*long*/ oldFont = OS.SelectObject(hDC, hFont);
+ TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
+ OS.GetTextMetrics(hDC, lptm);
+ OS.SelectObject(hDC, oldFont);
+ pixels = logFont.lfHeight - lptm.tmInternalLeading;
+ } else {
+ pixels = -logFont.lfHeight;
+ }
+ internal_dispose_GC (hDC, null);
+ return pixels * 72f / logPixelsY;
+}
+
+/**
+ * Destroys the device in the operating system and releases
+ * the device's handle. If the device does not have a handle,
+ * this method may do nothing depending on the device.
+ * <p>
+ * This method is called after <code>release</code>.
+ * </p><p>
+ * Subclasses are supposed to reimplement this method and not
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @see #dispose
+ * @see #release
+ */
+protected void destroy () {
+}
+
+/**
+ * Disposes of the operating system resources associated with
+ * the receiver. After this method has been invoked, the receiver
+ * will answer <code>true</code> when sent the message
+ * <code>isDisposed()</code>.
+ *
+ * @see #release
+ * @see #destroy
+ * @see #checkDevice
+ */
+public void dispose () {
+ synchronized (Device.class) {
+ if (isDisposed()) return;
+ checkDevice ();
+ release ();
+ destroy ();
+ disposed = true;
+ if (tracking) {
+ synchronized (trackingLock) {
+ printErrors ();
+ objects = null;
+ errors = null;
+ trackingLock = null;
+ }
+ }
+ }
+}
+
+void dispose_Object (Object object) {
+ synchronized (trackingLock) {
+ for (int i=0; i<objects.length; i++) {
+ if (objects [i] == object) {
+ objects [i] = null;
+ errors [i] = null;
+ return;
+ }
+ }
+ }
+}
+
+int /*long*/ EnumFontFamProc (int /*long*/ lpelfe, int /*long*/ lpntme, int /*long*/ FontType, int /*long*/ lParam) {
+ boolean isScalable = ((int)/*64*/FontType & OS.RASTER_FONTTYPE) == 0;
+ boolean scalable = lParam == 1;
+ if (isScalable == scalable) {
+ /* Add the log font to the list of log fonts */
+ if (nFonts == logFonts.length) {
+ LOGFONT [] newLogFonts = new LOGFONT [logFonts.length + 128];
+ System.arraycopy (logFonts, 0, newLogFonts, 0, nFonts);
+ logFonts = newLogFonts;
+ int[] newPixels = new int[newLogFonts.length];
+ System.arraycopy (pixels, 0, newPixels, 0, nFonts);
+ pixels = newPixels;
+ }
+ LOGFONT logFont = logFonts [nFonts];
+ if (logFont == null) logFont = OS.IsUnicode ? (LOGFONT)new LOGFONTW () : new LOGFONTA ();
+ OS.MoveMemory (logFont, lpelfe, LOGFONT.sizeof);
+ logFonts [nFonts] = logFont;
+ if (logFont.lfHeight > 0) {
+ /*
+ * Feature in Windows. If the lfHeight of the LOGFONT structure
+ * is positive, the lfHeight measures the height of the entire
+ * cell, including internal leading, in logical units. Since the
+ * height of a font in points does not include the internal leading,
+ * we must subtract the internal leading, which requires a TEXTMETRIC,
+ * which in turn requires font creation.
+ */
+ OS.MoveMemory(metrics, lpntme, TEXTMETRIC.sizeof);
+ pixels[nFonts] = logFont.lfHeight - metrics.tmInternalLeading;
+ } else {
+ pixels[nFonts] = -logFont.lfHeight;
+ }
+ nFonts++;
+ }
+ return 1;
+}
+
+/**
+ * Returns a rectangle describing the receiver's size and location.
+ *
+ * @return the bounding rectangle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getBounds () {
+ checkDevice ();
+ int /*long*/ hDC = internal_new_GC (null);
+ int width = OS.GetDeviceCaps (hDC, OS.HORZRES);
+ int height = OS.GetDeviceCaps (hDC, OS.VERTRES);
+ internal_dispose_GC (hDC, null);
+ return new Rectangle (0, 0, width, height);
+}
+
+/**
+ * Returns a <code>DeviceData</code> based on the receiver.
+ * Modifications made to this <code>DeviceData</code> will not
+ * affect the receiver.
+ *
+ * @return a <code>DeviceData</code> containing the device's data and attributes
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see DeviceData
+ */
+public DeviceData getDeviceData () {
+ checkDevice();
+ DeviceData data = new DeviceData ();
+ data.debug = debug;
+ data.tracking = tracking;
+ if (tracking) {
+ synchronized (trackingLock) {
+ int count = 0, length = objects.length;
+ for (int i=0; i<length; i++) {
+ if (objects [i] != null) count++;
+ }
+ int index = 0;
+ data.objects = new Object [count];
+ data.errors = new Error [count];
+ for (int i=0; i<length; i++) {
+ if (objects [i] != null) {
+ data.objects [index] = objects [i];
+ data.errors [index] = errors [i];
+ index++;
+ }
+ }
+ }
+ } else {
+ data.objects = new Object [0];
+ data.errors = new Error [0];
+ }
+ return data;
+}
+
+/**
+ * Returns a rectangle which describes the area of the
+ * receiver which is capable of displaying data.
+ *
+ * @return the client area
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getBounds
+ */
+public Rectangle getClientArea () {
+ return getBounds ();
+}
+
+/**
+ * Returns the bit depth of the screen, which is the number of
+ * bits it takes to represent the number of unique colors that
+ * the screen is currently capable of displaying. This number
+ * will typically be one of 1, 8, 15, 16, 24 or 32.
+ *
+ * @return the depth of the screen
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getDepth () {
+ checkDevice ();
+ int /*long*/ hDC = internal_new_GC (null);
+ int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL);
+ int planes = OS.GetDeviceCaps (hDC, OS.PLANES);
+ internal_dispose_GC (hDC, null);
+ return bits * planes;
+}
+
+/**
+ * Returns a point whose x coordinate is the horizontal
+ * dots per inch of the display, and whose y coordinate
+ * is the vertical dots per inch of the display.
+ *
+ * @return the horizontal and vertical DPI
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point getDPI () {
+ checkDevice ();
+ int /*long*/ hDC = internal_new_GC (null);
+ int dpiX = OS.GetDeviceCaps (hDC, OS.LOGPIXELSX);
+ int dpiY = OS.GetDeviceCaps (hDC, OS.LOGPIXELSY);
+ internal_dispose_GC (hDC, null);
+ return new Point (dpiX, dpiY);
+}
+
+/**
+ * Returns <code>FontData</code> objects which describe
+ * the fonts that match the given arguments. If the
+ * <code>faceName</code> is null, all fonts will be returned.
+ *
+ * @param faceName the name of the font to look for, or null
+ * @param scalable if true only scalable fonts are returned, otherwise only non-scalable fonts are returned.
+ * @return the matching font data
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontData [] getFontList (String faceName, boolean scalable) {
+ checkDevice ();
+
+ /* Create the callback */
+ Callback callback = new Callback (this, "EnumFontFamProc", 4); //$NON-NLS-1$
+ int /*long*/ lpEnumFontFamProc = callback.getAddress ();
+ if (lpEnumFontFamProc == 0) SWT.error (SWT.ERROR_NO_MORE_CALLBACKS);
+
+ /* Initialize the instance variables */
+ metrics = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
+ pixels = new int[nFonts];
+ logFonts = new LOGFONT [nFonts];
+ for (int i=0; i<logFonts.length; i++) {
+ logFonts [i] = OS.IsUnicode ? (LOGFONT) new LOGFONTW () : new LOGFONTA ();
+ }
+ nFonts = 0;
+
+ /* Enumerate */
+ int offset = 0;
+ int /*long*/ hDC = internal_new_GC (null);
+ if (faceName == null) {
+ /* The user did not specify a face name, so they want all versions of all available face names */
+ OS.EnumFontFamilies (hDC, null, lpEnumFontFamProc, scalable ? 1 : 0);
+
+ /**
+ * For bitmapped fonts, EnumFontFamilies only enumerates once for each font, regardless
+ * of how many styles are available. If the user wants bitmapped fonts, enumerate on
+ * each face name now.
+ */
+ offset = nFonts;
+ for (int i=0; i<offset; i++) {
+ LOGFONT lf = logFonts [i];
+ /**
+ * Bug in Windows 98. When EnumFontFamiliesEx is called with a specified face name, it
+ * should enumerate for each available style of that font. Instead, it only enumerates
+ * once. The fix is to call EnumFontFamilies, which works as expected.
+ */
+ if (OS.IsUnicode) {
+ OS.EnumFontFamiliesW (hDC, ((LOGFONTW)lf).lfFaceName, lpEnumFontFamProc, scalable ? 1 : 0);
+ } else {
+ OS.EnumFontFamiliesA (hDC, ((LOGFONTA)lf).lfFaceName, lpEnumFontFamProc, scalable ? 1 : 0);
+ }
+ }
+ } else {
+ /* Use the character encoding for the default locale */
+ TCHAR lpFaceName = new TCHAR (0, faceName, true);
+ /**
+ * Bug in Windows 98. When EnumFontFamiliesEx is called with a specified face name, it
+ * should enumerate for each available style of that font. Instead, it only enumerates
+ * once. The fix is to call EnumFontFamilies, which works as expected.
+ */
+ OS.EnumFontFamilies (hDC, lpFaceName, lpEnumFontFamProc, scalable ? 1 : 0);
+ }
+ int logPixelsY = OS.GetDeviceCaps(hDC, OS.LOGPIXELSY);
+ internal_dispose_GC (hDC, null);
+
+ /* Create the fontData from the logfonts */
+ int count = 0;
+ FontData [] result = new FontData [nFonts - offset];
+ for (int i=offset; i<nFonts; i++) {
+ FontData fd = FontData.win32_new (logFonts [i], pixels [i] * 72f / logPixelsY);
+ int j;
+ for (j = 0; j < count; j++) {
+ if (fd.equals (result [j])) break;
+ }
+ if (j == count) result [count++] = fd;
+ }
+ if (count != result.length) {
+ FontData [] newResult = new FontData [count];
+ System.arraycopy (result, 0, newResult, 0, count);
+ result = newResult;
+ }
+
+ /* Clean up */
+ callback.dispose ();
+ logFonts = null;
+ pixels = null;
+ metrics = null;
+ return result;
+}
+
+String getLastError () {
+ int error = OS.GetLastError();
+ if (error == 0) return ""; //$NON-NLS-1$
+ return " [GetLastError=0x" + Integer.toHexString(error) + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+}
+
+String getLastErrorText () {
+ int error = OS.GetLastError();
+ if (error == 0) return ""; //$NON-NLS-1$
+ int /*long*/ [] buffer = new int /*long*/ [1];
+ int dwFlags = OS.FORMAT_MESSAGE_ALLOCATE_BUFFER | OS.FORMAT_MESSAGE_FROM_SYSTEM | OS.FORMAT_MESSAGE_IGNORE_INSERTS;
+ int length = OS.FormatMessage(dwFlags, 0, error, OS.LANG_USER_DEFAULT, buffer, 0, 0);
+ if (length == 0) return " [GetLastError=0x" + Integer.toHexString(error) + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ TCHAR buffer1 = new TCHAR(0, length);
+ OS.MoveMemory(buffer1, buffer[0], length * TCHAR.sizeof);
+ if (buffer[0] != 0) OS.LocalFree(buffer[0]);
+ return buffer1.toString(0, length);
+}
+
+/**
+ * Returns the matching standard color for the given
+ * constant, which should be one of the color constants
+ * specified in class <code>SWT</code>. Any value other
+ * than one of the SWT color constants which is passed
+ * in will result in the color black. This color should
+ * not be freed because it was allocated by the system,
+ * not the application.
+ *
+ * @param id the color constant
+ * @return the matching color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see SWT
+ */
+public Color getSystemColor (int id) {
+ checkDevice ();
+ int pixel = 0x00000000;
+ switch (id) {
+ case SWT.COLOR_WHITE: pixel = 0x00FFFFFF; break;
+ case SWT.COLOR_BLACK: pixel = 0x00000000; break;
+ case SWT.COLOR_RED: pixel = 0x000000FF; break;
+ case SWT.COLOR_DARK_RED: pixel = 0x00000080; break;
+ case SWT.COLOR_GREEN: pixel = 0x0000FF00; break;
+ case SWT.COLOR_DARK_GREEN: pixel = 0x00008000; break;
+ case SWT.COLOR_YELLOW: pixel = 0x0000FFFF; break;
+ case SWT.COLOR_DARK_YELLOW: pixel = 0x00008080; break;
+ case SWT.COLOR_BLUE: pixel = 0x00FF0000; break;
+ case SWT.COLOR_DARK_BLUE: pixel = 0x00800000; break;
+ case SWT.COLOR_MAGENTA: pixel = 0x00FF00FF; break;
+ case SWT.COLOR_DARK_MAGENTA: pixel = 0x00800080; break;
+ case SWT.COLOR_CYAN: pixel = 0x00FFFF00; break;
+ case SWT.COLOR_DARK_CYAN: pixel = 0x00808000; break;
+ case SWT.COLOR_GRAY: pixel = 0x00C0C0C0; break;
+ case SWT.COLOR_DARK_GRAY: pixel = 0x00808080; break;
+ }
+ return Color.win32_new (this, pixel);
+}
+
+/**
+ * Returns a reasonable font for applications to use.
+ * On some platforms, this will match the "default font"
+ * or "system font" if such can be found. This font
+ * should not be freed because it was allocated by the
+ * system, not the application.
+ * <p>
+ * Typically, applications which want the default look
+ * should simply not set the font on the widgets they
+ * create. Widgets are always created with the correct
+ * default font for the class of user-interface component
+ * they represent.
+ * </p>
+ *
+ * @return a font
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Font getSystemFont () {
+ checkDevice ();
+ int /*long*/ hFont = OS.GetStockObject (OS.SYSTEM_FONT);
+ return Font.win32_new (this, hFont);
+}
+
+/**
+ * Returns <code>true</code> if the underlying window system prints out
+ * warning messages on the console, and <code>setWarnings</code>
+ * had previously been called with <code>true</code>.
+ *
+ * @return <code>true</code>if warnings are being handled, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean getWarnings () {
+ checkDevice ();
+ return false;
+}
+
+/**
+ * Initializes any internal resources needed by the
+ * device.
+ * <p>
+ * This method is called after <code>create</code>.
+ * </p><p>
+ * If subclasses reimplement this method, they must
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @see #create
+ */
+protected void init () {
+ if (debug) {
+ if (!OS.IsWinCE) OS.GdiSetBatchLimit(1);
+ }
+
+ /* Initialize the system font slot */
+ systemFont = getSystemFont();
+
+ /* Initialize scripts list */
+ if (!OS.IsWinCE) {
+ int /*long*/ [] ppSp = new int /*long*/ [1];
+ int [] piNumScripts = new int [1];
+ OS.ScriptGetProperties (ppSp, piNumScripts);
+ scripts = new int /*long*/ [piNumScripts [0]];
+ OS.MoveMemory (scripts, ppSp [0], scripts.length * OS.PTR_SIZEOF);
+ }
+
+ /*
+ * If we're not on a device which supports palettes,
+ * don't create one.
+ */
+ int /*long*/ hDC = internal_new_GC (null);
+ int rc = OS.GetDeviceCaps (hDC, OS.RASTERCAPS);
+ int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL);
+ int planes = OS.GetDeviceCaps (hDC, OS.PLANES);
+
+ bits *= planes;
+ if ((rc & OS.RC_PALETTE) == 0 || bits != 8) {
+ internal_dispose_GC (hDC, null);
+ return;
+ }
+
+ int numReserved = OS.GetDeviceCaps (hDC, OS.NUMRESERVED);
+ int numEntries = OS.GetDeviceCaps (hDC, OS.SIZEPALETTE);
+
+ if (OS.IsWinCE) {
+ /*
+ * Feature on WinCE. For some reason, certain 8 bit WinCE
+ * devices return 0 for the number of reserved entries in
+ * the system palette. Their system palette correctly contains
+ * the usual 20 system colors. The workaround is to assume
+ * there are 20 reserved system colors instead of 0.
+ */
+ if (numReserved == 0 && numEntries >= 20) numReserved = 20;
+ }
+
+ /* Create the palette and reference counter */
+ colorRefCount = new int [numEntries];
+
+ /* 4 bytes header + 4 bytes per entry * numEntries entries */
+ byte [] logPalette = new byte [4 + 4 * numEntries];
+
+ /* 2 bytes = special header */
+ logPalette [0] = 0x00;
+ logPalette [1] = 0x03;
+
+ /* 2 bytes = number of colors, LSB first */
+ logPalette [2] = 0;
+ logPalette [3] = 1;
+
+ /*
+ * Create a palette which contains the system entries
+ * as they are located in the system palette. The
+ * MSDN article 'Memory Device Contexts' describes
+ * where system entries are located. On an 8 bit
+ * display with 20 reserved colors, the system colors
+ * will be the first 10 entries and the last 10 ones.
+ */
+ byte[] lppe = new byte [4 * numEntries];
+ OS.GetSystemPaletteEntries (hDC, 0, numEntries, lppe);
+ /* Copy all entries from the system palette */
+ System.arraycopy (lppe, 0, logPalette, 4, 4 * numEntries);
+ /* Lock the indices corresponding to the system entries */
+ for (int i = 0; i < numReserved / 2; i++) {
+ colorRefCount [i] = 1;
+ colorRefCount [numEntries - 1 - i] = 1;
+ }
+ internal_dispose_GC (hDC, null);
+ hPalette = OS.CreatePalette (logPalette);
+}
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Device</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param data the platform specific GC data
+ * @return the platform specific GC handle
+ */
+public abstract int /*long*/ internal_new_GC (GCData data);
+
+/**
+ * Invokes platform specific functionality to dispose a GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Device</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param hDC the platform specific GC handle
+ * @param data the platform specific GC data
+ */
+public abstract void /*long*/ internal_dispose_GC (int /*long*/ hDC, GCData data);
+
+/**
+ * Returns <code>true</code> if the device has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the device.
+ * When a device has been disposed, it is an error to
+ * invoke any other method using the device.
+ *
+ * @return <code>true</code> when the device is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed () {
+ synchronized (Device.class) {
+ return disposed;
+ }
+}
+
+/**
+ * Loads the font specified by a file. The font will be
+ * present in the list of fonts available to the application.
+ *
+ * @param path the font file path
+ * @return whether the font was successfully loaded
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if path is null</li>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Font
+ *
+ * @since 3.3
+ */
+public boolean loadFont (String path) {
+ checkDevice();
+ if (path == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (OS.IsWinNT && OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
+ TCHAR lpszFilename = new TCHAR (0, path, true);
+ boolean loaded = OS.AddFontResourceEx (lpszFilename, OS.FR_PRIVATE, 0) != 0;
+ if (loaded) {
+ if (gdipToken != null) {
+ if (fontCollection == 0) {
+ fontCollection = Gdip.PrivateFontCollection_new();
+ if (fontCollection == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+ int length = path.length();
+ char [] buffer = new char [length + 1];
+ path.getChars(0, length, buffer, 0);
+ Gdip.PrivateFontCollection_AddFontFile(fontCollection, buffer);
+ } else {
+ addFont(path);
+ }
+ }
+ return loaded;
+ }
+ return false;
+}
+
+void new_Object (Object object) {
+ synchronized (trackingLock) {
+ for (int i=0; i<objects.length; i++) {
+ if (objects [i] == null) {
+ objects [i] = object;
+ errors [i] = new Error ();
+ return;
+ }
+ }
+ Object [] newObjects = new Object [objects.length + 128];
+ System.arraycopy (objects, 0, newObjects, 0, objects.length);
+ newObjects [objects.length] = object;
+ objects = newObjects;
+ Error [] newErrors = new Error [errors.length + 128];
+ System.arraycopy (errors, 0, newErrors, 0, errors.length);
+ newErrors [errors.length] = new Error ();
+ errors = newErrors;
+ }
+}
+
+void printErrors () {
+ if (!DEBUG) return;
+ if (tracking) {
+ synchronized (trackingLock) {
+ if (objects == null || errors == null) return;
+ int objectCount = 0;
+ int colors = 0, cursors = 0, fonts = 0, gcs = 0, images = 0;
+ int paths = 0, patterns = 0, regions = 0, textLayouts = 0, transforms = 0;
+ for (int i=0; i<objects.length; i++) {
+ Object object = objects [i];
+ if (object != null) {
+ objectCount++;
+ if (object instanceof Color) colors++;
+ if (object instanceof Cursor) cursors++;
+ if (object instanceof Font) fonts++;
+ if (object instanceof GC) gcs++;
+ if (object instanceof Image) images++;
+ if (object instanceof Path) paths++;
+ if (object instanceof Pattern) patterns++;
+ if (object instanceof Region) regions++;
+ if (object instanceof TextLayout) textLayouts++;
+ if (object instanceof Transform) transforms++;
+ }
+ }
+ if (objectCount != 0) {
+ String string = "Summary: ";
+ if (colors != 0) string += colors + " Color(s), ";
+ if (cursors != 0) string += cursors + " Cursor(s), ";
+ if (fonts != 0) string += fonts + " Font(s), ";
+ if (gcs != 0) string += gcs + " GC(s), ";
+ if (images != 0) string += images + " Image(s), ";
+ if (paths != 0) string += paths + " Path(s), ";
+ if (patterns != 0) string += patterns + " Pattern(s), ";
+ if (regions != 0) string += regions + " Region(s), ";
+ if (textLayouts != 0) string += textLayouts + " TextLayout(s), ";
+ if (transforms != 0) string += transforms + " Transforms(s), ";
+ if (string.length () != 0) {
+ string = string.substring (0, string.length () - 2);
+ System.err.println (string);
+ }
+ for (int i=0; i<errors.length; i++) {
+ if (errors [i] != null) errors [i].printStackTrace (System.err);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Releases any internal resources back to the operating
+ * system and clears all fields except the device handle.
+ * <p>
+ * When a device is destroyed, resources that were acquired
+ * on behalf of the programmer need to be returned to the
+ * operating system. For example, if the device allocated a
+ * font to be used as the system font, this font would be
+ * freed in <code>release</code>. Also,to assist the garbage
+ * collector and minimize the amount of memory that is not
+ * reclaimed when the programmer keeps a reference to a
+ * disposed device, all fields except the handle are zero'd.
+ * The handle is needed by <code>destroy</code>.
+ * </p>
+ * This method is called before <code>destroy</code>.
+ * </p><p>
+ * If subclasses reimplement this method, they must
+ * call the <code>super</code> implementation.
+ * </p>
+ *
+ * @see #dispose
+ * @see #destroy
+ */
+protected void release () {
+ if (gdipToken != null) {
+ if (fontCollection != 0) {
+ Gdip.PrivateFontCollection_delete(fontCollection);
+ }
+ fontCollection = 0;
+ Gdip.GdiplusShutdown (gdipToken[0]);
+ }
+ gdipToken = null;
+ scripts = null;
+ if (hPalette != 0) OS.DeleteObject (hPalette);
+ hPalette = 0;
+ colorRefCount = null;
+ logFonts = null;
+ nFonts = 0;
+}
+
+/**
+ * If the underlying window system supports printing warning messages
+ * to the console, setting warnings to <code>false</code> prevents these
+ * messages from being printed. If the argument is <code>true</code> then
+ * message printing is not blocked.
+ *
+ * @param warnings <code>true</code>if warnings should be printed, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_DEVICE_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setWarnings (boolean warnings) {
+ checkDevice ();
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/DeviceData.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/DeviceData.java
new file mode 100755
index 0000000000..9b95c99718
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/DeviceData.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+public class DeviceData {
+ /*
+ * Debug fields - may not be honoured
+ * on some SWT platforms.
+ */
+ public boolean debug;
+ public boolean tracking;
+ public Error [] errors;
+ public Object [] objects;
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Font.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Font.java
new file mode 100755
index 0000000000..23cc7aa24f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Font.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class manage operating system resources that
+ * define how text looks when it is displayed. Fonts may be constructed
+ * by providing a device and either name, size and style information
+ * or a <code>FontData</code> object which encapsulates this data.
+ * <p>
+ * Application code must explicitly invoke the <code>Font.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see FontData
+ * @see <a href="http://www.eclipse.org/swt/snippets/#font">Font snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: GraphicsExample, PaintExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+
+public final class Font extends Resource {
+
+ /**
+ * the handle to the OS font resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int /*long*/ handle;
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+Font(Device device) {
+ super(device);
+}
+
+/**
+ * Constructs a new font given a device and font data
+ * which describes the desired font's appearance.
+ * <p>
+ * You must dispose the font when it is no longer required.
+ * </p>
+ *
+ * @param device the device to create the font on
+ * @param fd the FontData that describes the desired font (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the fd argument is null</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a font could not be created from the given font data</li>
+ * </ul>
+ */
+public Font(Device device, FontData fd) {
+ super(device);
+ init(fd);
+ init();
+}
+
+/**
+ * Constructs a new font given a device and an array
+ * of font data which describes the desired font's
+ * appearance.
+ * <p>
+ * You must dispose the font when it is no longer required.
+ * </p>
+ *
+ * @param device the device to create the font on
+ * @param fds the array of FontData that describes the desired font (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the fds argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the length of fds is zero</li>
+ * <li>ERROR_NULL_ARGUMENT - if any fd in the array is null</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a font could not be created from the given font data</li>
+ * </ul>
+ *
+ * @since 2.1
+ */
+public Font(Device device, FontData[] fds) {
+ super(device);
+ if (fds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (fds.length == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ for (int i=0; i<fds.length; i++) {
+ if (fds[i] == null) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ init(fds[0]);
+ init();
+}
+
+/**
+ * Constructs a new font given a device, a font name,
+ * the height of the desired font in points, and a font
+ * style.
+ * <p>
+ * You must dispose the font when it is no longer required.
+ * </p>
+ *
+ * @param device the device to create the font on
+ * @param name the name of the font (must not be null)
+ * @param height the font height in points
+ * @param style a bit or combination of NORMAL, BOLD, ITALIC
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the name argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the height is negative</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES - if a font could not be created from the given arguments</li>
+ * </ul>
+ */
+public Font(Device device, String name, int height, int style) {
+ super(device);
+ if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(new FontData (name, height, style));
+ init();
+}
+
+/*public*/ Font(Device device, String name, float height, int style) {
+ super(device);
+ if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(new FontData (name, height, style));
+ init();
+}
+void destroy() {
+ OS.DeleteObject(handle);
+ handle = 0;
+}
+
+/**
+ * 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 boolean equals(Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Font)) return false;
+ Font font = (Font) object;
+ return device == font.device && handle == font.handle;
+}
+
+/**
+ * Returns an array of <code>FontData</code>s representing the receiver.
+ * On Windows, only one FontData will be returned per font. On X however,
+ * a <code>Font</code> object <em>may</em> be composed of multiple X
+ * fonts. To support this case, we return an array of font data objects.
+ *
+ * @return an array of font data objects describing the receiver
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontData[] getFontData() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ LOGFONT logFont = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA();
+ OS.GetObject(handle, LOGFONT.sizeof, logFont);
+ return new FontData[] {FontData.win32_new(logFont, device.computePoints(logFont, handle))};
+}
+
+/**
+ * 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
+ *
+ * @see #equals
+ */
+public int hashCode () {
+ return (int)/*64*/handle;
+}
+
+void init (FontData fd) {
+ if (fd == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ LOGFONT logFont = fd.data;
+ int lfHeight = logFont.lfHeight;
+ logFont.lfHeight = device.computePixels(fd.height);
+ handle = OS.CreateFontIndirect(logFont);
+ logFont.lfHeight = lfHeight;
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+}
+
+/**
+ * Returns <code>true</code> if the font has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the font.
+ * When a font has been disposed, it is an error to
+ * invoke any other method using the font.
+ *
+ * @return <code>true</code> when the font is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * 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 "Font {*DISPOSED*}";
+ return "Font {" + handle + "}";
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new font.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Font</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param handle the handle for the font
+ * @return a new font object containing the specified device and handle
+ */
+public static Font win32_new(Device device, int /*long*/ handle) {
+ Font font = new Font(device);
+ font.handle = handle;
+ return font;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontData.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontData.java
new file mode 100755
index 0000000000..15e6cb2472
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontData.java
@@ -0,0 +1,669 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class describe operating system fonts.
+ * <p>
+ * For platform-independent behaviour, use the get and set methods
+ * corresponding to the following properties:
+ * <dl>
+ * <dt>height</dt><dd>the height of the font in points</dd>
+ * <dt>name</dt><dd>the face name of the font, which may include the foundry</dd>
+ * <dt>style</dt><dd>A bitwise combination of NORMAL, ITALIC and BOLD</dd>
+ * </dl>
+ * If extra, platform-dependent functionality is required:
+ * <ul>
+ * <li>On <em>Windows</em>, the data member of the <code>FontData</code>
+ * corresponds to a Windows <code>LOGFONT</code> structure whose fields
+ * may be retrieved and modified.</li>
+ * <li>On <em>X</em>, the fields of the <code>FontData</code> correspond
+ * to the entries in the font's XLFD name and may be retrieved and modified.
+ * </ul>
+ * Application code does <em>not</em> need to explicitly release the
+ * resources managed by each instance when those instances are no longer
+ * required, and thus no <code>dispose()</code> method is provided.
+ *
+ * @see Font
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+
+public final class FontData {
+
+ /**
+ * A Win32 LOGFONT struct
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public LOGFONT data;
+
+ /**
+ * The height of the font data in points
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public float height;
+
+ /**
+ * The locales of the font
+ */
+ String lang, country, variant;
+
+/**
+ * Constructs a new uninitialized font data.
+ */
+public FontData() {
+ data = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA();
+ // We set the charset field so that
+ // wildcard searching will work properly
+ // out of the box
+ data.lfCharSet = (byte)OS.DEFAULT_CHARSET;
+ height = 12;
+}
+
+/**
+ * Constructs a new font data given the Windows <code>LOGFONT</code>
+ * that it should represent.
+ *
+ * @param data the <code>LOGFONT</code> for the result
+ */
+FontData(LOGFONT data, float height) {
+ this.data = data;
+ this.height = height;
+}
+
+/**
+ * Constructs a new FontData given a string representation
+ * in the form generated by the <code>FontData.toString</code>
+ * method.
+ * <p>
+ * Note that the representation varies between platforms,
+ * and a FontData can only be created from a string that was
+ * generated on the same platform.
+ * </p>
+ *
+ * @param string the string representation of a <code>FontData</code> (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument does not represent a valid description</li>
+ * </ul>
+ *
+ * @see #toString
+ */
+public FontData(String string) {
+ if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ int start = 0;
+ int end = string.indexOf('|');
+ if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ String version1 = string.substring(start, end);
+ try {
+ if (Integer.parseInt(version1) != 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ } catch (NumberFormatException e) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ String name = string.substring(start, end);
+
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ float height = 0;
+ try {
+ height = Float.parseFloat(string.substring(start, end));
+ } catch (NumberFormatException e) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ int style = 0;
+ try {
+ style = Integer.parseInt(string.substring(start, end));
+ } catch (NumberFormatException e) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ start = end + 1;
+ end = string.indexOf('|', start);
+ data = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA();
+ data.lfCharSet = (byte)OS.DEFAULT_CHARSET;
+ setName(name);
+ setHeight(height);
+ setStyle(style);
+ if (end == -1) return;
+ String platform = string.substring(start, end);
+
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ String version2 = string.substring(start, end);
+
+ if (platform.equals("WINDOWS") && version2.equals("1")) { //$NON-NLS-1$//$NON-NLS-2$
+ LOGFONT newData = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA();
+ try {
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfHeight = Integer.parseInt(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfWidth = Integer.parseInt(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfEscapement = Integer.parseInt(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfOrientation = Integer.parseInt(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfWeight = Integer.parseInt(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfItalic = Byte.parseByte(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfUnderline = Byte.parseByte(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfStrikeOut = Byte.parseByte(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfCharSet = Byte.parseByte(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfOutPrecision = Byte.parseByte(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfClipPrecision = Byte.parseByte(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfQuality = Byte.parseByte(string.substring(start, end));
+ start = end + 1;
+ end = string.indexOf('|', start);
+ if (end == -1) return;
+ newData.lfPitchAndFamily = Byte.parseByte(string.substring(start, end));
+ start = end + 1;
+ } catch (NumberFormatException e) {
+ setName(name);
+ setHeight(height);
+ setStyle(style);
+ return;
+ }
+ TCHAR buffer = new TCHAR(0, string.substring(start), false);
+ int length = Math.min(OS.LF_FACESIZE - 1, buffer.length());
+ if (OS.IsUnicode) {
+ char[] lfFaceName = ((LOGFONTW)newData).lfFaceName;
+ System.arraycopy(buffer.chars, 0, lfFaceName, 0, length);
+ } else {
+ byte[] lfFaceName = ((LOGFONTA)newData).lfFaceName;
+ System.arraycopy(buffer.bytes, 0, lfFaceName, 0, length);
+ }
+ data = newData;
+ }
+}
+
+/**
+ * Constructs a new font data given a font name,
+ * the height of the desired font in points,
+ * and a font style.
+ *
+ * @param name the name of the font (must not be null)
+ * @param height the font height in points
+ * @param style a bit or combination of NORMAL, BOLD, ITALIC
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - when the font name is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the height is negative</li>
+ * </ul>
+ */
+public FontData(String name, int height, int style) {
+ if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ data = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA();
+ setName(name);
+ setHeight(height);
+ setStyle(style);
+ // We set the charset field so that
+ // wildcard searching will work properly
+ // out of the box
+ data.lfCharSet = (byte)OS.DEFAULT_CHARSET;
+}
+
+/*public*/ FontData(String name, float height, int style) {
+ if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ data = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA();
+ setName(name);
+ setHeight(height);
+ setStyle(style);
+ // We set the charset field so that
+ // wildcard searching will work properly
+ // out of the box
+ data.lfCharSet = (byte)OS.DEFAULT_CHARSET;
+}
+
+/**
+ * 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 boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof FontData)) return false;
+ FontData fd = (FontData)object;
+ LOGFONT lf = fd.data;
+ return data.lfCharSet == lf.lfCharSet &&
+ /*
+ * This code is intentionally commented. When creating
+ * a FontData, lfHeight is not necessarily set. Instead
+ * we check the height field which is always set.
+ */
+// data.lfHeight == lf.lfHeight &&
+ height == fd.height &&
+ data.lfWidth == lf.lfWidth &&
+ data.lfEscapement == lf.lfEscapement &&
+ data.lfOrientation == lf.lfOrientation &&
+ data.lfWeight == lf.lfWeight &&
+ data.lfItalic == lf.lfItalic &&
+ data.lfUnderline == lf.lfUnderline &&
+ data.lfStrikeOut == lf.lfStrikeOut &&
+ data.lfCharSet == lf.lfCharSet &&
+ data.lfOutPrecision == lf.lfOutPrecision &&
+ data.lfClipPrecision == lf.lfClipPrecision &&
+ data.lfQuality == lf.lfQuality &&
+ data.lfPitchAndFamily == lf.lfPitchAndFamily &&
+ getName().equals(fd.getName());
+}
+
+int /*long*/ EnumLocalesProc(int /*long*/ lpLocaleString) {
+
+ /* Get the locale ID */
+ int length = 8;
+ TCHAR buffer = new TCHAR(0, length);
+ int byteCount = length * TCHAR.sizeof;
+ OS.MoveMemory(buffer, lpLocaleString, byteCount);
+ int lcid = Integer.parseInt(buffer.toString(0, buffer.strlen ()), 16);
+
+ /* Check the language */
+ int size = OS.GetLocaleInfo(lcid, OS.LOCALE_SISO639LANGNAME, buffer, length);
+ if (size <= 0 || !lang.equals(buffer.toString(0, size - 1))) return 1;
+
+ /* Check the country */
+ if (country != null) {
+ size = OS.GetLocaleInfo(lcid, OS.LOCALE_SISO3166CTRYNAME, buffer, length);
+ if (size <= 0 || !country.equals(buffer.toString(0, size - 1))) return 1;
+ }
+
+ /* Get the charset */
+ size = OS.GetLocaleInfo(lcid, OS.LOCALE_IDEFAULTANSICODEPAGE, buffer, length);
+ if (size <= 0) return 1;
+ int cp = Integer.parseInt(buffer.toString(0, size - 1));
+ int [] lpCs = new int[8];
+ OS.TranslateCharsetInfo(cp, lpCs, OS.TCI_SRCCODEPAGE);
+ data.lfCharSet = (byte)lpCs[0];
+
+ return 0;
+}
+
+/**
+ * Returns the height of the receiver in points.
+ *
+ * @return the height of this FontData
+ *
+ * @see #setHeight(int)
+ */
+public int getHeight() {
+ return (int)(0.5f + height);
+}
+
+/*public*/ float getHeightF() {
+ return height;
+}
+
+/**
+ * Returns the locale of the receiver.
+ * <p>
+ * The locale determines which platform character set this
+ * font is going to use. Widgets and graphics operations that
+ * use this font will convert UNICODE strings to the platform
+ * character set of the specified locale.
+ * </p>
+ * <p>
+ * On platforms where there are multiple character sets for a
+ * given language/country locale, the variant portion of the
+ * locale will determine the character set.
+ * </p>
+ *
+ * @return the <code>String</code> representing a Locale object
+ * @since 3.0
+ */
+public String getLocale () {
+ StringBuffer buffer = new StringBuffer ();
+ char sep = '_';
+ if (lang != null) {
+ buffer.append (lang);
+ buffer.append (sep);
+ }
+ if (country != null) {
+ buffer.append (country);
+ buffer.append (sep);
+ }
+ if (variant != null) {
+ buffer.append (variant);
+ }
+
+ String result = buffer.toString ();
+ int length = result.length ();
+ if (length > 0) {
+ if (result.charAt (length - 1) == sep) {
+ result = result.substring (0, length - 1);
+ }
+ }
+ return result;
+}
+
+/**
+ * Returns the name of the receiver.
+ * On platforms that support font foundries, the return value will
+ * be the foundry followed by a dash ("-") followed by the face name.
+ *
+ * @return the name of this <code>FontData</code>
+ *
+ * @see #setName
+ */
+public String getName() {
+ char[] chars;
+ if (OS.IsUnicode) {
+ chars = ((LOGFONTW)data).lfFaceName;
+ } else {
+ chars = new char[OS.LF_FACESIZE];
+ byte[] bytes = ((LOGFONTA)data).lfFaceName;
+ OS.MultiByteToWideChar (OS.CP_ACP, OS.MB_PRECOMPOSED, bytes, bytes.length, chars, chars.length);
+ }
+ int index = 0;
+ while (index < chars.length) {
+ if (chars [index] == 0) break;
+ index++;
+ }
+ return new String (chars, 0, index);
+}
+
+/**
+ * Returns the style of the receiver which is a bitwise OR of
+ * one or more of the <code>SWT</code> constants NORMAL, BOLD
+ * and ITALIC.
+ *
+ * @return the style of this <code>FontData</code>
+ *
+ * @see #setStyle
+ */
+public int getStyle() {
+ int style = SWT.NORMAL;
+ if (data.lfWeight == 700) style |= SWT.BOLD;
+ if (data.lfItalic != 0) style |= SWT.ITALIC;
+ return style;
+}
+
+/**
+ * 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
+ *
+ * @see #equals
+ */
+public int hashCode () {
+ return data.lfCharSet ^ getHeight() ^ data.lfWidth ^ data.lfEscapement ^
+ data.lfOrientation ^ data.lfWeight ^ data.lfItalic ^data.lfUnderline ^
+ data.lfStrikeOut ^ data.lfCharSet ^ data.lfOutPrecision ^
+ data.lfClipPrecision ^ data.lfQuality ^ data.lfPitchAndFamily ^
+ getName().hashCode();
+}
+
+/**
+ * Sets the height of the receiver. The parameter is
+ * specified in terms of points, where a point is one
+ * seventy-second of an inch.
+ *
+ * @param height the height of the <code>FontData</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the height is negative</li>
+ * </ul>
+ *
+ * @see #getHeight
+ */
+public void setHeight(int height) {
+ if (height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ this.height = height;
+}
+
+/*public*/ void setHeight(float height) {
+ if (height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ this.height = height;
+}
+
+/**
+ * Sets the locale of the receiver.
+ * <p>
+ * The locale determines which platform character set this
+ * font is going to use. Widgets and graphics operations that
+ * use this font will convert UNICODE strings to the platform
+ * character set of the specified locale.
+ * </p>
+ * <p>
+ * On platforms where there are multiple character sets for a
+ * given language/country locale, the variant portion of the
+ * locale will determine the character set.
+ * </p>
+ *
+ * @param locale the <code>String</code> representing a Locale object
+ * @see java.util.Locale#toString
+ */
+public void setLocale(String locale) {
+ lang = country = variant = null;
+ if (locale != null) {
+ char sep = '_';
+ int length = locale.length();
+ int firstSep, secondSep;
+
+ firstSep = locale.indexOf(sep);
+ if (firstSep == -1) {
+ firstSep = secondSep = length;
+ } else {
+ secondSep = locale.indexOf(sep, firstSep + 1);
+ if (secondSep == -1) secondSep = length;
+ }
+ if (firstSep > 0) lang = locale.substring(0, firstSep);
+ if (secondSep > firstSep + 1) country = locale.substring(firstSep + 1, secondSep);
+ if (length > secondSep + 1) variant = locale.substring(secondSep + 1);
+ }
+ if (lang == null) {
+ data.lfCharSet = (byte)OS.DEFAULT_CHARSET;
+ } else {
+ Callback callback = new Callback (this, "EnumLocalesProc", 1); //$NON-NLS-1$
+ int /*long*/ lpEnumLocalesProc = callback.getAddress ();
+ if (lpEnumLocalesProc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ OS.EnumSystemLocales(lpEnumLocalesProc, OS.LCID_SUPPORTED);
+ callback.dispose ();
+ }
+}
+
+/**
+ * Sets the name of the receiver.
+ * <p>
+ * Some platforms support font foundries. On these platforms, the name
+ * of the font specified in setName() may have one of the following forms:
+ * <ol>
+ * <li>a face name (for example, "courier")</li>
+ * <li>a foundry followed by a dash ("-") followed by a face name (for example, "adobe-courier")</li>
+ * </ol>
+ * In either case, the name returned from getName() will include the
+ * foundry.
+ * </p>
+ * <p>
+ * On platforms that do not support font foundries, only the face name
+ * (for example, "courier") is used in <code>setName()</code> and
+ * <code>getName()</code>.
+ * </p>
+ *
+ * @param name the name of the font data (must not be null)
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - when the font name is null</li>
+ * </ul>
+ *
+ * @see #getName
+ */
+public void setName(String name) {
+ if (name == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+
+ /* The field lfFaceName must be NULL terminated */
+ TCHAR buffer = new TCHAR(0, name, true);
+ int length = Math.min(OS.LF_FACESIZE - 1, buffer.length());
+ if (OS.IsUnicode) {
+ char[] lfFaceName = ((LOGFONTW)data).lfFaceName;
+ for (int i = 0; i < lfFaceName.length; i++) lfFaceName[i] = 0;
+ System.arraycopy(buffer.chars, 0, lfFaceName, 0, length);
+ } else {
+ byte[] lfFaceName = ((LOGFONTA)data).lfFaceName;
+ for (int i = 0; i < lfFaceName.length; i++) lfFaceName[i] = 0;
+ System.arraycopy(buffer.bytes, 0, lfFaceName, 0, length);
+ }
+}
+
+/**
+ * Sets the style of the receiver to the argument which must
+ * be a bitwise OR of one or more of the <code>SWT</code>
+ * constants NORMAL, BOLD and ITALIC. All other style bits are
+ * ignored.
+ *
+ * @param style the new style for this <code>FontData</code>
+ *
+ * @see #getStyle
+ */
+public void setStyle(int style) {
+ if ((style & SWT.BOLD) == SWT.BOLD) {
+ data.lfWeight = 700;
+ } else {
+ data.lfWeight = 0;
+ }
+ if ((style & SWT.ITALIC) == SWT.ITALIC) {
+ data.lfItalic = 1;
+ } else {
+ data.lfItalic = 0;
+ }
+}
+
+/**
+ * Returns a string representation of the receiver which is suitable
+ * for constructing an equivalent instance using the
+ * <code>FontData(String)</code> constructor.
+ *
+ * @return a string representation of the FontData
+ *
+ * @see FontData
+ */
+public String toString() {
+ StringBuffer buffer = new StringBuffer(128);
+ buffer.append("1|"); //$NON-NLS-1$
+ String name = getName();
+ buffer.append(name);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(getHeightF());
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(getStyle());
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append("WINDOWS|1|"); //$NON-NLS-1$
+ buffer.append(data.lfHeight);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfWidth);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfEscapement);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfOrientation);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfWeight);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfItalic);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfUnderline);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfStrikeOut);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfCharSet);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfOutPrecision);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfClipPrecision);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfQuality);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(data.lfPitchAndFamily);
+ buffer.append("|"); //$NON-NLS-1$
+ buffer.append(name);
+ return buffer.toString();
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new font data.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>FontData</code>. It is marked public only so that
+ * it can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param data the <code>LOGFONT</code> for the font data
+ * @param height the height of the font data
+ * @return a new font data object containing the specified <code>LOGFONT</code> and height
+ */
+public static FontData win32_new(LOGFONT data, float height) {
+ return new FontData(data, height);
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontMetrics.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontMetrics.java
new file mode 100755
index 0000000000..bfa851cd98
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/FontMetrics.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class provide measurement information
+ * about fonts including ascent, descent, height, leading
+ * space between rows, and average character width.
+ * <code>FontMetrics</code> are obtained from <code>GC</code>s
+ * using the <code>getFontMetrics()</code> method.
+ *
+ * @see GC#getFontMetrics
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+
+public final class FontMetrics {
+
+ /**
+ * On Windows, handle is a Win32 TEXTMETRIC struct
+ * On Photon, handle is a Photon FontQueryInfo struct
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public TEXTMETRIC handle;
+
+/**
+ * Prevents instances from being created outside the package.
+ */
+FontMetrics() {
+}
+
+/**
+ * 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 boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof FontMetrics)) return false;
+ TEXTMETRIC metric = ((FontMetrics)object).handle;
+ return handle.tmHeight == metric.tmHeight &&
+ handle.tmAscent == metric.tmAscent &&
+ handle.tmDescent == metric.tmDescent &&
+ handle.tmInternalLeading == metric.tmInternalLeading &&
+ handle.tmExternalLeading == metric.tmExternalLeading &&
+ handle.tmAveCharWidth == metric.tmAveCharWidth &&
+ handle.tmMaxCharWidth == metric.tmMaxCharWidth &&
+ handle.tmWeight == metric.tmWeight &&
+ handle.tmOverhang == metric.tmOverhang &&
+ handle.tmDigitizedAspectX == metric.tmDigitizedAspectX &&
+ handle.tmDigitizedAspectY == metric.tmDigitizedAspectY &&
+// handle.tmFirstChar == metric.tmFirstChar &&
+// handle.tmLastChar == metric.tmLastChar &&
+// handle.tmDefaultChar == metric.tmDefaultChar &&
+// handle.tmBreakChar == metric.tmBreakChar &&
+ handle.tmItalic == metric.tmItalic &&
+ handle.tmUnderlined == metric.tmUnderlined &&
+ handle.tmStruckOut == metric.tmStruckOut &&
+ handle.tmPitchAndFamily == metric.tmPitchAndFamily &&
+ handle.tmCharSet == metric.tmCharSet;
+}
+
+/**
+ * Returns the ascent of the font described by the receiver. A
+ * font's <em>ascent</em> is the distance from the baseline to the
+ * top of actual characters, not including any of the leading area,
+ * measured in pixels.
+ *
+ * @return the ascent of the font
+ */
+public int getAscent() {
+ return handle.tmAscent - handle.tmInternalLeading;
+}
+
+/**
+ * Returns the average character width, measured in pixels,
+ * of the font described by the receiver.
+ *
+ * @return the average character width of the font
+ */
+public int getAverageCharWidth() {
+ return handle.tmAveCharWidth;
+}
+
+/**
+ * Returns the descent of the font described by the receiver. A
+ * font's <em>descent</em> is the distance from the baseline to the
+ * bottom of actual characters, not including any of the leading area,
+ * measured in pixels.
+ *
+ * @return the descent of the font
+ */
+public int getDescent() {
+ return handle.tmDescent;
+}
+
+/**
+ * Returns the height of the font described by the receiver,
+ * measured in pixels. A font's <em>height</em> is the sum of
+ * its ascent, descent and leading area.
+ *
+ * @return the height of the font
+ *
+ * @see #getAscent
+ * @see #getDescent
+ * @see #getLeading
+ */
+public int getHeight() {
+ return handle.tmHeight;
+}
+
+/**
+ * Returns the leading area of the font described by the
+ * receiver. A font's <em>leading area</em> is the space
+ * above its ascent which may include accents or other marks.
+ *
+ * @return the leading space of the font
+ */
+public int getLeading() {
+ return handle.tmInternalLeading;
+}
+
+/**
+ * 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
+ *
+ * @see #equals
+ */
+public int hashCode() {
+ return handle.tmHeight ^ handle.tmAscent ^ handle.tmDescent ^
+ handle.tmInternalLeading ^ handle.tmExternalLeading ^
+ handle.tmAveCharWidth ^ handle.tmMaxCharWidth ^ handle.tmWeight ^
+ handle.tmOverhang ^ handle.tmDigitizedAspectX ^ handle.tmDigitizedAspectY ^
+// handle.tmFirstChar ^ handle.tmLastChar ^ handle.tmDefaultChar ^ handle.tmBreakChar ^
+ handle.tmItalic ^ handle.tmUnderlined ^ handle.tmStruckOut ^
+ handle.tmPitchAndFamily ^ handle.tmCharSet;
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new font metrics.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>FontMetrics</code>. It is marked public only so that
+ * it can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param handle the <code>TEXTMETRIC</code> containing information about a font
+ * @return a new font metrics object containing the specified <code>TEXTMETRIC</code>
+ */
+public static FontMetrics win32_new(TEXTMETRIC handle) {
+ FontMetrics fontMetrics = new FontMetrics();
+ fontMetrics.handle = handle;
+ return fontMetrics;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java
new file mode 100755
index 0000000000..e08cbf3e48
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GC.java
@@ -0,0 +1,4979 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+
+/**
+ * Class <code>GC</code> is where all of the drawing capabilities that are
+ * supported by SWT 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 SWT 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>
+ * The result of drawing on an image that was created with an indexed
+ * palette using a color that is not in the palette is platform specific.
+ * Some platforms will match to the nearest color while other will draw
+ * the color itself. This happens because the allocated image might use
+ * a direct palette on platforms that do not support indexed palette.
+ * </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 org.eclipse.swt.events.PaintEvent
+ * @see <a href="http://www.eclipse.org/swt/snippets/#gc">GC snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: GraphicsExample, PaintExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+
+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 SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int /*long*/ handle;
+
+ Drawable drawable;
+ GCData data;
+
+ static final int FOREGROUND = 1 << 0;
+ static final int BACKGROUND = 1 << 1;
+ static final int FONT = 1 << 2;
+ static final int LINE_STYLE = 1 << 3;
+ static final int LINE_WIDTH = 1 << 4;
+ static final int LINE_CAP = 1 << 5;
+ static final int LINE_JOIN = 1 << 6;
+ static final int LINE_MITERLIMIT = 1 << 7;
+ static final int FOREGROUND_TEXT = 1 << 8;
+ static final int BACKGROUND_TEXT = 1 << 9;
+ static final int BRUSH = 1 << 10;
+ static final int PEN = 1 << 11;
+ static final int NULL_BRUSH = 1 << 12;
+ static final int NULL_PEN = 1 << 13;
+ static final int DRAW_OFFSET = 1 << 14;
+
+ static final int DRAW = FOREGROUND | LINE_STYLE | LINE_WIDTH | LINE_CAP | LINE_JOIN | LINE_MITERLIMIT | PEN | NULL_BRUSH | DRAW_OFFSET;
+ static final int FILL = BACKGROUND | BRUSH | NULL_PEN;
+
+ 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};
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+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 SWTError <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, SWT.NONE);
+}
+
+/**
+ * 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 SWTError <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 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ GCData data = new GCData ();
+ data.style = checkStyle(style);
+ int /*long*/ hDC = drawable.internal_new_GC(data);
+ Device device = data.device;
+ if (device == null) device = Device.getDevice();
+ if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ this.device = data.device = device;
+ init (drawable, data, hDC);
+ init();
+}
+
+static int checkStyle(int style) {
+ if ((style & SWT.LEFT_TO_RIGHT) != 0) style &= ~SWT.RIGHT_TO_LEFT;
+ return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
+}
+
+void checkGC(int mask) {
+ int state = data.state;
+ if ((state & mask) == mask) return;
+ state = (state ^ mask) & mask;
+ data.state |= mask;
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ int /*long*/ pen = data.gdipPen;
+ float width = data.lineWidth;
+ if ((state & FOREGROUND) != 0 || (pen == 0 && (state & (LINE_WIDTH | LINE_STYLE | LINE_MITERLIMIT | LINE_JOIN | LINE_CAP)) != 0)) {
+ if (data.gdipFgBrush != 0) Gdip.SolidBrush_delete(data.gdipFgBrush);
+ data.gdipFgBrush = 0;
+ int /*long*/ brush;
+ Pattern pattern = data.foregroundPattern;
+ if (pattern != null) {
+ brush = pattern.handle;
+ if ((data.style & SWT.MIRRORED) != 0) {
+ switch (Gdip.Brush_GetType(brush)) {
+ case Gdip.BrushTypeTextureFill:
+ brush = Gdip.Brush_Clone(brush);
+ if (brush == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
+ data.gdipFgBrush = brush;
+ }
+ }
+ } else {
+ int foreground = data.foreground;
+ int rgb = ((foreground >> 16) & 0xFF) | (foreground & 0xFF00) | ((foreground & 0xFF) << 16);
+ int /*long*/ color = Gdip.Color_new(data.alpha << 24 | rgb);
+ if (color == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ brush = Gdip.SolidBrush_new(color);
+ if (brush == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.Color_delete(color);
+ data.gdipFgBrush = brush;
+ }
+ if (pen != 0) {
+ Gdip.Pen_SetBrush(pen, brush);
+ } else {
+ pen = data.gdipPen = Gdip.Pen_new(brush, width);
+ }
+ }
+ if ((state & LINE_WIDTH) != 0) {
+ Gdip.Pen_SetWidth(pen, width);
+ switch (data.lineStyle) {
+ case SWT.LINE_CUSTOM:
+ state |= LINE_STYLE;
+ }
+ }
+ if ((state & LINE_STYLE) != 0) {
+ float[] dashes = null;
+ float dashOffset = 0;
+ int dashStyle = Gdip.DashStyleSolid;
+ switch (data.lineStyle) {
+ case SWT.LINE_SOLID: break;
+ case SWT.LINE_DOT: dashStyle = Gdip.DashStyleDot; if (width == 0) dashes = LINE_DOT_ZERO; break;
+ case SWT.LINE_DASH: dashStyle = Gdip.DashStyleDash; if (width == 0) dashes = LINE_DASH_ZERO; break;
+ case SWT.LINE_DASHDOT: dashStyle = Gdip.DashStyleDashDot; if (width == 0) dashes = LINE_DASHDOT_ZERO; break;
+ case SWT.LINE_DASHDOTDOT: dashStyle = Gdip.DashStyleDashDotDot; if (width == 0) dashes = LINE_DASHDOTDOT_ZERO; break;
+ case SWT.LINE_CUSTOM: {
+ if (data.lineDashes != null) {
+ dashOffset = data.lineDashesOffset / Math.max (1, width);
+ dashes = new float[data.lineDashes.length * 2];
+ for (int i = 0; i < data.lineDashes.length; i++) {
+ float dash = data.lineDashes[i] / Math.max (1, width);
+ dashes[i] = dash;
+ dashes[i + data.lineDashes.length] = dash;
+ }
+ }
+ }
+ }
+ if (dashes != null) {
+ Gdip.Pen_SetDashPattern(pen, dashes, dashes.length);
+ Gdip.Pen_SetDashStyle(pen, Gdip.DashStyleCustom);
+ Gdip.Pen_SetDashOffset(pen, dashOffset);
+ } else {
+ Gdip.Pen_SetDashStyle(pen, dashStyle);
+ }
+ }
+ if ((state & LINE_MITERLIMIT) != 0) {
+ Gdip.Pen_SetMiterLimit(pen, data.lineMiterLimit);
+ }
+ if ((state & LINE_JOIN) != 0) {
+ int joinStyle = 0;
+ switch (data.lineJoin) {
+ case SWT.JOIN_MITER: joinStyle = Gdip.LineJoinMiter; break;
+ case SWT.JOIN_BEVEL: joinStyle = Gdip.LineJoinBevel; break;
+ case SWT.JOIN_ROUND: joinStyle = Gdip.LineJoinRound; break;
+ }
+ Gdip.Pen_SetLineJoin(pen, joinStyle);
+ }
+ if ((state & LINE_CAP) != 0) {
+ int dashCap = Gdip.DashCapFlat, capStyle = 0;
+ switch (data.lineCap) {
+ case SWT.CAP_FLAT: capStyle = Gdip.LineCapFlat; break;
+ case SWT.CAP_ROUND: capStyle = Gdip.LineCapRound; dashCap = Gdip.DashCapRound; break;
+ case SWT.CAP_SQUARE: capStyle = Gdip.LineCapSquare; break;
+ }
+ Gdip.Pen_SetLineCap(pen, capStyle, capStyle, dashCap);
+ }
+ if ((state & BACKGROUND) != 0) {
+ if (data.gdipBgBrush != 0) Gdip.SolidBrush_delete(data.gdipBgBrush);
+ data.gdipBgBrush = 0;
+ Pattern pattern = data.backgroundPattern;
+ if (pattern != null) {
+ data.gdipBrush = pattern.handle;
+ if ((data.style & SWT.MIRRORED) != 0) {
+ switch (Gdip.Brush_GetType(data.gdipBrush)) {
+ case Gdip.BrushTypeTextureFill:
+ int /*long*/ brush = Gdip.Brush_Clone(data.gdipBrush);
+ if (brush == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
+ data.gdipBrush = data.gdipBgBrush = brush;
+ }
+ }
+ } else {
+ int background = data.background;
+ int rgb = ((background >> 16) & 0xFF) | (background & 0xFF00) | ((background & 0xFF) << 16);
+ int /*long*/ color = Gdip.Color_new(data.alpha << 24 | rgb);
+ if (color == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ brush = Gdip.SolidBrush_new(color);
+ if (brush == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.Color_delete(color);
+ data.gdipBrush = data.gdipBgBrush = brush;
+ }
+ }
+ if ((state & FONT) != 0) {
+ Font font = data.font;
+ OS.SelectObject(handle, font.handle);
+ int /*long*/[] hFont = new int /*long*/[1];
+ int /*long*/ gdipFont = createGdipFont(handle, font.handle, gdipGraphics, device.fontCollection, null, hFont);
+ if (hFont[0] != 0) {
+ OS.SelectObject(handle, hFont[0]);
+ if (data.hGDIFont != 0) OS.DeleteObject(data.hGDIFont);
+ data.hGDIFont = hFont[0];
+ }
+ if (data.gdipFont != 0) Gdip.Font_delete(data.gdipFont);
+ data.gdipFont = gdipFont;
+ }
+ if ((state & DRAW_OFFSET) != 0) {
+ data.gdipXOffset = data.gdipYOffset = 0;
+ int /*long*/ matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
+ PointF point = new PointF();
+ point.X = point.Y = 1;
+ Gdip.Graphics_GetTransform(gdipGraphics, matrix);
+ Gdip.Matrix_TransformVectors(matrix, point, 1);
+ Gdip.Matrix_delete(matrix);
+ float scaling = point.X;
+ if (scaling < 0) scaling = -scaling;
+ float penWidth = data.lineWidth * scaling;
+ if (penWidth == 0 || ((int)penWidth % 2) == 1) {
+ data.gdipXOffset = 0.5f / scaling;
+ }
+ scaling = point.Y;
+ if (scaling < 0) scaling = -scaling;
+ penWidth = data.lineWidth * scaling;
+ if (penWidth == 0 || ((int)penWidth % 2) == 1) {
+ data.gdipYOffset = 0.5f / scaling;
+ }
+ }
+ return;
+ }
+ if ((state & (FOREGROUND | LINE_CAP | LINE_JOIN | LINE_STYLE | LINE_WIDTH)) != 0) {
+ int color = data.foreground;
+ int width = (int)data.lineWidth;
+ int[] dashes = null;
+ int lineStyle = OS.PS_SOLID;
+ switch (data.lineStyle) {
+ case SWT.LINE_SOLID: break;
+ case SWT.LINE_DASH: lineStyle = OS.PS_DASH; break;
+ case SWT.LINE_DOT: lineStyle = OS.PS_DOT; break;
+ case SWT.LINE_DASHDOT: lineStyle = OS.PS_DASHDOT; break;
+ case SWT.LINE_DASHDOTDOT: lineStyle = OS.PS_DASHDOTDOT; break;
+ case SWT.LINE_CUSTOM: {
+ if (data.lineDashes != null) {
+ lineStyle = OS.PS_USERSTYLE;
+ dashes = new int[data.lineDashes.length];
+ for (int i = 0; i < dashes.length; i++) {
+ dashes[i] = (int)data.lineDashes[i];
+ }
+ }
+ break;
+ }
+ }
+ if ((state & LINE_STYLE) != 0) {
+ OS.SetBkMode(handle, data.lineStyle == SWT.LINE_SOLID ? OS.OPAQUE : OS.TRANSPARENT);
+ }
+ int joinStyle = 0;
+ switch (data.lineJoin) {
+ case SWT.JOIN_MITER: joinStyle = OS.PS_JOIN_MITER; break;
+ case SWT.JOIN_ROUND: joinStyle = OS.PS_JOIN_ROUND; break;
+ case SWT.JOIN_BEVEL: joinStyle = OS.PS_JOIN_BEVEL; break;
+ }
+ int capStyle = 0;
+ switch (data.lineCap) {
+ case SWT.CAP_ROUND: capStyle = OS.PS_ENDCAP_ROUND; break;
+ case SWT.CAP_FLAT: capStyle = OS.PS_ENDCAP_FLAT; break;
+ case SWT.CAP_SQUARE: capStyle = OS.PS_ENDCAP_SQUARE;break;
+ }
+ int style = lineStyle | joinStyle | capStyle;
+ /*
+ * Feature in Windows. Windows does not honour line styles other then
+ * PS_SOLID for pens wider than 1 pixel created with CreatePen(). The fix
+ * is to use ExtCreatePen() instead.
+ */
+ int /*long*/ newPen;
+ if (OS.IsWinCE || (width == 0 && lineStyle != OS.PS_USERSTYLE) || style == 0) {
+ newPen = OS.CreatePen(style & OS.PS_STYLE_MASK, width, color);
+ } else {
+ LOGBRUSH logBrush = new LOGBRUSH();
+ logBrush.lbStyle = OS.BS_SOLID;
+ logBrush.lbColor = color;
+ /* Feature in Windows. PS_GEOMETRIC pens cannot have zero width. */
+ newPen = OS.ExtCreatePen (style | OS.PS_GEOMETRIC, Math.max(1, width), logBrush, dashes != null ? dashes.length : 0, dashes);
+ }
+ OS.SelectObject(handle, newPen);
+ data.state |= PEN;
+ data.state &= ~NULL_PEN;
+ if (data.hPen != 0) OS.DeleteObject(data.hPen);
+ data.hPen = data.hOldPen = newPen;
+ } else if ((state & PEN) != 0) {
+ OS.SelectObject(handle, data.hOldPen);
+ data.state &= ~NULL_PEN;
+ } else if ((state & NULL_PEN) != 0) {
+ data.hOldPen = OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN));
+ data.state &= ~PEN;
+ }
+ if ((state & BACKGROUND) != 0) {
+ int /*long*/ newBrush = OS.CreateSolidBrush(data.background);
+ OS.SelectObject(handle, newBrush);
+ data.state |= BRUSH;
+ data.state &= ~NULL_BRUSH;
+ if (data.hBrush != 0) OS.DeleteObject(data.hBrush);
+ data.hOldBrush = data.hBrush = newBrush;
+ } else if ((state & BRUSH) != 0) {
+ OS.SelectObject(handle, data.hOldBrush);
+ data.state &= ~NULL_BRUSH;
+ } else if ((state & NULL_BRUSH) != 0) {
+ data.hOldBrush = OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH));
+ data.state &= ~BRUSH;
+ }
+ if ((state & BACKGROUND_TEXT) != 0) {
+ OS.SetBkColor(handle, data.background);
+ }
+ if ((state & FOREGROUND_TEXT) != 0) {
+ OS.SetTextColor(handle, data.foreground);
+ }
+ if ((state & FONT) != 0) {
+ Font font = data.font;
+ OS.SelectObject(handle, font.handle);
+ }
+}
+
+/**
+ * Copies a rectangular area of the receiver at the specified
+ * position into the image, which must be of type <code>SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void copyArea(Image image, int x, int y) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (image.type != SWT.BITMAP || image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+
+ /* Copy the bitmap area */
+ Rectangle rect = image.getBounds();
+ int /*long*/ memHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ hOldBitmap = OS.SelectObject(memHdc, image.handle);
+ OS.BitBlt(memHdc, 0, 0, rect.width, rect.height, handle, x, y, OS.SRCCOPY);
+ OS.SelectObject(memHdc, hOldBitmap);
+ OS.DeleteDC(memHdc);
+}
+
+/**
+ * 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 SWTException <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 SWTException <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, boolean paint) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+
+ /*
+ * Feature in WinCE. The function WindowFromDC is not part of the
+ * WinCE SDK. The fix is to remember the HWND.
+ */
+ int /*long*/ hwnd = data.hwnd;
+ if (hwnd == 0) {
+ OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY);
+ } else {
+ RECT lprcClip = null;
+ int /*long*/ hrgn = OS.CreateRectRgn(0, 0, 0, 0);
+ if (OS.GetClipRgn(handle, hrgn) == 1) {
+ lprcClip = new RECT();
+ OS.GetRgnBox(hrgn, lprcClip);
+ }
+ OS.DeleteObject(hrgn);
+ RECT lprcScroll = new RECT();
+ OS.SetRect(lprcScroll, srcX, srcY, srcX + width, srcY + height);
+ int flags = paint ? OS.SW_INVALIDATE | OS.SW_ERASE : 0;
+ int res = OS.ScrollWindowEx(hwnd, destX - srcX, destY - srcY, lprcScroll, lprcClip, 0, null, flags);
+
+ /*
+ * Feature in WinCE. ScrollWindowEx does not accept combined
+ * vertical and horizontal scrolling. The fix is to do a
+ * BitBlt and invalidate the appropriate source area.
+ */
+ if (res == 0 && OS.IsWinCE) {
+ OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY);
+ if (paint) {
+ int deltaX = destX - srcX, deltaY = destY - srcY;
+ boolean disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY);
+ if (disjoint) {
+ OS.InvalidateRect(hwnd, lprcScroll, true);
+ } else {
+ if (deltaX != 0) {
+ int newX = destX - deltaX;
+ if (deltaX < 0) newX = destX + width;
+ OS.SetRect(lprcScroll, newX, srcY, newX + Math.abs(deltaX), srcY + height);
+ OS.InvalidateRect(hwnd, lprcScroll, true);
+ }
+ if (deltaY != 0) {
+ int newY = destY - deltaY;
+ if (deltaY < 0) newY = destY + height;
+ OS.SetRect(lprcScroll, srcX, newY, srcX + width, newY + Math.abs(deltaY));
+ OS.InvalidateRect(hwnd, lprcScroll, true);
+ }
+ }
+ }
+ }
+ }
+}
+static int /*long*/ createGdipFont(int /*long*/ hDC, int /*long*/ hFont, int /*long*/ graphics, int /*long*/ fontCollection, int /*long*/ [] outFamily, int /*long*/[] outFont) {
+ int /*long*/ font = Gdip.Font_new(hDC, hFont);
+ if (font == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ family = 0;
+ if (!Gdip.Font_IsAvailable(font)) {
+ Gdip.Font_delete(font);
+ LOGFONT logFont = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA();
+ OS.GetObject(hFont, LOGFONT.sizeof, logFont);
+ int size = Math.abs(logFont.lfHeight);
+ int style = Gdip.FontStyleRegular;
+ if (logFont.lfWeight == 700) style |= Gdip.FontStyleBold;
+ if (logFont.lfItalic != 0) style |= Gdip.FontStyleItalic;
+ char[] chars;
+ if (OS.IsUnicode) {
+ chars = ((LOGFONTW)logFont).lfFaceName;
+ } else {
+ chars = new char[OS.LF_FACESIZE];
+ byte[] bytes = ((LOGFONTA)logFont).lfFaceName;
+ OS.MultiByteToWideChar (OS.CP_ACP, OS.MB_PRECOMPOSED, bytes, bytes.length, chars, chars.length);
+ }
+ int index = 0;
+ while (index < chars.length) {
+ if (chars [index] == 0) break;
+ index++;
+ }
+ String name = new String (chars, 0, index);
+ if (Compatibility.equalsIgnoreCase(name, "Courier")) { //$NON-NLS-1$
+ name = "Courier New"; //$NON-NLS-1$
+ }
+ char[] buffer = new char[name.length() + 1];
+ name.getChars(0, name.length(), buffer, 0);
+ if (fontCollection != 0) {
+ family = Gdip.FontFamily_new(buffer, fontCollection);
+ if (!Gdip.FontFamily_IsAvailable(family)) {
+ Gdip.FontFamily_delete(family);
+ family = Gdip.FontFamily_new(buffer, 0);
+ if (!Gdip.FontFamily_IsAvailable(family)) {
+ Gdip.FontFamily_delete(family);
+ family = 0;
+ }
+ }
+ }
+ if (family != 0) {
+ font = Gdip.Font_new(family, size, style, Gdip.UnitPixel);
+ } else {
+ font = Gdip.Font_new(buffer, size, style, Gdip.UnitPixel, 0);
+ }
+ if (outFont != null && font != 0) {
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ int /*long*/ pLogFont = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, LOGFONTW.sizeof);
+ Gdip.Font_GetLogFontW(font, graphics, pLogFont);
+ outFont[0] = OS.CreateFontIndirectW(pLogFont);
+ OS.HeapFree(hHeap, 0, pLogFont);
+ }
+ }
+ if (outFamily != null && font != 0) {
+ if (family == 0) {
+ family = Gdip.FontFamily_new();
+ Gdip.Font_GetFamily(font, family);
+ }
+ outFamily [0] = family;
+ } else {
+ if (family != 0) Gdip.FontFamily_delete(family);
+ }
+ if (font == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ return font;
+}
+
+static void destroyGdipBrush(int /*long*/ brush) {
+ int type = Gdip.Brush_GetType(brush);
+ switch (type) {
+ case Gdip.BrushTypeSolidColor:
+ Gdip.SolidBrush_delete(brush);
+ break;
+ case Gdip.BrushTypeHatchFill:
+ Gdip.HatchBrush_delete(brush);
+ break;
+ case Gdip.BrushTypeLinearGradient:
+ Gdip.LinearGradientBrush_delete(brush);
+ break;
+ case Gdip.BrushTypeTextureFill:
+ Gdip.TextureBrush_delete(brush);
+ break;
+ }
+}
+
+/**
+ * Disposes of the operating system resources associated with
+ * the graphics context. Applications must dispose of all GCs
+ * which they allocate.
+ *
+ * @exception SWTError <ul>
+ * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
+ * </ul>
+ */
+void destroy() {
+ boolean gdip = data.gdipGraphics != 0;
+ disposeGdip();
+ if (gdip && (data.style & SWT.MIRRORED) != 0) {
+ OS.SetLayout(handle, OS.GetLayout(handle) | OS.LAYOUT_RTL);
+ }
+
+ /* Select stock pen and brush objects and free resources */
+ if (data.hPen != 0) {
+ OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN));
+ OS.DeleteObject(data.hPen);
+ data.hPen = 0;
+ }
+ if (data.hBrush != 0) {
+ OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH));
+ OS.DeleteObject(data.hBrush);
+ data.hBrush = 0;
+ }
+
+ /*
+ * Put back the original bitmap into the device context.
+ * This will ensure that we have not left a bitmap
+ * selected in it when we delete the HDC.
+ */
+ int /*long*/ hNullBitmap = data.hNullBitmap;
+ if (hNullBitmap != 0) {
+ OS.SelectObject(handle, hNullBitmap);
+ data.hNullBitmap = 0;
+ }
+ Image image = data.image;
+ if (image != null) image.memGC = null;
+
+ /*
+ * Dispose the HDC.
+ */
+ if (drawable != null) drawable.internal_dispose_GC(handle, data);
+ drawable = null;
+ handle = 0;
+ data.image = null;
+ data.ps = null;
+ data = null;
+}
+
+void disposeGdip() {
+ if (data.gdipPen != 0) Gdip.Pen_delete(data.gdipPen);
+ if (data.gdipBgBrush != 0) destroyGdipBrush(data.gdipBgBrush);
+ if (data.gdipFgBrush != 0) destroyGdipBrush(data.gdipFgBrush);
+ if (data.gdipFont != 0) Gdip.Font_delete(data.gdipFont);
+ if (data.hGDIFont != 0) OS.DeleteObject(data.hGDIFont);
+ if (data.gdipGraphics != 0) Gdip.Graphics_delete(data.gdipGraphics);
+ data.gdipGraphics = data.gdipBrush = data.gdipBgBrush = data.gdipFgBrush =
+ data.gdipFont = data.gdipPen = data.hGDIFont = 0;
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(DRAW);
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ if (width == 0 || height == 0 || arcAngle == 0) return;
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ if (width == height) {
+ Gdip.Graphics_DrawArc(gdipGraphics, data.gdipPen, x, y, width, height, -startAngle, -arcAngle);
+ } else {
+ int /*long*/ path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
+ if (path == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ matrix = Gdip.Matrix_new(width, 0, 0, height, x, y);
+ if (matrix == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.GraphicsPath_AddArc(path, 0, 0, 1, 1, -startAngle, -arcAngle);
+ Gdip.GraphicsPath_Transform(path, matrix);
+ Gdip.Graphics_DrawPath(gdipGraphics, data.gdipPen, path);
+ Gdip.Matrix_delete(matrix);
+ Gdip.GraphicsPath_delete(path);
+ }
+ Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ return;
+ }
+ if ((data.style & SWT.MIRRORED) != 0) {
+ if (data.lineWidth != 0 && data.lineWidth % 2 == 0) x--;
+ }
+ /*
+ * Feature in WinCE. The function Arc is not present in the
+ * WinCE SDK. The fix is to emulate arc drawing by using
+ * Polyline.
+ */
+ if (OS.IsWinCE) {
+ /* compute arc with a simple linear interpolation */
+ if (arcAngle < 0) {
+ startAngle += arcAngle;
+ arcAngle = -arcAngle;
+ }
+ if (arcAngle > 360) arcAngle = 360;
+ int[] points = new int[(arcAngle + 1) * 2];
+ int cteX = 2 * x + width;
+ int cteY = 2 * y + height;
+ int index = 0;
+ for (int i = 0; i <= arcAngle; i++) {
+ points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1;
+ points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1;
+ }
+ OS.Polyline(handle, points, points.length / 2);
+ } else {
+ int x1, y1, x2, y2,tmp;
+ boolean isNegative;
+ if (arcAngle >= 360 || arcAngle <= -360) {
+ x1 = x2 = x + width;
+ y1 = y2 = y + height / 2;
+ } else {
+ isNegative = arcAngle < 0;
+
+ arcAngle = arcAngle + startAngle;
+ if (isNegative) {
+ // swap angles
+ tmp = startAngle;
+ startAngle = arcAngle;
+ arcAngle = tmp;
+ }
+ x1 = Compatibility.cos(startAngle, width) + x + width/2;
+ y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2;
+
+ x2 = Compatibility.cos(arcAngle, width) + x + width/2;
+ y2 = -1 * Compatibility.sin(arcAngle, height) + y + height/2;
+ }
+ OS.Arc(handle, x, y, x + width + 1, y + height + 1, x1, y1, x2, y2);
+ }
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if ((data.uiState & OS.UISF_HIDEFOCUS) != 0) return;
+ data.focusDrawn = true;
+ int /*long*/ hdc = handle;
+ int state = 0;
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ int /*long*/ clipRgn = 0;
+ Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone);
+ int /*long*/ rgn = Gdip.Region_new();
+ if (rgn == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.Graphics_GetClip(gdipGraphics, rgn);
+ if (!Gdip.Region_IsInfinite(rgn, gdipGraphics)) {
+ clipRgn = Gdip.Region_GetHRGN(rgn, gdipGraphics);
+ }
+ Gdip.Region_delete(rgn);
+ Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf);
+ float[] lpXform = null;
+ int /*long*/ matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
+ if (matrix == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.Graphics_GetTransform(gdipGraphics, matrix);
+ if (!Gdip.Matrix_IsIdentity(matrix)) {
+ lpXform = new float[6];
+ Gdip.Matrix_GetElements(matrix, lpXform);
+ }
+ Gdip.Matrix_delete(matrix);
+ hdc = Gdip.Graphics_GetHDC(gdipGraphics);
+ state = OS.SaveDC(hdc);
+ if (lpXform != null) {
+ OS.SetGraphicsMode(hdc, OS.GM_ADVANCED);
+ OS.SetWorldTransform(hdc, lpXform);
+ }
+ if (clipRgn != 0) {
+ OS.SelectClipRgn(hdc, clipRgn);
+ OS.DeleteObject(clipRgn);
+ }
+ }
+ OS.SetBkColor(hdc, 0xFFFFFF);
+ OS.SetTextColor(hdc, 0x000000);
+ RECT rect = new RECT();
+ OS.SetRect(rect, x, y, x + width, y + height);
+ OS.DrawFocusRect(hdc, rect);
+ if (gdipGraphics != 0) {
+ OS.RestoreDC(hdc, state);
+ Gdip.Graphics_ReleaseHDC(gdipGraphics, hdc);
+ } else {
+ data.state &= ~(BACKGROUND_TEXT | FOREGROUND_TEXT);
+ }
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception SWTError <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (image == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (image.isDisposed()) SWT.error(SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception SWTError <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) return;
+ if (srcX < 0 || srcY < 0 || srcWidth < 0 || srcHeight < 0 || destWidth < 0 || destHeight < 0) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ if (image == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (image.isDisposed()) SWT.error(SWT.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, boolean simple) {
+ if (data.gdipGraphics != 0) {
+ //TODO - cache bitmap
+ int /*long*/ [] gdipImage = srcImage.createGdipImage();
+ int /*long*/ img = gdipImage[0];
+ int imgWidth = Gdip.Image_GetWidth(img);
+ int imgHeight = Gdip.Image_GetHeight(img);
+ if (simple) {
+ srcWidth = destWidth = imgWidth;
+ srcHeight = destHeight = imgHeight;
+ } else {
+ if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ simple = srcX == 0 && srcY == 0 &&
+ srcWidth == destWidth && destWidth == imgWidth &&
+ srcHeight == destHeight && destHeight == imgHeight;
+ }
+ Rect rect = new Rect();
+ rect.X = destX;
+ rect.Y = destY;
+ rect.Width = destWidth;
+ rect.Height = destHeight;
+ /*
+ * Note that if the wrap mode is not WrapModeTileFlipXY, the scaled image
+ * is translucent around the borders.
+ */
+ int /*long*/ attrib = Gdip.ImageAttributes_new();
+ Gdip.ImageAttributes_SetWrapMode(attrib, Gdip.WrapModeTileFlipXY);
+ if (data.alpha != 0xFF) {
+ float[] matrix = new float[]{
+ 1,0,0,0,0,
+ 0,1,0,0,0,
+ 0,0,1,0,0,
+ 0,0,0,data.alpha / (float)0xFF,0,
+ 0,0,0,0,1,
+ };
+ Gdip.ImageAttributes_SetColorMatrix(attrib, matrix, Gdip.ColorMatrixFlagsDefault, Gdip.ColorAdjustTypeBitmap);
+ }
+ int gstate = 0;
+ if ((data.style & SWT.MIRRORED) != 0) {
+ gstate = Gdip.Graphics_Save(data.gdipGraphics);
+ Gdip.Graphics_ScaleTransform(data.gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_TranslateTransform(data.gdipGraphics, - 2 * destX - destWidth, 0, Gdip.MatrixOrderPrepend);
+ }
+ Gdip.Graphics_DrawImage(data.gdipGraphics, img, rect, srcX, srcY, srcWidth, srcHeight, Gdip.UnitPixel, attrib, 0, 0);
+ if ((data.style & SWT.MIRRORED) != 0) {
+ Gdip.Graphics_Restore(data.gdipGraphics, gstate);
+ }
+ Gdip.ImageAttributes_delete(attrib);
+ Gdip.Bitmap_delete(img);
+ if (gdipImage[1] != 0) {
+ int /*long*/ hHeap = OS.GetProcessHeap ();
+ OS.HeapFree(hHeap, 0, gdipImage[1]);
+ }
+ return;
+ }
+ switch (srcImage.type) {
+ case SWT.BITMAP:
+ drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
+ break;
+ case SWT.ICON:
+ drawIcon(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
+ break;
+ }
+}
+
+void drawIcon(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
+ int technology = OS.GetDeviceCaps(handle, OS.TECHNOLOGY);
+
+ boolean drawIcon = true;
+ int flags = OS.DI_NORMAL;
+ int offsetX = 0, offsetY = 0;
+ if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(5, 1)) {
+ if ((OS.GetLayout(handle) & OS.LAYOUT_RTL) != 0) {
+ flags |= OS.DI_NOMIRROR;
+ /*
+ * Bug in Windows. For some reason, DrawIconEx() does not take
+ * into account the window origin when the DI_NOMIRROR and
+ * LAYOUT_RTL are set. The fix is to set the window origin to
+ * (0, 0) and offset the drawing ourselves.
+ */
+ POINT pt = new POINT();
+ OS.GetWindowOrgEx(handle, pt);
+ offsetX = pt.x;
+ offsetY = pt.y;
+ }
+ } else {
+ if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
+ drawIcon = (OS.GetLayout(handle) & OS.LAYOUT_RTL) == 0;
+ }
+ }
+
+ /* Simple case: no stretching, entire icon */
+ if (simple && technology != OS.DT_RASPRINTER && drawIcon) {
+ if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, 0, 0, null);
+ OS.DrawIconEx(handle, destX - offsetX, destY - offsetY, srcImage.handle, 0, 0, 0, 0, flags);
+ if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, offsetX, offsetY, null);
+ return;
+ }
+
+ /* Get the icon info */
+ ICONINFO srcIconInfo = new ICONINFO();
+ if (OS.IsWinCE) {
+ Image.GetIconInfo(srcImage, srcIconInfo);
+ } else {
+ OS.GetIconInfo(srcImage.handle, srcIconInfo);
+ }
+
+ /* Get the icon width and height */
+ int /*long*/ hBitmap = srcIconInfo.hbmColor;
+ if (hBitmap == 0) hBitmap = srcIconInfo.hbmMask;
+ BITMAP bm = new BITMAP();
+ OS.GetObject(hBitmap, BITMAP.sizeof, bm);
+ int iconWidth = bm.bmWidth, iconHeight = bm.bmHeight;
+ if (hBitmap == srcIconInfo.hbmMask) iconHeight /= 2;
+
+ if (simple) {
+ srcWidth = destWidth = iconWidth;
+ srcHeight = destHeight = iconHeight;
+ }
+
+ /* Draw the icon */
+ boolean failed = srcX + srcWidth > iconWidth || srcY + srcHeight > iconHeight;
+ if (!failed) {
+ simple = srcX == 0 && srcY == 0 &&
+ srcWidth == destWidth && srcHeight == destHeight &&
+ srcWidth == iconWidth && srcHeight == iconHeight;
+ if (!drawIcon) {
+ drawBitmapMask(srcImage, srcIconInfo.hbmColor, srcIconInfo.hbmMask, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, iconWidth, iconHeight, false);
+ } else if (simple && technology != OS.DT_RASPRINTER) {
+ /* Simple case: no stretching, entire icon */
+ if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, 0, 0, null);
+ OS.DrawIconEx(handle, destX - offsetX, destY - offsetY, srcImage.handle, 0, 0, 0, 0, flags);
+ if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, offsetX, offsetY, null);
+ } else {
+ /* Create the icon info and HDC's */
+ ICONINFO newIconInfo = new ICONINFO();
+ newIconInfo.fIcon = true;
+ int /*long*/ srcHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ dstHdc = OS.CreateCompatibleDC(handle);
+
+ /* Blt the color bitmap */
+ int srcColorY = srcY;
+ int /*long*/ srcColor = srcIconInfo.hbmColor;
+ if (srcColor == 0) {
+ srcColor = srcIconInfo.hbmMask;
+ srcColorY += iconHeight;
+ }
+ int /*long*/ oldSrcBitmap = OS.SelectObject(srcHdc, srcColor);
+ newIconInfo.hbmColor = OS.CreateCompatibleBitmap(srcHdc, destWidth, destHeight);
+ if (newIconInfo.hbmColor == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ oldDestBitmap = OS.SelectObject(dstHdc, newIconInfo.hbmColor);
+ boolean stretch = !simple && (srcWidth != destWidth || srcHeight != destHeight);
+ if (stretch) {
+ if (!OS.IsWinCE) OS.SetStretchBltMode(dstHdc, OS.COLORONCOLOR);
+ OS.StretchBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCCOPY);
+ } else {
+ OS.BitBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcColorY, OS.SRCCOPY);
+ }
+
+ /* Blt the mask bitmap */
+ OS.SelectObject(srcHdc, srcIconInfo.hbmMask);
+ newIconInfo.hbmMask = OS.CreateBitmap(destWidth, destHeight, 1, 1, null);
+ if (newIconInfo.hbmMask == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.SelectObject(dstHdc, newIconInfo.hbmMask);
+ if (stretch) {
+ OS.StretchBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCCOPY);
+ } else {
+ OS.BitBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCCOPY);
+ }
+
+ if (technology == OS.DT_RASPRINTER) {
+ OS.SelectObject(srcHdc, newIconInfo.hbmColor);
+ OS.SelectObject(dstHdc, newIconInfo.hbmMask);
+ drawBitmapTransparentByClipping(srcHdc, dstHdc, 0, 0, destWidth, destHeight, destX, destY, destWidth, destHeight, true, destWidth, destHeight);
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ OS.SelectObject(dstHdc, oldDestBitmap);
+ } else {
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ OS.SelectObject(dstHdc, oldDestBitmap);
+ int /*long*/ hIcon = OS.CreateIconIndirect(newIconInfo);
+ if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, 0, 0, null);
+ OS.DrawIconEx(handle, destX - offsetX, destY - offsetY, hIcon, destWidth, destHeight, 0, 0, flags);
+ if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, offsetX, offsetY, null);
+ OS.DestroyIcon(hIcon);
+ }
+
+ /* Destroy the new icon src and mask and hdc's*/
+ OS.DeleteObject(newIconInfo.hbmMask);
+ OS.DeleteObject(newIconInfo.hbmColor);
+ OS.DeleteDC(dstHdc);
+ OS.DeleteDC(srcHdc);
+ }
+ }
+
+ /* Free icon info */
+ OS.DeleteObject(srcIconInfo.hbmMask);
+ if (srcIconInfo.hbmColor != 0) {
+ OS.DeleteObject(srcIconInfo.hbmColor);
+ }
+
+ if (failed) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+}
+
+void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
+ BITMAP bm = new BITMAP();
+ OS.GetObject(srcImage.handle, BITMAP.sizeof, bm);
+ int imgWidth = bm.bmWidth;
+ int imgHeight = bm.bmHeight;
+ if (simple) {
+ srcWidth = destWidth = imgWidth;
+ srcHeight = destHeight = imgHeight;
+ } else {
+ if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ simple = srcX == 0 && srcY == 0 &&
+ srcWidth == destWidth && destWidth == imgWidth &&
+ srcHeight == destHeight && destHeight == imgHeight;
+ }
+ boolean mustRestore = false;
+ GC memGC = srcImage.memGC;
+ if (memGC != null && !memGC.isDisposed()) {
+ memGC.flush();
+ mustRestore = true;
+ GCData data = memGC.data;
+ if (data.hNullBitmap != 0) {
+ OS.SelectObject(memGC.handle, data.hNullBitmap);
+ data.hNullBitmap = 0;
+ }
+ }
+ if (srcImage.alpha != -1 || srcImage.alphaData != null) {
+ drawBitmapAlpha(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
+ } else if (srcImage.transparentPixel != -1) {
+ drawBitmapTransparent(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
+ } else {
+ drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
+ }
+ if (mustRestore) {
+ int /*long*/ hOldBitmap = OS.SelectObject(memGC.handle, srcImage.handle);
+ memGC.data.hNullBitmap = hOldBitmap;
+ }
+}
+
+void drawBitmapAlpha(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) {
+ /* Simple cases */
+ if (srcImage.alpha == 0) return;
+ if (srcImage.alpha == 255) {
+ drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
+ return;
+ }
+
+ if (OS.IsWinNT && OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
+ BLENDFUNCTION blend = new BLENDFUNCTION();
+ blend.BlendOp = OS.AC_SRC_OVER;
+ int /*long*/ srcHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
+ if (srcImage.alpha != -1) {
+ blend.SourceConstantAlpha = (byte)srcImage.alpha;
+ OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, blend);
+ } else {
+ int /*long*/ memDib = Image.createDIB(srcWidth, srcHeight, 32);
+ if (memDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ memHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ oldMemBitmap = OS.SelectObject(memHdc, memDib);
+ BITMAP dibBM = new BITMAP();
+ OS.GetObject(memDib, BITMAP.sizeof, dibBM);
+ OS.BitBlt(memHdc, 0, 0, srcWidth, srcHeight, srcHdc, srcX, srcY, OS.SRCCOPY);
+ byte[] srcData = new byte[dibBM.bmWidthBytes * dibBM.bmHeight];
+ OS.MoveMemory(srcData, dibBM.bmBits, srcData.length);
+ final int apinc = imgWidth - srcWidth;
+ int ap = srcY * imgWidth + srcX, sp = 0;
+ byte[] alphaData = srcImage.alphaData;
+ for (int y = 0; y < srcHeight; ++y) {
+ for (int x = 0; x < srcWidth; ++x) {
+ int alpha = alphaData[ap++] & 0xff;
+ int r = ((srcData[sp + 0] & 0xFF) * alpha) + 128;
+ r = (r + (r >> 8)) >> 8;
+ int g = ((srcData[sp + 1] & 0xFF) * alpha) + 128;
+ g = (g + (g >> 8)) >> 8;
+ int b = ((srcData[sp + 2] & 0xFF) * alpha) + 128;
+ b = (b + (b >> 8)) >> 8;
+ srcData[sp+0] = (byte)r;
+ srcData[sp+1] = (byte)g;
+ srcData[sp+2] = (byte)b;
+ srcData[sp+3] = (byte)alpha;
+ sp += 4;
+ }
+ ap += apinc;
+ }
+ OS.MoveMemory(dibBM.bmBits, srcData, srcData.length);
+ blend.SourceConstantAlpha = (byte)0xff;
+ blend.AlphaFormat = OS.AC_SRC_ALPHA;
+ OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, blend);
+ OS.SelectObject(memHdc, oldMemBitmap);
+ OS.DeleteDC(memHdc);
+ OS.DeleteObject(memDib);
+ }
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ OS.DeleteDC(srcHdc);
+ return;
+ }
+
+ /* Check clipping */
+ Rectangle rect = getClipping();
+ rect = rect.intersection(new Rectangle(destX, destY, destWidth, destHeight));
+ if (rect.isEmpty()) return;
+
+ /*
+ * Optimization. Recalculate src and dest rectangles so that
+ * only the clipping area is drawn.
+ */
+ int sx1 = srcX + (((rect.x - destX) * srcWidth) / destWidth);
+ int sx2 = srcX + ((((rect.x + rect.width) - destX) * srcWidth) / destWidth);
+ int sy1 = srcY + (((rect.y - destY) * srcHeight) / destHeight);
+ int sy2 = srcY + ((((rect.y + rect.height) - destY) * srcHeight) / destHeight);
+ destX = rect.x;
+ destY = rect.y;
+ destWidth = rect.width;
+ destHeight = rect.height;
+ srcX = sx1;
+ srcY = sy1;
+ srcWidth = Math.max(1, sx2 - sx1);
+ srcHeight = Math.max(1, sy2 - sy1);
+
+ /* Create resources */
+ int /*long*/ srcHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
+ int /*long*/ memHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ memDib = Image.createDIB(Math.max(srcWidth, destWidth), Math.max(srcHeight, destHeight), 32);
+ if (memDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ oldMemBitmap = OS.SelectObject(memHdc, memDib);
+
+ BITMAP dibBM = new BITMAP();
+ OS.GetObject(memDib, BITMAP.sizeof, dibBM);
+ int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
+
+ /* Get the background pixels */
+ OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY);
+ byte[] destData = new byte[sizeInBytes];
+ OS.MoveMemory(destData, dibBM.bmBits, sizeInBytes);
+
+ /* Get the foreground pixels */
+ OS.BitBlt(memHdc, 0, 0, srcWidth, srcHeight, srcHdc, srcX, srcY, OS.SRCCOPY);
+ byte[] srcData = new byte[sizeInBytes];
+ OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
+
+ /* Merge the alpha channel in place */
+ int alpha = srcImage.alpha;
+ final boolean hasAlphaChannel = (srcImage.alpha == -1);
+ if (hasAlphaChannel) {
+ final int apinc = imgWidth - srcWidth;
+ final int spinc = dibBM.bmWidthBytes - srcWidth * 4;
+ int ap = srcY * imgWidth + srcX, sp = 3;
+ byte[] alphaData = srcImage.alphaData;
+ for (int y = 0; y < srcHeight; ++y) {
+ for (int x = 0; x < srcWidth; ++x) {
+ srcData[sp] = alphaData[ap++];
+ sp += 4;
+ }
+ ap += apinc;
+ sp += spinc;
+ }
+ }
+
+ /* Scale the foreground pixels with alpha */
+ OS.MoveMemory(dibBM.bmBits, srcData, sizeInBytes);
+ /*
+ * Bug in WinCE and Win98. StretchBlt does not correctly stretch when
+ * the source and destination HDCs are the same. The workaround is to
+ * stretch to a temporary HDC and blit back into the original HDC.
+ * Note that on WinCE StretchBlt correctly compresses the image when the
+ * source and destination HDCs are the same.
+ */
+ if ((OS.IsWinCE && (destWidth > srcWidth || destHeight > srcHeight)) || (!OS.IsWinNT && !OS.IsWinCE)) {
+ int /*long*/ tempHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ tempDib = Image.createDIB(destWidth, destHeight, 32);
+ if (tempDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ oldTempBitmap = OS.SelectObject(tempHdc, tempDib);
+ if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
+ if (!OS.IsWinCE) OS.SetStretchBltMode(memHdc, OS.COLORONCOLOR);
+ OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY);
+ } else {
+ OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY);
+ }
+ OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY);
+ OS.SelectObject(tempHdc, oldTempBitmap);
+ OS.DeleteObject(tempDib);
+ OS.DeleteDC(tempHdc);
+ } else {
+ if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
+ if (!OS.IsWinCE) OS.SetStretchBltMode(memHdc, OS.COLORONCOLOR);
+ OS.StretchBlt(memHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY);
+ } else {
+ OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY);
+ }
+ }
+ OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
+
+ /* Compose the pixels */
+ final int dpinc = dibBM.bmWidthBytes - destWidth * 4;
+ int dp = 0;
+ for (int y = 0; y < destHeight; ++y) {
+ for (int x = 0; x < destWidth; ++x) {
+ if (hasAlphaChannel) alpha = srcData[dp + 3] & 0xff;
+ destData[dp] += ((srcData[dp] & 0xff) - (destData[dp] & 0xff)) * alpha / 255;
+ destData[dp + 1] += ((srcData[dp + 1] & 0xff) - (destData[dp + 1] & 0xff)) * alpha / 255;
+ destData[dp + 2] += ((srcData[dp + 2] & 0xff) - (destData[dp + 2] & 0xff)) * alpha / 255;
+ dp += 4;
+ }
+ dp += dpinc;
+ }
+
+ /* Draw the composed pixels */
+ OS.MoveMemory(dibBM.bmBits, destData, sizeInBytes);
+ OS.BitBlt(handle, destX, destY, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY);
+
+ /* Free resources */
+ OS.SelectObject(memHdc, oldMemBitmap);
+ OS.DeleteDC(memHdc);
+ OS.DeleteObject(memDib);
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ OS.DeleteDC(srcHdc);
+}
+
+void drawBitmapTransparentByClipping(int /*long*/ srcHdc, int /*long*/ maskHdc, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, int imgWidth, int imgHeight) {
+ /* Create a clipping region from the mask */
+ int /*long*/ rgn = OS.CreateRectRgn(0, 0, 0, 0);
+ for (int y=0; y<imgHeight; y++) {
+ for (int x=0; x<imgWidth; x++) {
+ if (OS.GetPixel(maskHdc, x, y) == 0) {
+ int /*long*/ tempRgn = OS.CreateRectRgn(x, y, x+1, y+1);
+ OS.CombineRgn(rgn, rgn, tempRgn, OS.RGN_OR);
+ OS.DeleteObject(tempRgn);
+ }
+ }
+ }
+ /* Stretch the clipping mask if needed */
+ if (destWidth != srcWidth || destHeight != srcHeight) {
+ int nBytes = OS.GetRegionData (rgn, 0, null);
+ int[] lpRgnData = new int[nBytes / 4];
+ OS.GetRegionData (rgn, nBytes, lpRgnData);
+ float[] lpXform = new float[] {(float)destWidth/srcWidth, 0, 0, (float)destHeight/srcHeight, 0, 0};
+ int /*long*/ tmpRgn = OS.ExtCreateRegion(lpXform, nBytes, lpRgnData);
+ OS.DeleteObject(rgn);
+ rgn = tmpRgn;
+ }
+ OS.OffsetRgn(rgn, destX, destY);
+ int /*long*/ clip = OS.CreateRectRgn(0, 0, 0, 0);
+ int result = OS.GetClipRgn(handle, clip);
+ if (result == 1) OS.CombineRgn(rgn, rgn, clip, OS.RGN_AND);
+ OS.SelectClipRgn(handle, rgn);
+ int rop2 = 0;
+ if (!OS.IsWinCE) {
+ rop2 = OS.GetROP2(handle);
+ } else {
+ rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN);
+ OS.SetROP2 (handle, rop2);
+ }
+ int dwRop = rop2 == OS.R2_XORPEN ? OS.SRCINVERT : OS.SRCCOPY;
+ if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
+ int mode = 0;
+ if (!OS.IsWinCE) mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR);
+ OS.StretchBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, dwRop);
+ if (!OS.IsWinCE) OS.SetStretchBltMode(handle, mode);
+ } else {
+ OS.BitBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, dwRop);
+ }
+ OS.SelectClipRgn(handle, result == 1 ? clip : 0);
+ OS.DeleteObject(clip);
+ OS.DeleteObject(rgn);
+}
+
+void drawBitmapMask(Image srcImage, int /*long*/ srcColor, int /*long*/ srcMask, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, int imgWidth, int imgHeight, boolean offscreen) {
+ int srcColorY = srcY;
+ if (srcColor == 0) {
+ srcColor = srcMask;
+ srcColorY += imgHeight;
+ }
+ int /*long*/ srcHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ oldSrcBitmap = OS.SelectObject(srcHdc, srcColor);
+ int /*long*/ destHdc = handle;
+ int x = destX, y = destY;
+ int /*long*/ tempHdc = 0, tempBitmap = 0, oldTempBitmap = 0;
+ int oldBkColor = 0, oldTextColor = 0;
+ if (offscreen) {
+ tempHdc = OS.CreateCompatibleDC(handle);
+ tempBitmap = OS.CreateCompatibleBitmap(handle, destWidth, destHeight);
+ oldTempBitmap = OS.SelectObject(tempHdc, tempBitmap);
+ OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY);
+ destHdc = tempHdc;
+ x = y = 0;
+ } else {
+ oldBkColor = OS.SetBkColor(handle, 0xFFFFFF);
+ oldTextColor = OS.SetTextColor(handle, 0);
+ }
+ if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
+ int mode = 0;
+ if (!OS.IsWinCE) mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR);
+ OS.StretchBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCINVERT);
+ OS.SelectObject(srcHdc, srcMask);
+ OS.StretchBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCAND);
+ OS.SelectObject(srcHdc, srcColor);
+ OS.StretchBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCINVERT);
+ if (!OS.IsWinCE) OS.SetStretchBltMode(handle, mode);
+ } else {
+ OS.BitBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, OS.SRCINVERT);
+ OS.SetTextColor(destHdc, 0);
+ OS.SelectObject(srcHdc, srcMask);
+ OS.BitBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCAND);
+ OS.SelectObject(srcHdc, srcColor);
+ OS.BitBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, OS.SRCINVERT);
+ }
+ if (offscreen) {
+ OS.BitBlt(handle, destX, destY, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY);
+ OS.SelectObject(tempHdc, oldTempBitmap);
+ OS.DeleteDC(tempHdc);
+ OS.DeleteObject(tempBitmap);
+ } else {
+ OS.SetBkColor(handle, oldBkColor);
+ OS.SetTextColor(handle, oldTextColor);
+ }
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ OS.DeleteDC(srcHdc);
+}
+
+void drawBitmapTransparent(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) {
+
+ /* Find the RGB values for the transparent pixel. */
+ boolean isDib = bm.bmBits != 0;
+ int /*long*/ hBitmap = srcImage.handle;
+ int /*long*/ srcHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ oldSrcBitmap = OS.SelectObject(srcHdc, hBitmap);
+ byte[] originalColors = null;
+ int transparentColor = srcImage.transparentColor;
+ if (transparentColor == -1) {
+ int transBlue = 0, transGreen = 0, transRed = 0;
+ boolean fixPalette = false;
+ if (bm.bmBitsPixel <= 8) {
+ if (isDib) {
+ /* Palette-based DIBSECTION */
+ if (OS.IsWinCE) {
+ byte[] pBits = new byte[1];
+ OS.MoveMemory(pBits, bm.bmBits, 1);
+ byte oldValue = pBits[0];
+ int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF;
+ pBits[0] = (byte)((srcImage.transparentPixel << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask));
+ OS.MoveMemory(bm.bmBits, pBits, 1);
+ int color = OS.GetPixel(srcHdc, 0, 0);
+ pBits[0] = oldValue;
+ OS.MoveMemory(bm.bmBits, pBits, 1);
+ transBlue = (color & 0xFF0000) >> 16;
+ transGreen = (color & 0xFF00) >> 8;
+ transRed = color & 0xFF;
+ } else {
+ int maxColors = 1 << bm.bmBitsPixel;
+ byte[] oldColors = new byte[maxColors * 4];
+ OS.GetDIBColorTable(srcHdc, 0, maxColors, oldColors);
+ int offset = srcImage.transparentPixel * 4;
+ for (int i = 0; i < oldColors.length; i += 4) {
+ if (i != offset) {
+ if (oldColors[offset] == oldColors[i] && oldColors[offset+1] == oldColors[i+1] && oldColors[offset+2] == oldColors[i+2]) {
+ fixPalette = true;
+ break;
+ }
+ }
+ }
+ if (fixPalette) {
+ byte[] newColors = new byte[oldColors.length];
+ transRed = transGreen = transBlue = 0xff;
+ newColors[offset] = (byte)transBlue;
+ newColors[offset+1] = (byte)transGreen;
+ newColors[offset+2] = (byte)transRed;
+ OS.SetDIBColorTable(srcHdc, 0, maxColors, newColors);
+ originalColors = oldColors;
+ } else {
+ transBlue = oldColors[offset] & 0xFF;
+ transGreen = oldColors[offset+1] & 0xFF;
+ transRed = oldColors[offset+2] & 0xFF;
+ }
+ }
+ } else {
+ /* Palette-based bitmap */
+ int numColors = 1 << bm.bmBitsPixel;
+ /* Set the few fields necessary to get the RGB data out */
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biPlanes = bm.bmPlanes;
+ bmiHeader.biBitCount = bm.bmBitsPixel;
+ byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ OS.GetDIBits(srcHdc, srcImage.handle, 0, 0, 0, bmi, OS.DIB_RGB_COLORS);
+ int offset = BITMAPINFOHEADER.sizeof + 4 * srcImage.transparentPixel;
+ transRed = bmi[offset + 2] & 0xFF;
+ transGreen = bmi[offset + 1] & 0xFF;
+ transBlue = bmi[offset] & 0xFF;
+ }
+ } else {
+ /* Direct color image */
+ int pixel = srcImage.transparentPixel;
+ switch (bm.bmBitsPixel) {
+ case 16:
+ transBlue = (pixel & 0x1F) << 3;
+ transGreen = (pixel & 0x3E0) >> 2;
+ transRed = (pixel & 0x7C00) >> 7;
+ break;
+ case 24:
+ transBlue = (pixel & 0xFF0000) >> 16;
+ transGreen = (pixel & 0xFF00) >> 8;
+ transRed = pixel & 0xFF;
+ break;
+ case 32:
+ transBlue = (pixel & 0xFF000000) >>> 24;
+ transGreen = (pixel & 0xFF0000) >> 16;
+ transRed = (pixel & 0xFF00) >> 8;
+ break;
+ }
+ }
+ transparentColor = transBlue << 16 | transGreen << 8 | transRed;
+ if (!fixPalette) srcImage.transparentColor = transparentColor;
+ }
+
+ if (OS.IsWinCE) {
+ /*
+ * Note in WinCE. TransparentImage uses the first entry of a palette
+ * based image when there are multiple entries that have the same
+ * transparent color.
+ */
+ OS.TransparentImage(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, transparentColor);
+ } else if (originalColors == null && OS.IsWinNT && OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
+ int mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR);
+ OS.TransparentBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, transparentColor);
+ OS.SetStretchBltMode(handle, mode);
+ } else {
+ /* Create the mask for the source image */
+ int /*long*/ maskHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ maskBitmap = OS.CreateBitmap(imgWidth, imgHeight, 1, 1, null);
+ int /*long*/ oldMaskBitmap = OS.SelectObject(maskHdc, maskBitmap);
+ OS.SetBkColor(srcHdc, transparentColor);
+ OS.BitBlt(maskHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, 0, OS.SRCCOPY);
+ if (originalColors != null) OS.SetDIBColorTable(srcHdc, 0, 1 << bm.bmBitsPixel, originalColors);
+
+ if (OS.GetDeviceCaps(handle, OS.TECHNOLOGY) == OS.DT_RASPRINTER) {
+ /* Most printers do not support BitBlt(), draw the source bitmap transparently using clipping */
+ drawBitmapTransparentByClipping(srcHdc, maskHdc, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight);
+ } else {
+ /* Draw the source bitmap transparently using invert/and mask/invert */
+ int /*long*/ tempHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ tempBitmap = OS.CreateCompatibleBitmap(handle, destWidth, destHeight);
+ int /*long*/ oldTempBitmap = OS.SelectObject(tempHdc, tempBitmap);
+ OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY);
+ if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
+ if (!OS.IsWinCE) OS.SetStretchBltMode(tempHdc, OS.COLORONCOLOR);
+ OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCINVERT);
+ OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, maskHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCAND);
+ OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCINVERT);
+ } else {
+ OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCINVERT);
+ OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, maskHdc, srcX, srcY, OS.SRCAND);
+ OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCINVERT);
+ }
+ OS.BitBlt(handle, destX, destY, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY);
+ OS.SelectObject(tempHdc, oldTempBitmap);
+ OS.DeleteDC(tempHdc);
+ OS.DeleteObject(tempBitmap);
+ }
+ OS.SelectObject(maskHdc, oldMaskBitmap);
+ OS.DeleteDC(maskHdc);
+ OS.DeleteObject(maskBitmap);
+ }
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ if (hBitmap != srcImage.handle) OS.DeleteObject(hBitmap);
+ OS.DeleteDC(srcHdc);
+}
+
+void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, BITMAP bm, int imgWidth, int imgHeight) {
+ int /*long*/ srcHdc = OS.CreateCompatibleDC(handle);
+ int /*long*/ oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
+ int rop2 = 0;
+ if (!OS.IsWinCE) {
+ rop2 = OS.GetROP2(handle);
+ } else {
+ rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN);
+ OS.SetROP2 (handle, rop2);
+ }
+ int dwRop = rop2 == OS.R2_XORPEN ? OS.SRCINVERT : OS.SRCCOPY;
+ if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
+ int mode = 0;
+ if (!OS.IsWinCE) mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR);
+ OS.StretchBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, dwRop);
+ if (!OS.IsWinCE) OS.SetStretchBltMode(handle, mode);
+ } else {
+ OS.BitBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, dwRop);
+ }
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ OS.DeleteDC(srcHdc);
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(DRAW);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_DrawLine(gdipGraphics, data.gdipPen, x1, y1, x2, y2);
+ Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ return;
+ }
+ if ((data.style & SWT.MIRRORED) != 0) {
+ if (data.lineWidth != 0 && data.lineWidth % 2 == 0) {
+ x1--;
+ x2--;
+ }
+ }
+ if (OS.IsWinCE) {
+ int [] points = new int [] {x1, y1, x2, y2};
+ OS.Polyline (handle, points, points.length / 2);
+ } else {
+ OS.MoveToEx (handle, x1, y1, 0);
+ OS.LineTo (handle, x2, y2);
+ }
+ if (data.lineWidth <= 1) {
+ OS.SetPixel (handle, x2, y2, data.foreground);
+ }
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(DRAW);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_DrawEllipse(gdipGraphics, data.gdipPen, x, y, width, height);
+ Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ return;
+ }
+ if ((data.style & SWT.MIRRORED) != 0) {
+ if (data.lineWidth != 0 && data.lineWidth % 2 == 0) x--;
+ }
+ OS.Ellipse(handle, x, y, x + width + 1, y + height + 1);
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (path.handle == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ initGdip();
+ checkGC(DRAW);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_DrawPath(gdipGraphics, data.gdipPen, path.handle);
+ Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.gdipGraphics != 0) {
+ checkGC(DRAW);
+ Gdip.Graphics_FillRectangle(data.gdipGraphics, getFgBrush(), x, y, 1, 1);
+ return;
+ }
+ OS.SetPixel (handle, x, y, data.foreground);
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawPolygon(int[] pointArray) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ checkGC(DRAW);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_DrawPolygon(gdipGraphics, data.gdipPen, pointArray, pointArray.length / 2);
+ Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ return;
+ }
+ if ((data.style & SWT.MIRRORED) != 0) {
+ if (data.lineWidth != 0 && data.lineWidth % 2 == 0) {
+ for (int i = 0; i < pointArray.length; i+=2) {
+ pointArray[i]--;
+ }
+ }
+ }
+ OS.Polygon(handle, pointArray, pointArray.length / 2);
+ if ((data.style & SWT.MIRRORED) != 0) {
+ if (data.lineWidth != 0 && data.lineWidth % 2 == 0) {
+ for (int i = 0; i < pointArray.length; i+=2) {
+ pointArray[i]++;
+ }
+ }
+ }
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawPolyline(int[] pointArray) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ checkGC(DRAW);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_DrawLines(gdipGraphics, data.gdipPen, pointArray, pointArray.length / 2);
+ Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ return;
+ }
+ if ((data.style & SWT.MIRRORED) != 0) {
+ if (data.lineWidth != 0 && data.lineWidth % 2 == 0) {
+ for (int i = 0; i < pointArray.length; i+=2) {
+ pointArray[i]--;
+ }
+ }
+ }
+ OS.Polyline(handle, pointArray, pointArray.length / 2);
+ int length = pointArray.length;
+ if (length >= 2) {
+ if (data.lineWidth <= 1) {
+ OS.SetPixel (handle, pointArray[length - 2], pointArray[length - 1], data.foreground);
+ }
+ }
+ if ((data.style & SWT.MIRRORED) != 0) {
+ if (data.lineWidth != 0 && data.lineWidth % 2 == 0) {
+ for (int i = 0; i < pointArray.length; i+=2) {
+ pointArray[i]++;
+ }
+ }
+ }
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(DRAW);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_DrawRectangle(gdipGraphics, data.gdipPen, x, y, width, height);
+ Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ return;
+ }
+ if ((data.style & SWT.MIRRORED) != 0) {
+ /*
+ * Note that Rectangle() subtracts one pixel in MIRRORED mode when
+ * the pen was created with CreatePen() and its width is 0 or 1.
+ */
+ if (data.lineWidth > 1) {
+ if ((data.lineWidth % 2) == 1) x++;
+ } else {
+ if (data.hPen != 0 && OS.GetObject(data.hPen, 0, 0) != LOGPEN.sizeof) {
+ x++;
+ }
+ }
+ }
+ OS.Rectangle (handle, x, y, x + width + 1, y + height + 1);
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawRectangle (Rectangle rect) {
+ if (rect == null) SWT.error(SWT.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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(DRAW);
+ if (data.gdipGraphics != 0) {
+ drawRoundRectangleGdip(data.gdipGraphics, data.gdipPen, x, y, width, height, arcWidth, arcHeight);
+ return;
+ }
+ if ((data.style & SWT.MIRRORED) != 0) {
+ if (data.lineWidth != 0 && data.lineWidth % 2 == 0) x--;
+ }
+ if (OS.IsWinCE) {
+ /*
+ * Bug in WinCE PPC. On certain devices, RoundRect does not draw
+ * all the pixels. The workaround is to draw a round rectangle
+ * using lines and arcs.
+ */
+ if (width == 0 || height == 0) return;
+ if (arcWidth == 0 || arcHeight == 0) {
+ drawRectangle(x, y, width, height);
+ return;
+ }
+ if (width < 0) {
+ x += width;
+ width = -width;
+ }
+ if (height < 0) {
+ y += height;
+ height = -height;
+ }
+ if (arcWidth < 0) arcWidth = -arcWidth;
+ if (arcHeight < 0) arcHeight = -arcHeight;
+ if (arcWidth > width) arcWidth = width;
+ if (arcHeight > height) arcHeight = height;
+
+ if (arcWidth < width) {
+ drawLine(x+arcWidth/2, y, x+width-arcWidth/2, y);
+ drawLine(x+arcWidth/2, y+height, x+width-arcWidth/2, y+height);
+ }
+ if (arcHeight < height) {
+ drawLine(x, y+arcHeight/2, x, y+height-arcHeight/2);
+ drawLine(x+width, y+arcHeight/2, x+width, y+height-arcHeight/2);
+ }
+ if (arcWidth != 0 && arcHeight != 0) {
+ drawArc(x, y, arcWidth, arcHeight, 90, 90);
+ drawArc(x+width-arcWidth, y, arcWidth, arcHeight, 0, 90);
+ drawArc(x+width-arcWidth, y+height-arcHeight, arcWidth, arcHeight, 0, -90);
+ drawArc(x, y+height-arcHeight, arcWidth, arcHeight, 180, 90);
+ }
+ } else {
+ OS.RoundRect(handle, x,y,x+width+1,y+height+1, arcWidth, arcHeight);
+ }
+}
+
+void drawRoundRectangleGdip (int /*long*/ gdipGraphics, int /*long*/ pen, int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ int nx = x;
+ int ny = y;
+ int nw = width;
+ int nh = height;
+ int naw = arcWidth;
+ int nah = arcHeight;
+
+ if (nw < 0) {
+ nw = 0 - nw;
+ nx = nx - nw;
+ }
+ if (nh < 0) {
+ nh = 0 - nh;
+ ny = ny - nh;
+ }
+ if (naw < 0)
+ naw = 0 - naw;
+ if (nah < 0)
+ nah = 0 - nah;
+
+ Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
+ if (naw == 0 || nah == 0) {
+ Gdip.Graphics_DrawRectangle(gdipGraphics, data.gdipPen, x, y, width, height);
+ } else {
+ int /*long*/ path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
+ if (path == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ if (nw > naw) {
+ if (nh > nah) {
+ Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nah, 0, -90);
+ Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nah, -90, -90);
+ Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, naw, nah, -180, -90);
+ Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny + nh - nah, naw, nah, -270, -90);
+ } else {
+ Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nh, -270, -180);
+ Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nh, -90, -180);
+ }
+ } else {
+ if (nh > nah) {
+ Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nah, 0, -180);
+ Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, nw, nah, -180, -180);
+ } else {
+ Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nh, 0, 360);
+ }
+ }
+ Gdip.GraphicsPath_CloseFigure(path);
+ Gdip.Graphics_DrawPath(gdipGraphics, pen, path);
+ Gdip.GraphicsPath_delete(path);
+ }
+ Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
+}
+
+/**
+ * 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 SWTException <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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawString (String string, int x, int y, boolean isTransparent) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+// TCHAR buffer = new TCHAR (getCodePage(), string, false);
+ int length = string.length();
+ if (length == 0) return;
+ char[] buffer = new char [length];
+ string.getChars(0, length, buffer, 0);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ checkGC(FONT | FOREGROUND | (isTransparent ? 0 : BACKGROUND));
+ int nGlyphs = (length * 3 / 2) + 16;
+ GCP_RESULTS result = new GCP_RESULTS();
+ result.lStructSize = GCP_RESULTS.sizeof;
+ result.nGlyphs = nGlyphs;
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ int /*long*/ lpDx = result.lpDx = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, nGlyphs * 4);
+ int /*long*/ lpGlyphs = result.lpGlyphs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, nGlyphs * 2);
+ int dwFlags = OS.GCP_GLYPHSHAPE | OS.GCP_REORDER | OS.GCP_LIGATE;
+ int /*long*/ hdc = Gdip.Graphics_GetHDC(gdipGraphics);
+ int /*long*/ hFont = data.hGDIFont;
+ if (hFont == 0 && data.font != null) hFont = data.font.handle;
+ int /*long*/ oldFont = 0;
+ if (hFont != 0) oldFont = OS.SelectObject(hdc, hFont);
+ if ((data.style & SWT.MIRRORED) != 0) OS.SetLayout(hdc, OS.GetLayout(hdc) | OS.LAYOUT_RTL);
+ OS.GetCharacterPlacementW(hdc, buffer, length, 0, result, dwFlags);
+ if ((data.style & SWT.MIRRORED) != 0) OS.SetLayout(hdc, OS.GetLayout(hdc) & ~OS.LAYOUT_RTL);
+ TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
+ OS.GetTextMetrics(hdc, lptm);
+ if (hFont != 0) OS.SelectObject(hdc, oldFont);
+ Gdip.Graphics_ReleaseHDC(gdipGraphics, hdc);
+ nGlyphs = result.nGlyphs;
+ int drawX = x, drawY = y + lptm.tmAscent;
+ int[] dx = new int[nGlyphs];
+ OS.MoveMemory(dx, result.lpDx, nGlyphs * 4);
+ float[] points = new float[dx.length * 2];
+ for (int i = 0, j = 0; i < dx.length; i++) {
+ points[j++] = drawX;
+ points[j++] = drawY;
+ drawX += dx[i];
+ }
+ RectF bounds = null;
+ if (!isTransparent || (data.style & SWT.MIRRORED) != 0) {
+ bounds = new RectF();
+ Gdip.Graphics_MeasureDriverString(gdipGraphics, lpGlyphs, nGlyphs, data.gdipFont, points, 0, 0, bounds);
+ if (!isTransparent) {
+ Gdip.Graphics_FillRectangle(gdipGraphics, data.gdipBrush, x, y, Math.round(bounds.Width), Math.round(bounds.Height));
+ }
+ }
+ int gstate = 0;
+ int /*long*/ brush = getFgBrush();
+ if ((data.style & SWT.MIRRORED) != 0) {
+ switch (Gdip.Brush_GetType(brush)) {
+ case Gdip.BrushTypeLinearGradient:
+ Gdip.LinearGradientBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.LinearGradientBrush_TranslateTransform(brush, - 2 * x - bounds.Width, 0, Gdip.MatrixOrderPrepend);
+ break;
+ case Gdip.BrushTypeTextureFill:
+ Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.TextureBrush_TranslateTransform(brush, - 2 * x - bounds.Width, 0, Gdip.MatrixOrderPrepend);
+ break;
+ }
+ gstate = Gdip.Graphics_Save(gdipGraphics);
+ Gdip.Graphics_ScaleTransform(gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_TranslateTransform(gdipGraphics, - 2 * x - bounds.Width, 0, Gdip.MatrixOrderPrepend);
+ }
+ Gdip.Graphics_DrawDriverString(gdipGraphics, lpGlyphs, result.nGlyphs, data.gdipFont, brush, points, 0, 0);
+ if ((data.style & SWT.MIRRORED) != 0) {
+ switch (Gdip.Brush_GetType(brush)) {
+ case Gdip.BrushTypeLinearGradient:
+ Gdip.LinearGradientBrush_ResetTransform(brush);
+ break;
+ case Gdip.BrushTypeTextureFill:
+ Gdip.TextureBrush_ResetTransform(brush);
+ break;
+ }
+ Gdip.Graphics_Restore(gdipGraphics, gstate);
+ }
+ OS.HeapFree(hHeap, 0, lpGlyphs);
+ OS.HeapFree(hHeap, 0, lpDx);
+ return;
+ }
+ int rop2 = 0;
+ if (OS.IsWinCE) {
+ rop2 = OS.SetROP2(handle, OS.R2_COPYPEN);
+ OS.SetROP2(handle, rop2);
+ } else {
+ rop2 = OS.GetROP2(handle);
+ }
+ checkGC(FONT | FOREGROUND_TEXT | BACKGROUND_TEXT);
+ int oldBkMode = OS.SetBkMode(handle, isTransparent ? OS.TRANSPARENT : OS.OPAQUE);
+ RECT rect = null;
+ SIZE size = null;
+ int flags = 0;
+ if ((data.style & SWT.MIRRORED) != 0) {
+ if (!isTransparent) {
+ size = new SIZE();
+ OS.GetTextExtentPoint32W(handle, buffer, length, size);
+ rect = new RECT ();
+ rect.left = x;
+ rect.right = x + size.cx;
+ rect.top = y;
+ rect.bottom = y + size.cy;
+ flags = OS.ETO_CLIPPED;
+ }
+ x--;
+ }
+ if (rop2 != OS.R2_XORPEN) {
+ OS.ExtTextOutW(handle, x, y, flags, rect, buffer, length, null);
+ } else {
+ int foreground = OS.GetTextColor(handle);
+ if (isTransparent) {
+ if (size == null) {
+ size = new SIZE();
+ OS.GetTextExtentPoint32W(handle, buffer, length, size);
+ }
+ int width = size.cx, height = size.cy;
+ int /*long*/ hBitmap = OS.CreateCompatibleBitmap(handle, width, height);
+ if (hBitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ memDC = OS.CreateCompatibleDC(handle);
+ int /*long*/ hOldBitmap = OS.SelectObject(memDC, hBitmap);
+ OS.PatBlt(memDC, 0, 0, width, height, OS.BLACKNESS);
+ OS.SetBkMode(memDC, OS.TRANSPARENT);
+ OS.SetTextColor(memDC, foreground);
+ OS.SelectObject(memDC, OS.GetCurrentObject(handle, OS.OBJ_FONT));
+ OS.ExtTextOutW(memDC, 0, 0, 0, null, buffer, length, null);
+ OS.BitBlt(handle, x, y, width, height, memDC, 0, 0, OS.SRCINVERT);
+ OS.SelectObject(memDC, hOldBitmap);
+ OS.DeleteDC(memDC);
+ OS.DeleteObject(hBitmap);
+ } else {
+ int background = OS.GetBkColor(handle);
+ OS.SetTextColor(handle, foreground ^ background);
+ OS.ExtTextOutW(handle, x, y, flags, rect, buffer, length, null);
+ OS.SetTextColor(handle, foreground);
+ }
+ }
+ OS.SetBkMode(handle, oldBkMode);
+}
+
+/**
+ * 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 SWTException <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, SWT.DRAW_DELIMITER | SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void drawText (String string, int x, int y, boolean isTransparent) {
+ int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB;
+ if (isTransparent) flags |= SWT.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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (string.length() == 0) return;
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ checkGC(FONT | FOREGROUND | ((flags & SWT.DRAW_TRANSPARENT) != 0 ? 0 : BACKGROUND));
+ int length = string.length();
+ char[] buffer = new char [length];
+ string.getChars(0, length, buffer, 0);
+ PointF pt = new PointF();
+ int /*long*/ format = Gdip.StringFormat_Clone(Gdip.StringFormat_GenericTypographic());
+ int formatFlags = Gdip.StringFormat_GetFormatFlags(format) | Gdip.StringFormatFlagsMeasureTrailingSpaces;
+ if ((data.style & SWT.MIRRORED) != 0) formatFlags |= Gdip.StringFormatFlagsDirectionRightToLeft;
+ Gdip.StringFormat_SetFormatFlags(format, formatFlags);
+ float[] tabs = (flags & SWT.DRAW_TAB) != 0 ? new float[]{measureSpace(data.gdipFont, format) * 8} : new float[1];
+ Gdip.StringFormat_SetTabStops(format, 0, tabs.length, tabs);
+ int hotkeyPrefix = (flags & SWT.DRAW_MNEMONIC) != 0 ? Gdip.HotkeyPrefixShow : Gdip.HotkeyPrefixNone;
+ if ((flags & SWT.DRAW_MNEMONIC) != 0 && (data.uiState & OS.UISF_HIDEACCEL) != 0) hotkeyPrefix = Gdip.HotkeyPrefixHide;
+ Gdip.StringFormat_SetHotkeyPrefix(format, hotkeyPrefix);
+ if ((flags & SWT.DRAW_TRANSPARENT) == 0) {
+ RectF bounds = new RectF();
+ Gdip.Graphics_MeasureString(gdipGraphics, buffer, length, data.gdipFont, pt, format, bounds);
+ Gdip.Graphics_FillRectangle(gdipGraphics, data.gdipBrush, x, y, Math.round(bounds.Width), Math.round(bounds.Height));
+ }
+ int gstate = 0;
+ int /*long*/ brush = getFgBrush();
+ if ((data.style & SWT.MIRRORED) != 0) {
+ switch (Gdip.Brush_GetType(brush)) {
+ case Gdip.BrushTypeLinearGradient:
+ Gdip.LinearGradientBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.LinearGradientBrush_TranslateTransform(brush, - 2 * x, 0, Gdip.MatrixOrderPrepend);
+ break;
+ case Gdip.BrushTypeTextureFill:
+ Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.TextureBrush_TranslateTransform(brush, - 2 * x, 0, Gdip.MatrixOrderPrepend);
+ break;
+ }
+ gstate = Gdip.Graphics_Save(gdipGraphics);
+ Gdip.Graphics_ScaleTransform(gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_TranslateTransform(gdipGraphics, - 2 * x, 0, Gdip.MatrixOrderPrepend);
+ }
+ pt.X = x;
+ pt.Y = y;
+ Gdip.Graphics_DrawString(gdipGraphics, buffer, length, data.gdipFont, pt, format, brush);
+ if ((data.style & SWT.MIRRORED) != 0) {
+ switch (Gdip.Brush_GetType(brush)) {
+ case Gdip.BrushTypeLinearGradient:
+ Gdip.LinearGradientBrush_ResetTransform(brush);
+ break;
+ case Gdip.BrushTypeTextureFill:
+ Gdip.TextureBrush_ResetTransform(brush);
+ break;
+ }
+ Gdip.Graphics_Restore(gdipGraphics, gstate);
+ }
+ Gdip.StringFormat_delete(format);
+ return;
+ }
+ TCHAR buffer = new TCHAR(getCodePage(), string, false);
+ int length = buffer.length();
+ if (length == 0) return;
+ RECT rect = new RECT();
+ /*
+ * Feature in Windows. For some reason DrawText(), the maximum
+ * value for the bottom and right coordinates for the RECT that
+ * is used to position the text is different on between Windows
+ * versions. If this value is larger than the maximum, nothing
+ * is drawn. On Windows 98, the limit is 0x7FFF. On Windows CE,
+ * NT, and 2000 it is 0x6FFFFFF. And on XP, it is 0x7FFFFFFF.
+ * The fix is to use the the smaller limit for Windows 98 and the
+ * larger limit on the other Windows platforms.
+ */
+ int limit = OS.IsWin95 ? 0x7FFF : 0x6FFFFFF;
+ OS.SetRect(rect, x, y, limit, limit);
+ int uFormat = OS.DT_LEFT;
+ if ((flags & SWT.DRAW_DELIMITER) == 0) uFormat |= OS.DT_SINGLELINE;
+ if ((flags & SWT.DRAW_TAB) != 0) uFormat |= OS.DT_EXPANDTABS;
+ if ((flags & SWT.DRAW_MNEMONIC) == 0) uFormat |= OS.DT_NOPREFIX;
+ if ((flags & SWT.DRAW_MNEMONIC) != 0 && (data.uiState & OS.UISF_HIDEACCEL) != 0) {
+ uFormat |= OS.DT_HIDEPREFIX;
+ }
+ int rop2 = 0;
+ if (OS.IsWinCE) {
+ rop2 = OS.SetROP2(handle, OS.R2_COPYPEN);
+ OS.SetROP2(handle, rop2);
+ } else {
+ rop2 = OS.GetROP2(handle);
+ }
+ checkGC(FONT | FOREGROUND_TEXT | BACKGROUND_TEXT);
+ int oldBkMode = OS.SetBkMode(handle, (flags & SWT.DRAW_TRANSPARENT) != 0 ? OS.TRANSPARENT : OS.OPAQUE);
+ if (rop2 != OS.R2_XORPEN) {
+ OS.DrawText(handle, buffer, length, rect, uFormat);
+ } else {
+ int foreground = OS.GetTextColor(handle);
+ if ((flags & SWT.DRAW_TRANSPARENT) != 0) {
+ OS.DrawText(handle, buffer, buffer.length(), rect, uFormat | OS.DT_CALCRECT);
+ int width = rect.right - rect.left;
+ int height = rect.bottom - rect.top;
+ int /*long*/ hBitmap = OS.CreateCompatibleBitmap(handle, width, height);
+ if (hBitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ memDC = OS.CreateCompatibleDC(handle);
+ int /*long*/ hOldBitmap = OS.SelectObject(memDC, hBitmap);
+ OS.PatBlt(memDC, 0, 0, width, height, OS.BLACKNESS);
+ OS.SetBkMode(memDC, OS.TRANSPARENT);
+ OS.SetTextColor(memDC, foreground);
+ OS.SelectObject(memDC, OS.GetCurrentObject(handle, OS.OBJ_FONT));
+ OS.SetRect(rect, 0, 0, 0x7FFF, 0x7FFF);
+ OS.DrawText(memDC, buffer, length, rect, uFormat);
+ OS.BitBlt(handle, x, y, width, height, memDC, 0, 0, OS.SRCINVERT);
+ OS.SelectObject(memDC, hOldBitmap);
+ OS.DeleteDC(memDC);
+ OS.DeleteObject(hBitmap);
+ } else {
+ int background = OS.GetBkColor(handle);
+ OS.SetTextColor(handle, foreground ^ background);
+ OS.DrawText(handle, buffer, length, rect, uFormat);
+ OS.SetTextColor(handle, foreground);
+ }
+ }
+ OS.SetBkMode(handle, oldBkMode);
+}
+
+/**
+ * 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 boolean equals (Object object) {
+ return (object == this) || ((object instanceof GC) && (handle == ((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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(FILL);
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ if (width == 0 || height == 0 || arcAngle == 0) return;
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ if (width == height) {
+ Gdip.Graphics_FillPie(gdipGraphics, data.gdipBrush, x, y, width, height, -startAngle, -arcAngle);
+ } else {
+ int state = Gdip.Graphics_Save(gdipGraphics);
+ Gdip.Graphics_TranslateTransform(gdipGraphics, x, y, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_ScaleTransform(gdipGraphics, width, height, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_FillPie(gdipGraphics, data.gdipBrush, 0, 0, 1, 1, -startAngle, -arcAngle);
+ Gdip.Graphics_Restore(gdipGraphics, state);
+ }
+ return;
+ }
+
+ if ((data.style & SWT.MIRRORED) != 0) x--;
+ /*
+ * Feature in WinCE. The function Pie is not present in the
+ * WinCE SDK. The fix is to emulate it by using Polygon.
+ */
+ if (OS.IsWinCE) {
+ /* compute arc with a simple linear interpolation */
+ if (arcAngle < 0) {
+ startAngle += arcAngle;
+ arcAngle = -arcAngle;
+ }
+ boolean drawSegments = true;
+ if (arcAngle >= 360) {
+ arcAngle = 360;
+ drawSegments = false;
+ }
+ int[] points = new int[(arcAngle + 1) * 2 + (drawSegments ? 4 : 0)];
+ int cteX = 2 * x + width;
+ int cteY = 2 * y + height;
+ int index = (drawSegments ? 2 : 0);
+ for (int i = 0; i <= arcAngle; i++) {
+ points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1;
+ points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1;
+ }
+ if (drawSegments) {
+ points[0] = points[points.length - 2] = cteX >> 1;
+ points[1] = points[points.length - 1] = cteY >> 1;
+ }
+ OS.Polygon(handle, points, points.length / 2);
+ } else {
+ int x1, y1, x2, y2,tmp;
+ boolean isNegative;
+ if (arcAngle >= 360 || arcAngle <= -360) {
+ x1 = x2 = x + width;
+ y1 = y2 = y + height / 2;
+ } else {
+ isNegative = arcAngle < 0;
+
+ arcAngle = arcAngle + startAngle;
+ if (isNegative) {
+ // swap angles
+ tmp = startAngle;
+ startAngle = arcAngle;
+ arcAngle = tmp;
+ }
+ x1 = Compatibility.cos(startAngle, width) + x + width/2;
+ y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2;
+
+ x2 = Compatibility.cos(arcAngle, width) + x + width/2;
+ y2 = -1 * Compatibility.sin(arcAngle, height) + y + height/2;
+ }
+ OS.Pie(handle, x, y, x + width + 1, y + height + 1, x1, y1, x2, y2);
+ }
+}
+
+/**
+ * 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 SWTException <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, boolean vertical) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width == 0 || height == 0) return;
+
+ RGB backgroundRGB, foregroundRGB;
+ backgroundRGB = getBackground().getRGB();
+ foregroundRGB = getForeground().getRGB();
+
+ RGB fromRGB, toRGB;
+ fromRGB = foregroundRGB;
+ toRGB = backgroundRGB;
+
+ boolean 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);
+ return;
+ }
+ if (data.gdipGraphics != 0) {
+ initGdip();
+ PointF p1= new PointF(), p2 = new PointF();
+ p1.X = x;
+ p1.Y = y;
+ if (vertical) {
+ p2.X = p1.X;
+ p2.Y = p1.Y + height;
+ } else {
+ p2.X = p1.X + width;
+ p2.Y = p1.Y;
+ }
+ int rgb = ((fromRGB.red & 0xFF) << 16) | ((fromRGB.green & 0xFF) << 8) | (fromRGB.blue & 0xFF);
+ int /*long*/ fromGpColor = Gdip.Color_new(data.alpha << 24 | rgb);
+ if (fromGpColor == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ rgb = ((toRGB.red & 0xFF) << 16) | ((toRGB.green & 0xFF) << 8) | (toRGB.blue & 0xFF);
+ int /*long*/ toGpColor = Gdip.Color_new(data.alpha << 24 | rgb);
+ if (toGpColor == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ brush = Gdip.LinearGradientBrush_new(p1, p2, fromGpColor, toGpColor);
+ Gdip.Graphics_FillRectangle(data.gdipGraphics, brush, x, y, width, height);
+ Gdip.LinearGradientBrush_delete(brush);
+ Gdip.Color_delete(fromGpColor);
+ Gdip.Color_delete(toGpColor);
+ return;
+ }
+ /* Use GradientFill if supported, only on Windows 98, 2000 and newer. */
+ /*
+ * Bug in Windows: On Windows 2000 when the device is a printer,
+ * GradientFill swaps red and blue color components, causing the
+ * gradient to be printed in the wrong color. On Windows 98 when
+ * the device is a printer, GradientFill does not fill completely
+ * to the right edge of the rectangle. The fix is not to use
+ * GradientFill for printer devices.
+ */
+ int rop2 = 0;
+ if (OS.IsWinCE) {
+ rop2 = OS.SetROP2(handle, OS.R2_COPYPEN);
+ OS.SetROP2(handle, rop2);
+ } else {
+ rop2 = OS.GetROP2(handle);
+ }
+ if (OS.IsWinNT && rop2 != OS.R2_XORPEN && OS.GetDeviceCaps(handle, OS.TECHNOLOGY) != OS.DT_RASPRINTER) {
+ final int /*long*/ hHeap = OS.GetProcessHeap();
+ final int /*long*/ pMesh = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, GRADIENT_RECT.sizeof + TRIVERTEX.sizeof * 2);
+ if (pMesh == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ final int /*long*/ pVertex = pMesh + GRADIENT_RECT.sizeof;
+
+ GRADIENT_RECT gradientRect = new GRADIENT_RECT();
+ gradientRect.UpperLeft = 0;
+ gradientRect.LowerRight = 1;
+ OS.MoveMemory(pMesh, gradientRect, GRADIENT_RECT.sizeof);
+
+ TRIVERTEX trivertex = new TRIVERTEX();
+ trivertex.x = x;
+ trivertex.y = y;
+ trivertex.Red = (short)((fromRGB.red << 8) | fromRGB.red);
+ trivertex.Green = (short)((fromRGB.green << 8) | fromRGB.green);
+ trivertex.Blue = (short)((fromRGB.blue << 8) | fromRGB.blue);
+ trivertex.Alpha = -1;
+ OS.MoveMemory(pVertex, trivertex, TRIVERTEX.sizeof);
+
+ trivertex.x = x + width;
+ trivertex.y = y + height;
+ trivertex.Red = (short)((toRGB.red << 8) | toRGB.red);
+ trivertex.Green = (short)((toRGB.green << 8) | toRGB.green);
+ trivertex.Blue = (short)((toRGB.blue << 8) | toRGB.blue);
+ trivertex.Alpha = -1;
+ OS.MoveMemory(pVertex + TRIVERTEX.sizeof, trivertex, TRIVERTEX.sizeof);
+
+ boolean success = OS.GradientFill(handle, pVertex, 2, pMesh, 1, vertical ? OS.GRADIENT_FILL_RECT_V : OS.GRADIENT_FILL_RECT_H);
+ OS.HeapFree(hHeap, 0, pMesh);
+ if (success) return;
+ }
+
+ final int depth = OS.GetDeviceCaps(handle, OS.BITSPIXEL);
+ final int bitResolution = (depth >= 24) ? 8 : (depth >= 15) ? 5 : 0;
+ ImageData.fillGradientRectangle(this, data.device,
+ x, y, width, height, vertical, fromRGB, toRGB,
+ bitResolution, bitResolution, bitResolution);
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(FILL);
+ if (data.gdipGraphics != 0) {
+ Gdip.Graphics_FillEllipse(data.gdipGraphics, data.gdipBrush, x, y, width, height);
+ return;
+ }
+ if ((data.style & SWT.MIRRORED) != 0) x--;
+ OS.Ellipse(handle, x, y, x + width + 1, y + height + 1);
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (path.handle == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ initGdip();
+ checkGC(FILL);
+ int mode = OS.GetPolyFillMode(handle) == OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate;
+ Gdip.GraphicsPath_SetFillMode(path.handle, mode);
+ Gdip.Graphics_FillPath(data.gdipGraphics, data.gdipBrush, path.handle);
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #drawPolygon
+ */
+public void fillPolygon(int[] pointArray) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ checkGC(FILL);
+ if (data.gdipGraphics != 0) {
+ int mode = OS.GetPolyFillMode(handle) == OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate;
+ Gdip.Graphics_FillPolygon(data.gdipGraphics, data.gdipBrush, pointArray, pointArray.length / 2, mode);
+ return;
+ }
+ if ((data.style & SWT.MIRRORED) != 0) {
+ for (int i = 0; i < pointArray.length; i+=2) {
+ pointArray[i]--;
+ }
+ }
+ OS.Polygon(handle, pointArray, pointArray.length / 2);
+ if ((data.style & SWT.MIRRORED) != 0) {
+ for (int i = 0; i < pointArray.length; i+=2) {
+ pointArray[i]++;
+ }
+ }
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(FILL);
+ if (data.gdipGraphics != 0) {
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ Gdip.Graphics_FillRectangle(data.gdipGraphics, data.gdipBrush, x, y, width, height);
+ return;
+ }
+ int rop2 = 0;
+ if (OS.IsWinCE) {
+ rop2 = OS.SetROP2(handle, OS.R2_COPYPEN);
+ OS.SetROP2(handle, rop2);
+ } else {
+ rop2 = OS.GetROP2(handle);
+ }
+ int dwRop = rop2 == OS.R2_XORPEN ? OS.PATINVERT : OS.PATCOPY;
+ OS.PatBlt(handle, x, y, width, height, dwRop);
+}
+
+/**
+ * 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 SWTException <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 (rect == null) SWT.error(SWT.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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(FILL);
+ if (data.gdipGraphics != 0) {
+ fillRoundRectangleGdip(data.gdipGraphics, data.gdipBrush, x, y, width, height, arcWidth, arcHeight);
+ return;
+ }
+ if ((data.style & SWT.MIRRORED) != 0) x--;
+ OS.RoundRect(handle, x,y,x+width+1,y+height+1,arcWidth, arcHeight);
+}
+
+void fillRoundRectangleGdip (int /*long*/ gdipGraphics, int /*long*/ brush, int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ int nx = x;
+ int ny = y;
+ int nw = width;
+ int nh = height;
+ int naw = arcWidth;
+ int nah = arcHeight;
+
+ if (nw < 0) {
+ nw = 0 - nw;
+ nx = nx - nw;
+ }
+ if (nh < 0) {
+ nh = 0 - nh;
+ ny = ny -nh;
+ }
+ if (naw < 0)
+ naw = 0 - naw;
+ if (nah < 0)
+ nah = 0 - nah;
+
+ if (naw == 0 || nah == 0) {
+ Gdip.Graphics_FillRectangle(data.gdipGraphics, data.gdipBrush, x, y, width, height);
+ } else {
+ int /*long*/ path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
+ if (path == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ if (nw > naw) {
+ if (nh > nah) {
+ Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nah, 0, -90);
+ Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nah, -90, -90);
+ Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, naw, nah, -180, -90);
+ Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny + nh - nah, naw, nah, -270, -90);
+ } else {
+ Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nh, -270, -180);
+ Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nh, -90, -180);
+ }
+ } else {
+ if (nh > nah) {
+ Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nah, 0, -180);
+ Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, nw, nah, -180, -180);
+ } else {
+ Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nh, 0, 360);
+ }
+ }
+ Gdip.GraphicsPath_CloseFigure(path);
+ Gdip.Graphics_FillPath(gdipGraphics, brush, path);
+ Gdip.GraphicsPath_delete(path);
+ }
+}
+
+void flush () {
+ if (data.gdipGraphics != 0) {
+ Gdip.Graphics_Flush(data.gdipGraphics, 0);
+ /*
+ * Note Flush() does not flush the output to the
+ * underline HDC. This is done by calling GetHDC()
+ * followed by ReleaseHDC().
+ */
+ int /*long*/ hdc = Gdip.Graphics_GetHDC(data.gdipGraphics);
+ Gdip.Graphics_ReleaseHDC(data.gdipGraphics, hdc);
+ }
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getAdvanceWidth(char ch) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(FONT);
+ if (OS.IsWinCE) {
+ SIZE size = new SIZE();
+ OS.GetTextExtentPoint32W(handle, new char[]{ch}, 1, size);
+ return size.cx;
+ }
+ int tch = ch;
+ if (ch > 0x7F) {
+ TCHAR buffer = new TCHAR(getCodePage(), ch, false);
+ tch = buffer.tcharAt(0);
+ }
+ int[] width = new int[1];
+ OS.GetCharWidth(handle, tch, tch, width);
+ return width[0];
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setAdvanced
+ *
+ * @since 3.1
+ */
+public boolean getAdvanced() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.gdipGraphics != 0;
+}
+
+/**
+ * Returns the receiver's alpha value. The alpha value
+ * is between 0 (transparent) and 255 (opaque).
+ *
+ * @return the alpha value
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getAlpha() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.alpha;
+}
+
+/**
+ * Returns the receiver's anti-aliasing setting value, which will be
+ * one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or
+ * <code>SWT.ON</code>. Note that this controls anti-aliasing for all
+ * <em>non-text drawing</em> operations.
+ *
+ * @return the anti-aliasing setting
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getTextAntialias
+ *
+ * @since 3.1
+ */
+public int getAntialias() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.gdipGraphics == 0) return SWT.DEFAULT;
+ int mode = Gdip.Graphics_GetSmoothingMode(data.gdipGraphics);
+ switch (mode) {
+ case Gdip.SmoothingModeDefault: return SWT.DEFAULT;
+ case Gdip.SmoothingModeHighSpeed:
+ case Gdip.SmoothingModeNone: return SWT.OFF;
+ case Gdip.SmoothingModeAntiAlias:
+ case Gdip.SmoothingModeAntiAlias8x8:
+ case Gdip.SmoothingModeHighQuality: return SWT.ON;
+ }
+ return SWT.DEFAULT;
+}
+
+/**
+ * Returns the background color.
+ *
+ * @return the receiver's background color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getBackground() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return Color.win32_new(data.device, data.background);
+}
+
+/**
+ * Returns the background pattern. The default value is
+ * <code>null</code>.
+ *
+ * @return the receiver's background pattern
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Pattern
+ *
+ * @since 3.1
+ */
+public Pattern getBackgroundPattern() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.backgroundPattern;
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getCharWidth(char ch) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(FONT);
+
+ /* GetCharABCWidths only succeeds on truetype fonts */
+ if (!OS.IsWinCE) {
+ int tch = ch;
+ if (ch > 0x7F) {
+ TCHAR buffer = new TCHAR(getCodePage(), ch, false);
+ tch = buffer.tcharAt (0);
+ }
+ int[] width = new int[3];
+ if (OS.GetCharABCWidths(handle, tch, tch, width)) {
+ return width[1];
+ }
+ }
+
+ /* It wasn't a truetype font */
+ TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
+ OS.GetTextMetrics(handle, lptm);
+ SIZE size = new SIZE();
+ OS.GetTextExtentPoint32W(handle, new char[]{ch}, 1, size);
+ return size.cx - lptm.tmOverhang;
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getClipping() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ Rect rect = new Rect();
+ Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone);
+ Gdip.Graphics_GetVisibleClipBounds(gdipGraphics, rect);
+ Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf);
+ return new Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
+ }
+ RECT rect = new RECT();
+ OS.GetClipBox(handle, rect);
+ return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void getClipping (Region region) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (region == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ if (region.isDisposed()) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ int /*long*/ rgn = Gdip.Region_new();
+ Gdip.Graphics_GetClip(data.gdipGraphics, rgn);
+ if (Gdip.Region_IsInfinite(rgn, gdipGraphics)) {
+ Rect rect = new Rect();
+ Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone);
+ Gdip.Graphics_GetVisibleClipBounds(gdipGraphics, rect);
+ Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf);
+ OS.SetRectRgn(region.handle, rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
+ } else {
+ int /*long*/ matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
+ int /*long*/ identity = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
+ Gdip.Graphics_GetTransform(gdipGraphics, matrix);
+ Gdip.Graphics_SetTransform(gdipGraphics, identity);
+ int /*long*/ hRgn = Gdip.Region_GetHRGN(rgn, data.gdipGraphics);
+ Gdip.Graphics_SetTransform(gdipGraphics, matrix);
+ Gdip.Matrix_delete(identity);
+ Gdip.Matrix_delete(matrix);
+ if (!OS.IsWinCE) {
+ POINT pt = new POINT ();
+ OS.GetWindowOrgEx (handle, pt);
+ OS.OffsetRgn (hRgn, pt.x, pt.y);
+ }
+ OS.CombineRgn(region.handle, hRgn, 0, OS.RGN_COPY);
+ OS.DeleteObject(hRgn);
+ }
+ Gdip.Region_delete(rgn);
+ return;
+ }
+ POINT pt = new POINT ();
+ if (!OS.IsWinCE) OS.GetWindowOrgEx (handle, pt);
+ int result = OS.GetClipRgn (handle, region.handle);
+ if (result != 1) {
+ RECT rect = new RECT();
+ OS.GetClipBox(handle, rect);
+ OS.SetRectRgn(region.handle, rect.left, rect.top, rect.right, rect.bottom);
+ } else {
+ OS.OffsetRgn (region.handle, pt.x, pt.y);
+ }
+ if (!OS.IsWinCE) {
+ int /*long*/ metaRgn = OS.CreateRectRgn (0, 0, 0, 0);
+ if (OS.GetMetaRgn (handle, metaRgn) != 0) {
+ OS.OffsetRgn (metaRgn, pt.x, pt.y);
+ OS.CombineRgn (region.handle, metaRgn, region.handle, OS.RGN_AND);
+ }
+ OS.DeleteObject(metaRgn);
+ int /*long*/ hwnd = data.hwnd;
+ if (hwnd != 0 && data.ps != null) {
+ int /*long*/ sysRgn = OS.CreateRectRgn (0, 0, 0, 0);
+ if (OS.GetRandomRgn (handle, sysRgn, OS.SYSRGN) == 1) {
+ if (OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
+ if ((OS.GetLayout(handle) & OS.LAYOUT_RTL) != 0) {
+ int nBytes = OS.GetRegionData (sysRgn, 0, null);
+ int [] lpRgnData = new int [nBytes / 4];
+ OS.GetRegionData (sysRgn, nBytes, lpRgnData);
+ int /*long*/ newSysRgn = OS.ExtCreateRegion(new float [] {-1, 0, 0, 1, 0, 0}, nBytes, lpRgnData);
+ OS.DeleteObject(sysRgn);
+ sysRgn = newSysRgn;
+ }
+ }
+ if (OS.IsWinNT) {
+ OS.MapWindowPoints(0, hwnd, pt, 1);
+ OS.OffsetRgn(sysRgn, pt.x, pt.y);
+ }
+ OS.CombineRgn (region.handle, sysRgn, region.handle, OS.RGN_AND);
+ }
+ OS.DeleteObject(sysRgn);
+ }
+ }
+}
+
+int getCodePage () {
+ if (OS.IsUnicode) return OS.CP_ACP;
+ int[] lpCs = new int[8];
+ int cs = OS.GetTextCharset(handle);
+ OS.TranslateCharsetInfo(cs, lpCs, OS.TCI_SRCCHARSET);
+ return lpCs[1];
+}
+
+int /*long*/ getFgBrush() {
+ return data.foregroundPattern != null ? data.foregroundPattern.handle : data.gdipFgBrush;
+}
+
+/**
+ * Returns the receiver's fill rule, which will be one of
+ * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>.
+ *
+ * @return the receiver's fill rule
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getFillRule() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (OS.IsWinCE) return SWT.FILL_EVEN_ODD;
+ return OS.GetPolyFillMode(handle) == OS.WINDING ? SWT.FILL_WINDING : SWT.FILL_EVEN_ODD;
+}
+
+/**
+ * Returns the font currently being used by the receiver
+ * to draw and measure text.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Font getFont () {
+ if (handle == 0) SWT.error(SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontMetrics getFontMetrics() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ checkGC(FONT);
+ TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
+ OS.GetTextMetrics(handle, lptm);
+ return FontMetrics.win32_new(lptm);
+}
+
+/**
+ * Returns the receiver's foreground color.
+ *
+ * @return the color used for drawing foreground things
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getForeground() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return Color.win32_new(data.device, data.foreground);
+}
+
+/**
+ * Returns the foreground pattern. The default value is
+ * <code>null</code>.
+ *
+ * @return the receiver's foreground pattern
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Pattern
+ *
+ * @since 3.1
+ */
+public Pattern getForegroundPattern() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_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 SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @return the receiver's GCData
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see GCData
+ *
+ * @since 3.2
+ * @noreference This method is not intended to be referenced by clients.
+ */
+public GCData getGCData() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data;
+}
+
+/**
+ * Returns the receiver's interpolation setting, which will be one of
+ * <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>,
+ * <code>SWT.LOW</code> or <code>SWT.HIGH</code>.
+ *
+ * @return the receiver's interpolation setting
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getInterpolation() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.gdipGraphics == 0) return SWT.DEFAULT;
+ int mode = Gdip.Graphics_GetInterpolationMode(data.gdipGraphics);
+ switch (mode) {
+ case Gdip.InterpolationModeDefault: return SWT.DEFAULT;
+ case Gdip.InterpolationModeNearestNeighbor: return SWT.NONE;
+ case Gdip.InterpolationModeBilinear:
+ case Gdip.InterpolationModeLowQuality: return SWT.LOW;
+ case Gdip.InterpolationModeBicubic:
+ case Gdip.InterpolationModeHighQualityBilinear:
+ case Gdip.InterpolationModeHighQualityBicubic:
+ case Gdip.InterpolationModeHighQuality: return SWT.HIGH;
+ }
+ return SWT.DEFAULT;
+}
+
+/**
+ * Returns the receiver's line attributes.
+ *
+ * @return the line attributes used for drawing lines
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.3
+ */
+public LineAttributes getLineAttributes() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ float[] dashes = null;
+ if (data.lineDashes != 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>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>,
+ * or <code>SWT.CAP_SQUARE</code>.
+ *
+ * @return the cap style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getLineCap() {
+ if (handle == 0) SWT.error(SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int[] getLineDash() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.lineDashes == 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>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>,
+ * or <code>SWT.JOIN_BEVEL</code>.
+ *
+ * @return the join style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public int getLineJoin() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.lineJoin;
+}
+
+/**
+ * Returns the receiver's line style, which will be one
+ * of the constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>,
+ * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or
+ * <code>SWT.LINE_DASHDOTDOT</code>.
+ *
+ * @return the style used for drawing lines
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineStyle() {
+ if (handle == 0) SWT.error(SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineWidth() {
+ if (handle == 0) SWT.error(SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 2.1.2
+ */
+public int getStyle () {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return data.style;
+}
+
+/**
+ * Returns the receiver's text drawing anti-aliasing setting value,
+ * which will be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or
+ * <code>SWT.ON</code>. Note that this controls anti-aliasing
+ * <em>only</em> for text drawing operations.
+ *
+ * @return the anti-aliasing setting
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getAntialias
+ *
+ * @since 3.1
+ */
+public int getTextAntialias() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.gdipGraphics == 0) return SWT.DEFAULT;
+ int mode = Gdip.Graphics_GetTextRenderingHint(data.gdipGraphics);
+ switch (mode) {
+ case Gdip.TextRenderingHintSystemDefault: return SWT.DEFAULT;
+ case Gdip.TextRenderingHintSingleBitPerPixel:
+ case Gdip.TextRenderingHintSingleBitPerPixelGridFit: return SWT.OFF;
+ case Gdip.TextRenderingHintAntiAlias:
+ case Gdip.TextRenderingHintAntiAliasGridFit:
+ case Gdip.TextRenderingHintClearTypeGridFit: return SWT.ON;
+ }
+ return SWT.DEFAULT;
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (transform == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ Gdip.Graphics_GetTransform(gdipGraphics, transform.handle);
+ int /*long*/ identity = identity();
+ Gdip.Matrix_Invert(identity);
+ Gdip.Matrix_Multiply(transform.handle, identity, Gdip.MatrixOrderAppend);
+ Gdip.Matrix_delete(identity);
+ } 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean getXORMode() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ int rop2 = 0;
+ if (OS.IsWinCE) {
+ rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN);
+ OS.SetROP2 (handle, rop2);
+ } else {
+ rop2 = OS.GetROP2(handle);
+ }
+ return rop2 == OS.R2_XORPEN;
+}
+
+void initGdip() {
+ data.device.checkGDIP();
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) return;
+ /*
+ * Feature in GDI+. The GDI+ clipping set with Graphics->SetClip()
+ * is always intersected with the GDI clipping at the time the
+ * GDI+ graphics is created. This means that the clipping
+ * cannot be reset. The fix is to clear the clipping before
+ * the GDI+ graphics is created and reset it afterwards.
+ */
+ int /*long*/ hRgn = OS.CreateRectRgn(0, 0, 0, 0);
+ int result = OS.GetClipRgn(handle, hRgn);
+ if (!OS.IsWinCE) {
+ POINT pt = new POINT ();
+ OS.GetWindowOrgEx (handle, pt);
+ OS.OffsetRgn (hRgn, pt.x, pt.y);
+ }
+ OS.SelectClipRgn(handle, 0);
+
+ /*
+ * Bug in GDI+. GDI+ does not work when the HDC layout is RTL. There
+ * are many issues like pixel corruption, but the most visible problem
+ * is that it does not have an effect when drawing to an bitmap. The
+ * fix is to clear the bit before creating the GDI+ graphics and install
+ * a mirroring matrix ourselves.
+ */
+ if ((data.style & SWT.MIRRORED) != 0) {
+ OS.SetLayout(handle, OS.GetLayout(handle) & ~OS.LAYOUT_RTL);
+ }
+
+ gdipGraphics = data.gdipGraphics = Gdip.Graphics_new(handle);
+ if (gdipGraphics == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.Graphics_SetPageUnit(gdipGraphics, Gdip.UnitPixel);
+ Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf);
+ if ((data.style & SWT.MIRRORED) != 0) {
+ int /*long*/ matrix = identity();
+ Gdip.Graphics_SetTransform(gdipGraphics, matrix);
+ Gdip.Matrix_delete(matrix);
+ }
+ if (result == 1) setClipping(hRgn);
+ OS.DeleteObject(hRgn);
+ data.state = 0;
+ if (data.hPen != 0) {
+ OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN));
+ OS.DeleteObject(data.hPen);
+ data.hPen = 0;
+ }
+ if (data.hBrush != 0) {
+ OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH));
+ OS.DeleteObject(data.hBrush);
+ data.hBrush = 0;
+ }
+}
+
+int /*long*/ identity() {
+ if ((data.style & SWT.MIRRORED) != 0) {
+ int width = 0;
+ int technology = OS.GetDeviceCaps(handle, OS.TECHNOLOGY);
+ if (technology == OS.DT_RASPRINTER) {
+ width = OS.GetDeviceCaps(handle, OS.PHYSICALWIDTH);
+ } else {
+ Image image = data.image;
+ if (image != null) {
+ BITMAP bm = new BITMAP();
+ OS.GetObject(image.handle, BITMAP.sizeof, bm);
+ width = bm.bmWidth;
+ } else {
+ int /*long*/ hwnd = OS.IsWinCE ? data.hwnd : OS.WindowFromDC(handle);
+ if (hwnd != 0) {
+ RECT rect = new RECT();
+ OS.GetClientRect(hwnd, rect);
+ width = rect.right - rect.left;
+ } else {
+ int /*long*/ hBitmap = OS.GetCurrentObject(handle, OS.OBJ_BITMAP);
+ BITMAP bm = new BITMAP();
+ OS.GetObject(hBitmap, BITMAP.sizeof, bm);
+ width = bm.bmWidth;
+ }
+ }
+ }
+ POINT pt = new POINT ();
+ if (!OS.IsWinCE) OS.GetWindowOrgEx (handle, pt);
+ return Gdip.Matrix_new(-1, 0, 0, 1, width + 2 * pt.x, 0);
+ }
+ return Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
+}
+
+void init(Drawable drawable, GCData data, int /*long*/ hDC) {
+ int foreground = data.foreground;
+ if (foreground != -1) {
+ data.state &= ~(FOREGROUND | FOREGROUND_TEXT | PEN);
+ } else {
+ data.foreground = OS.GetTextColor(hDC);
+ }
+ int background = data.background;
+ if (background != -1) {
+ data.state &= ~(BACKGROUND | BACKGROUND_TEXT | BRUSH);
+ } else {
+ data.background = OS.GetBkColor(hDC);
+ }
+ data.state &= ~(NULL_BRUSH | NULL_PEN);
+ Font font = data.font;
+ if (font != null) {
+ data.state &= ~FONT;
+ } else {
+ data.font = Font.win32_new(device, OS.GetCurrentObject(hDC, OS.OBJ_FONT));
+ }
+ int /*long*/ hPalette = data.device.hPalette;
+ if (hPalette != 0) {
+ OS.SelectPalette(hDC, hPalette, true);
+ OS.RealizePalette(hDC);
+ }
+ Image image = data.image;
+ if (image != null) {
+ data.hNullBitmap = OS.SelectObject(hDC, image.handle);
+ image.memGC = this;
+ }
+ int layout = data.layout;
+ if (layout != -1) {
+ if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
+ int flags = OS.GetLayout(hDC);
+ if ((flags & OS.LAYOUT_RTL) != (layout & OS.LAYOUT_RTL)) {
+ flags &= ~OS.LAYOUT_RTL;
+ OS.SetLayout(hDC, flags | layout);
+ }
+ if ((data.style & SWT.RIGHT_TO_LEFT) != 0) data.style |= SWT.MIRRORED;
+ }
+ }
+ this.drawable = drawable;
+ this.data = data;
+ handle = hDC;
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #equals
+ */
+public int hashCode () {
+ return (int)/*64*/handle;
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean isClipped() {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ int /*long*/ rgn = Gdip.Region_new();
+ Gdip.Graphics_GetClip(data.gdipGraphics, rgn);
+ boolean isInfinite = Gdip.Region_IsInfinite(rgn, gdipGraphics);
+ Gdip.Region_delete(rgn);
+ return !isInfinite;
+ }
+ int /*long*/ region = OS.CreateRectRgn(0, 0, 0, 0);
+ int result = OS.GetClipRgn(handle, region);
+ OS.DeleteObject(region);
+ return result > 0;
+}
+
+/**
+ * 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 boolean isDisposed() {
+ return handle == 0;
+}
+
+float measureSpace(int /*long*/ font, int /*long*/ format) {
+ PointF pt = new PointF();
+ RectF bounds = new RectF();
+ Gdip.Graphics_MeasureString(data.gdipGraphics, new char[]{' '}, 1, font, pt, format, bounds);
+ return bounds.Width;
+}
+
+/**
+ * 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 SWTException <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(boolean advanced) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (advanced && data.gdipGraphics != 0) return;
+ if (advanced) {
+ try {
+ initGdip();
+ } catch (SWTException e) {}
+ } else {
+ disposeGdip();
+ data.alpha = 0xFF;
+ data.backgroundPattern = data.foregroundPattern = null;
+ data.state = 0;
+ setClipping(0);
+ if ((data.style & SWT.MIRRORED) != 0) {
+ OS.SetLayout(handle, OS.GetLayout(handle) | OS.LAYOUT_RTL);
+ }
+ }
+}
+
+/**
+ * Sets the receiver's anti-aliasing value to the parameter,
+ * which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code>
+ * or <code>SWT.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>SWT.DEFAULT</code>,
+ * <code>SWT.OFF</code> or <code>SWT.ON</code></li>
+ * </ul>
+ * @exception SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.gdipGraphics == 0 && antialias == SWT.DEFAULT) return;
+ int mode = 0;
+ switch (antialias) {
+ case SWT.DEFAULT:
+ mode = Gdip.SmoothingModeDefault;
+ break;
+ case SWT.OFF:
+ mode = Gdip.SmoothingModeNone;
+ break;
+ case SWT.ON:
+ mode = Gdip.SmoothingModeAntiAlias;
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ initGdip();
+ Gdip.Graphics_SetSmoothingMode(data.gdipGraphics, mode);
+}
+
+/**
+ * Sets the receiver's alpha value which must be
+ * between 0 (transparent) and 255 (opaque).
+ * <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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.gdipGraphics == 0 && (alpha & 0xFF) == 0xFF) return;
+ initGdip();
+ data.alpha = alpha & 0xFF;
+ data.state &= ~(BACKGROUND | FOREGROUND);
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setBackground (Color color) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (data.backgroundPattern == null && data.background == color.handle) return;
+ data.backgroundPattern = null;
+ data.background = color.handle;
+ data.state &= ~(BACKGROUND | BACKGROUND_TEXT);
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pattern != null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (data.gdipGraphics == 0 && pattern == null) return;
+ initGdip();
+ if (data.backgroundPattern == pattern) return;
+ data.backgroundPattern = pattern;
+ data.state &= ~BACKGROUND;
+}
+
+void setClipping(int /*long*/ clipRgn) {
+ int /*long*/ hRgn = clipRgn;
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ if (hRgn != 0) {
+ int /*long*/ region = Gdip.Region_new(hRgn);
+ Gdip.Graphics_SetClip(gdipGraphics, region, Gdip.CombineModeReplace);
+ Gdip.Region_delete(region);
+ } else {
+ Gdip.Graphics_ResetClip(gdipGraphics);
+ }
+ } else {
+ POINT pt = null;
+ if (hRgn != 0 && !OS.IsWinCE) {
+ pt = new POINT();
+ OS.GetWindowOrgEx(handle, pt);
+ OS.OffsetRgn(hRgn, -pt.x, -pt.y);
+ }
+ OS.SelectClipRgn(handle, hRgn);
+ if (hRgn != 0 && !OS.IsWinCE) {
+ OS.OffsetRgn(hRgn, pt.x, pt.y);
+ }
+ }
+ if (hRgn != 0 && hRgn != clipRgn) {
+ OS.DeleteObject(hRgn);
+ }
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ int /*long*/ hRgn = OS.CreateRectRgn(x, y, x + width, y + height);
+ setClipping(hRgn);
+ OS.DeleteObject(hRgn);
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (path != null && path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ setClipping(0);
+ if (path != null) {
+ initGdip();
+ int mode = OS.GetPolyFillMode(handle) == OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate;
+ Gdip.GraphicsPath_SetFillMode(path.handle, mode);
+ Gdip.Graphics_SetClipPath(data.gdipGraphics, path.handle);
+ }
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping (Rectangle rect) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) {
+ setClipping(0);
+ } 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setClipping (Region region) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (region != null && region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ setClipping(region != null ? region.handle : 0);
+}
+
+/**
+ * Sets the receiver's fill rule to the parameter, which must be one of
+ * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>.
+ *
+ * @param rule the new fill rule
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>SWT.FILL_EVEN_ODD</code>
+ * or <code>SWT.FILL_WINDING</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setFillRule(int rule) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (OS.IsWinCE) return;
+ int mode = OS.ALTERNATE;
+ switch (rule) {
+ case SWT.FILL_WINDING: mode = OS.WINDING; break;
+ case SWT.FILL_EVEN_ODD: mode = OS.ALTERNATE; break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ OS.SetPolyFillMode(handle, mode);
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setFont (Font font) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ data.font = font != 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setForeground (Color color) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (data.foregroundPattern == null && color.handle == data.foreground) return;
+ data.foregroundPattern = null;
+ data.foreground = color.handle;
+ data.state &= ~(FOREGROUND | FOREGROUND_TEXT);
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pattern != null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (data.gdipGraphics == 0 && pattern == null) return;
+ initGdip();
+ if (data.foregroundPattern == pattern) return;
+ data.foregroundPattern = pattern;
+ data.state &= ~FOREGROUND;
+}
+
+/**
+ * Sets the receiver's interpolation setting to the parameter, which
+ * must be one of <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>,
+ * <code>SWT.LOW</code> or <code>SWT.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>SWT.DEFAULT</code>,
+ * <code>SWT.NONE</code>, <code>SWT.LOW</code> or <code>SWT.HIGH</code>
+ * </ul>
+ * @exception SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.gdipGraphics == 0 && interpolation == SWT.DEFAULT) return;
+ int mode = 0;
+ switch (interpolation) {
+ case SWT.DEFAULT: mode = Gdip.InterpolationModeDefault; break;
+ case SWT.NONE: mode = Gdip.InterpolationModeNearestNeighbor; break;
+ case SWT.LOW: mode = Gdip.InterpolationModeLowQuality; break;
+ case SWT.HIGH: mode = Gdip.InterpolationModeHighQuality; break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ initGdip();
+ Gdip.Graphics_SetInterpolationMode(data.gdipGraphics, mode);
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (attributes == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ int mask = 0;
+ float lineWidth = attributes.width;
+ if (lineWidth != data.lineWidth) {
+ mask |= LINE_WIDTH | DRAW_OFFSET;
+ }
+ int lineStyle = attributes.style;
+ if (lineStyle != data.lineStyle) {
+ mask |= LINE_STYLE;
+ switch (lineStyle) {
+ case SWT.LINE_SOLID:
+ case SWT.LINE_DASH:
+ case SWT.LINE_DOT:
+ case SWT.LINE_DASHDOT:
+ case SWT.LINE_DASHDOTDOT:
+ break;
+ case SWT.LINE_CUSTOM:
+ if (attributes.dash == null) lineStyle = SWT.LINE_SOLID;
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ int join = attributes.join;
+ if (join != data.lineJoin) {
+ mask |= LINE_JOIN;
+ switch (join) {
+ case SWT.CAP_ROUND:
+ case SWT.CAP_FLAT:
+ case SWT.CAP_SQUARE:
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ int cap = attributes.cap;
+ if (cap != data.lineCap) {
+ mask |= LINE_CAP;
+ switch (cap) {
+ case SWT.JOIN_MITER:
+ case SWT.JOIN_ROUND:
+ case SWT.JOIN_BEVEL:
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+ float[] dashes = attributes.dash;
+ float[] lineDashes = data.lineDashes;
+ if (dashes != null && dashes.length > 0) {
+ boolean changed = lineDashes == null || lineDashes.length != dashes.length;
+ for (int i = 0; i < dashes.length; i++) {
+ float dash = dashes[i];
+ if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (!changed && lineDashes[i] != 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 != null && lineDashes.length > 0) {
+ mask |= LINE_STYLE;
+ } else {
+ dashes = lineDashes;
+ }
+ }
+ float dashOffset = attributes.dashOffset;
+ if (dashOffset != data.lineDashesOffset) {
+ mask |= LINE_STYLE;
+ }
+ float miterLimit = attributes.miterLimit;
+ if (miterLimit != data.lineMiterLimit) {
+ mask |= LINE_MITERLIMIT;
+ }
+ initGdip();
+ if (mask == 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>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>,
+ * or <code>SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setLineCap(int cap) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.lineCap == cap) return;
+ switch (cap) {
+ case SWT.CAP_ROUND:
+ case SWT.CAP_FLAT:
+ case SWT.CAP_SQUARE:
+ break;
+ default:
+ SWT.error(SWT.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>SWT.LINE_CUSTOM</code>, otherwise
+ * it is set to <code>SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setLineDash(int[] dashes) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ float[] lineDashes = data.lineDashes;
+ if (dashes != null && dashes.length > 0) {
+ boolean changed = data.lineStyle != SWT.LINE_CUSTOM || lineDashes == null || lineDashes.length != dashes.length;
+ for (int i = 0; i < dashes.length; i++) {
+ int dash = dashes[i];
+ if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (!changed && lineDashes[i] != 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 = SWT.LINE_CUSTOM;
+ } else {
+ if (data.lineStyle == SWT.LINE_SOLID && (lineDashes == null || lineDashes.length == 0)) return;
+ data.lineDashes = null;
+ data.lineStyle = SWT.LINE_SOLID;
+ }
+ data.state &= ~LINE_STYLE;
+}
+
+/**
+ * Sets the receiver's line join style to the argument, which must be one
+ * of the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>,
+ * or <code>SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void setLineJoin(int join) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.lineJoin == join) return;
+ switch (join) {
+ case SWT.JOIN_MITER:
+ case SWT.JOIN_ROUND:
+ case SWT.JOIN_BEVEL:
+ break;
+ default:
+ SWT.error(SWT.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>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>,
+ * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or
+ * <code>SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setLineStyle(int lineStyle) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.lineStyle == lineStyle) return;
+ switch (lineStyle) {
+ case SWT.LINE_SOLID:
+ case SWT.LINE_DASH:
+ case SWT.LINE_DOT:
+ case SWT.LINE_DASHDOT:
+ case SWT.LINE_DASHDOTDOT:
+ break;
+ case SWT.LINE_CUSTOM:
+ if (data.lineDashes == null) lineStyle = SWT.LINE_SOLID;
+ break;
+ default:
+ SWT.error(SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setLineWidth(int lineWidth) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.lineWidth == 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 SWTException <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(boolean xor) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ OS.SetROP2(handle, xor ? OS.R2_XORPEN : OS.R2_COPYPEN);
+}
+
+/**
+ * Sets the receiver's text anti-aliasing value to the parameter,
+ * which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code>
+ * or <code>SWT.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>SWT.DEFAULT</code>,
+ * <code>SWT.OFF</code> or <code>SWT.ON</code></li>
+ * </ul>
+ * @exception SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (data.gdipGraphics == 0 && antialias == SWT.DEFAULT) return;
+ int textMode = 0;
+ switch (antialias) {
+ case SWT.DEFAULT:
+ textMode = Gdip.TextRenderingHintSystemDefault;
+ break;
+ case SWT.OFF:
+ textMode = Gdip.TextRenderingHintSingleBitPerPixelGridFit;
+ break;
+ case SWT.ON:
+ int[] type = new int[1];
+ OS.SystemParametersInfo(OS.SPI_GETFONTSMOOTHINGTYPE, 0, type, 0);
+ if (type[0] == OS.FE_FONTSMOOTHINGCLEARTYPE) {
+ textMode = Gdip.TextRenderingHintClearTypeGridFit;
+ } else {
+ textMode = Gdip.TextRenderingHintAntiAliasGridFit;
+ }
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ initGdip();
+ Gdip.Graphics_SetTextRenderingHint(data.gdipGraphics, textMode);
+}
+
+/**
+ * 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 SWTException <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 == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (transform != null && transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (data.gdipGraphics == 0 && transform == null) return;
+ initGdip();
+ int /*long*/ identity = identity();
+ if (transform != null) {
+ Gdip.Matrix_Multiply(identity, transform.handle, Gdip.MatrixOrderPrepend);
+ }
+ Gdip.Graphics_SetTransform(data.gdipGraphics, identity);
+ Gdip.Matrix_delete(identity);
+ data.state &= ~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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point stringExtent(String string) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ checkGC(FONT);
+ int length = string.length();
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ if (gdipGraphics != 0) {
+ RectF bounds = new RectF();
+ char[] buffer;
+ if (length != 0) {
+ buffer = new char [length];
+ string.getChars(0, length, buffer, 0);
+ } else {
+ buffer = new char[]{' '};
+ }
+ int nGlyphs = (length * 3 / 2) + 16;
+ GCP_RESULTS result = new GCP_RESULTS();
+ result.lStructSize = GCP_RESULTS.sizeof;
+ result.nGlyphs = nGlyphs;
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ int /*long*/ lpDx = result.lpDx = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, nGlyphs * 4);
+ int /*long*/ lpGlyphs = result.lpGlyphs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, nGlyphs * 2);
+ int dwFlags = OS.GCP_GLYPHSHAPE | OS.GCP_REORDER | OS.GCP_LIGATE;
+ int /*long*/ hdc = Gdip.Graphics_GetHDC(gdipGraphics);
+ int /*long*/ hFont = data.hGDIFont;
+ if (hFont == 0 && data.font != null) hFont = data.font.handle;
+ int /*long*/ oldFont = 0;
+ if (hFont != 0) oldFont = OS.SelectObject(hdc, hFont);
+ if ((data.style & SWT.MIRRORED) != 0) OS.SetLayout(hdc, OS.GetLayout(hdc) | OS.LAYOUT_RTL);
+ OS.GetCharacterPlacementW(hdc, buffer, length, 0, result, dwFlags);
+ if ((data.style & SWT.MIRRORED) != 0) OS.SetLayout(hdc, OS.GetLayout(hdc) & ~OS.LAYOUT_RTL);
+ if (hFont != 0) OS.SelectObject(hdc, oldFont);
+ Gdip.Graphics_ReleaseHDC(gdipGraphics, hdc);
+ int drawX = 0;
+ int[] dx = new int[result.nGlyphs];
+ OS.MoveMemory(dx, lpDx, result.nGlyphs * 4);
+ float[] points = new float[dx.length * 2];
+ for (int i = 0, j = 0; i < dx.length; i++, j += 2) {
+ points[j] = drawX;
+ drawX += dx[i];
+ }
+ Gdip.Graphics_MeasureDriverString(gdipGraphics, lpGlyphs, result.nGlyphs, data.gdipFont, points, 0, 0, bounds);
+ OS.HeapFree(hHeap, 0, lpGlyphs);
+ OS.HeapFree(hHeap, 0, lpDx);
+ return new Point(length == 0 ? 0 : Math.round(bounds.Width), Math.round(bounds.Height));
+ }
+ SIZE size = new SIZE();
+ if (length == 0) {
+// OS.GetTextExtentPoint32(handle, SPACE, SPACE.length(), size);
+ OS.GetTextExtentPoint32W(handle, new char[]{' '}, 1, size);
+ return new Point(0, size.cy);
+ } else {
+// TCHAR buffer = new TCHAR (getCodePage(), string, false);
+ char[] buffer = new char [length];
+ string.getChars(0, length, buffer, 0);
+ OS.GetTextExtentPoint32W(handle, buffer, length, size);
+ return new Point(size.cx, size.cy);
+ }
+}
+
+/**
+ * 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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point textExtent(String string) {
+ return textExtent(string, SWT.DRAW_DELIMITER | SWT.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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Point textExtent(String string, int flags) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ checkGC(FONT);
+ if (data.gdipGraphics != 0) {
+ PointF pt = new PointF();
+ RectF bounds = new RectF();
+ char[] buffer;
+ int length = string.length();
+ if (length != 0) {
+ buffer = new char [length];
+ string.getChars(0, length, buffer, 0);
+ } else {
+ buffer = new char[]{' '};
+ }
+ int /*long*/ format = Gdip.StringFormat_Clone(Gdip.StringFormat_GenericTypographic());
+ int formatFlags = Gdip.StringFormat_GetFormatFlags(format) | Gdip.StringFormatFlagsMeasureTrailingSpaces;
+ if ((data.style & SWT.MIRRORED) != 0) formatFlags |= Gdip.StringFormatFlagsDirectionRightToLeft;
+ Gdip.StringFormat_SetFormatFlags(format, formatFlags);
+ float[] tabs = (flags & SWT.DRAW_TAB) != 0 ? new float[]{measureSpace(data.gdipFont, format) * 8} : new float[1];
+ Gdip.StringFormat_SetTabStops(format, 0, tabs.length, tabs);
+ Gdip.StringFormat_SetHotkeyPrefix(format, (flags & SWT.DRAW_MNEMONIC) != 0 ? Gdip.HotkeyPrefixShow : Gdip.HotkeyPrefixNone);
+ Gdip.Graphics_MeasureString(data.gdipGraphics, buffer, buffer.length, data.gdipFont, pt, format, bounds);
+ Gdip.StringFormat_delete(format);
+ return new Point(length == 0 ? 0 : Math.round(bounds.Width), Math.round(bounds.Height));
+ }
+ if (string.length () == 0) {
+ SIZE size = new SIZE();
+// OS.GetTextExtentPoint32(handle, SPACE, SPACE.length(), size);
+ OS.GetTextExtentPoint32W(handle, new char [] {' '}, 1, size);
+ return new Point(0, size.cy);
+ }
+ RECT rect = new RECT();
+ TCHAR buffer = new TCHAR(getCodePage(), string, false);
+ int uFormat = OS.DT_LEFT | OS.DT_CALCRECT;
+ if ((flags & SWT.DRAW_DELIMITER) == 0) uFormat |= OS.DT_SINGLELINE;
+ if ((flags & SWT.DRAW_TAB) != 0) uFormat |= OS.DT_EXPANDTABS;
+ if ((flags & SWT.DRAW_MNEMONIC) == 0) uFormat |= OS.DT_NOPREFIX;
+ OS.DrawText(handle, buffer, buffer.length(), rect, uFormat);
+ return new Point(rect.right, rect.bottom);
+}
+
+/**
+ * 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 + "}";
+}
+
+/**
+ * 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 SWT. 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>
+ */
+public static GC win32_new(Drawable drawable, GCData data) {
+ GC gc = new GC();
+ int /*long*/ hDC = drawable.internal_new_GC(data);
+ gc.device = data.device;
+ gc.init(drawable, data, hDC);
+ 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 SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param hDC the Windows HDC.
+ * @param data the data for the receiver.
+ *
+ * @return a new <code>GC</code>
+ */
+public static GC win32_new(int /*long*/ hDC, GCData data) {
+ GC gc = new GC();
+ gc.device = data.device;
+ data.style |= SWT.LEFT_TO_RIGHT;
+ if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION (4, 10)) {
+ int flags = OS.GetLayout (hDC);
+ if ((flags & OS.LAYOUT_RTL) != 0) {
+ data.style |= SWT.RIGHT_TO_LEFT | SWT.MIRRORED;
+ }
+ }
+ gc.init(null, data, hDC);
+ return gc;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java
new file mode 100755
index 0000000000..8ccb803401
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/GCData.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class are descriptions of GCs in terms
+ * of unallocated platform-specific data fields.
+ * <p>
+ * <b>IMPORTANT:</b> This class is <em>not</em> part of the public
+ * API for SWT. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms, and should never be called from application code.
+ * </p>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ * @noinstantiate This class is not intended to be instantiated by clients.
+ */
+
+public final class GCData {
+ public Device device;
+ public int style, state = -1;
+ public int foreground = -1;
+ public int background = -1;
+ public Font font;
+ public Pattern foregroundPattern;
+ public Pattern backgroundPattern;
+ public int lineStyle = SWT.LINE_SOLID;
+ public float lineWidth;
+ public int lineCap = SWT.CAP_FLAT;
+ public int lineJoin = SWT.JOIN_MITER;
+ public float lineDashesOffset;
+ public float[] lineDashes;
+ public float lineMiterLimit = 10;
+ public int alpha = 0xFF;
+
+ public Image image;
+ public int /*long*/ hPen, hOldPen;
+ public int /*long*/ hBrush, hOldBrush;
+ public int /*long*/ hNullBitmap;
+ public int /*long*/ hwnd;
+ public PAINTSTRUCT ps;
+ public int layout = -1;
+ public int /*long*/ gdipGraphics;
+ public int /*long*/ gdipPen;
+ public int /*long*/ gdipBrush;
+ public int /*long*/ gdipFgBrush;
+ public int /*long*/ gdipBgBrush;
+ public int /*long*/ gdipFont;
+ public int /*long*/ hGDIFont;
+ public float gdipXOffset, gdipYOffset;
+ public int uiState = 0;
+ public boolean focusDrawn;
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
new file mode 100755
index 0000000000..012f72e537
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Image.java
@@ -0,0 +1,2129 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+
+import java.io.*;
+
+/**
+ * Instances of this class are graphics which have been prepared
+ * for display on a specific device. That is, they are ready
+ * to paint using methods such as <code>GC.drawImage()</code>
+ * and display on widgets with, for example, <code>Button.setImage()</code>.
+ * <p>
+ * If loaded from a file format that supports it, an
+ * <code>Image</code> may have transparency, meaning that certain
+ * pixels are specified as being transparent when drawn. Examples
+ * of file formats that support transparency are GIF and PNG.
+ * </p><p>
+ * There are two primary ways to use <code>Images</code>.
+ * The first is to load a graphic file from disk and create an
+ * <code>Image</code> from it. This is done using an <code>Image</code>
+ * constructor, for example:
+ * <pre>
+ * Image i = new Image(device, "C:\\graphic.bmp");
+ * </pre>
+ * A graphic file may contain a color table specifying which
+ * colors the image was intended to possess. In the above example,
+ * these colors will be mapped to the closest available color in
+ * SWT. It is possible to get more control over the mapping of
+ * colors as the image is being created, using code of the form:
+ * <pre>
+ * ImageData data = new ImageData("C:\\graphic.bmp");
+ * RGB[] rgbs = data.getRGBs();
+ * // At this point, rgbs contains specifications of all
+ * // the colors contained within this image. You may
+ * // allocate as many of these colors as you wish by
+ * // using the Color constructor Color(RGB), then
+ * // create the image:
+ * Image i = new Image(device, data);
+ * </pre>
+ * <p>
+ * Applications which require even greater control over the image
+ * loading process should use the support provided in class
+ * <code>ImageLoader</code>.
+ * </p><p>
+ * Application code must explicitly invoke the <code>Image.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see Color
+ * @see ImageData
+ * @see ImageLoader
+ * @see <a href="http://www.eclipse.org/swt/snippets/#image">Image snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Examples: GraphicsExample, ImageAnalyzer</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+
+public final class Image extends Resource implements Drawable {
+
+ /**
+ * specifies whether the receiver is a bitmap or an icon
+ * (one of <code>SWT.BITMAP</code>, <code>SWT.ICON</code>)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int type;
+
+ /**
+ * the handle to the OS image resource
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int /*long*/ handle;
+
+ /**
+ * specifies the transparent pixel
+ */
+ int transparentPixel = -1, transparentColor = -1;
+
+ /**
+ * the GC which is drawing on the image
+ */
+ GC memGC;
+
+ /**
+ * the alpha data for the image
+ */
+ byte[] alphaData;
+
+ /**
+ * the global alpha value to be used for every pixel
+ */
+ int alpha = -1;
+
+ /**
+ * the image data used to create this image if it is a
+ * icon. Used only in WinCE
+ */
+ ImageData data;
+
+ /**
+ * width of the image
+ */
+ int width = -1;
+
+ /**
+ * height of the image
+ */
+ int height = -1;
+
+ /**
+ * specifies the default scanline padding
+ */
+ static final int DEFAULT_SCANLINE_PAD = 4;
+
+/**
+ * Prevents uninitialized instances from being created outside the package.
+ */
+Image (Device device) {
+ super(device);
+}
+
+/**
+ * Constructs an empty instance of this class with the
+ * specified width and height. The result may be drawn upon
+ * by creating a GC and using any of its drawing operations,
+ * as shown in the following example:
+ * <pre>
+ * Image i = new Image(device, width, height);
+ * GC gc = new GC(i);
+ * gc.drawRectangle(0, 0, 50, 50);
+ * gc.dispose();
+ * </pre>
+ * <p>
+ * Note: Some platforms may have a limitation on the size
+ * of image that can be created (size depends on width, height,
+ * and depth). For example, Windows 95, 98, and ME do not allow
+ * images larger than 16M.
+ * </p>
+ *
+ * @param device the device on which to create the image
+ * @param width the width of the new image
+ * @param height the height of the new image
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_INVALID_ARGUMENT - if either the width or height is negative or zero</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, int width, int height) {
+ super(device);
+ init(width, height);
+ init();
+}
+
+/**
+ * Constructs a new instance of this class based on the
+ * provided image, with an appearance that varies depending
+ * on the value of the flag. The possible flag values are:
+ * <dl>
+ * <dt><b>{@link SWT#IMAGE_COPY}</b></dt>
+ * <dd>the result is an identical copy of srcImage</dd>
+ * <dt><b>{@link SWT#IMAGE_DISABLE}</b></dt>
+ * <dd>the result is a copy of srcImage which has a <em>disabled</em> look</dd>
+ * <dt><b>{@link SWT#IMAGE_GRAY}</b></dt>
+ * <dd>the result is a copy of srcImage which has a <em>gray scale</em> look</dd>
+ * </dl>
+ *
+ * @param device the device on which to create the image
+ * @param srcImage the image to use as the source
+ * @param flag the style, either <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code>
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if srcImage is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the flag is not one of <code>IMAGE_COPY</code>, <code>IMAGE_DISABLE</code> or <code>IMAGE_GRAY</code></li>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon, or is otherwise in an invalid state</li>
+ * <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the image is not supported</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, Image srcImage, int flag) {
+ super(device);
+ device = this.device;
+ if (srcImage == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (srcImage.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ Rectangle rect = srcImage.getBounds();
+ this.type = srcImage.type;
+ switch (flag) {
+ case SWT.IMAGE_COPY: {
+ switch (type) {
+ case SWT.BITMAP:
+ /* Get the HDC for the device */
+ int /*long*/ hDC = device.internal_new_GC(null);
+
+ /* Copy the bitmap */
+ int /*long*/ hdcSource = OS.CreateCompatibleDC(hDC);
+ int /*long*/ hdcDest = OS.CreateCompatibleDC(hDC);
+ int /*long*/ hOldSrc = OS.SelectObject(hdcSource, srcImage.handle);
+ BITMAP bm = new BITMAP();
+ OS.GetObject(srcImage.handle, BITMAP.sizeof, bm);
+ handle = OS.CreateCompatibleBitmap(hdcSource, rect.width, bm.bmBits != 0 ? -rect.height : rect.height);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ hOldDest = OS.SelectObject(hdcDest, handle);
+ OS.BitBlt(hdcDest, 0, 0, rect.width, rect.height, hdcSource, 0, 0, OS.SRCCOPY);
+ OS.SelectObject(hdcSource, hOldSrc);
+ OS.SelectObject(hdcDest, hOldDest);
+ OS.DeleteDC(hdcSource);
+ OS.DeleteDC(hdcDest);
+
+ /* Release the HDC for the device */
+ device.internal_dispose_GC(hDC, null);
+
+ transparentPixel = srcImage.transparentPixel;
+ alpha = srcImage.alpha;
+ if (srcImage.alphaData != null) {
+ alphaData = new byte[srcImage.alphaData.length];
+ System.arraycopy(srcImage.alphaData, 0, alphaData, 0, alphaData.length);
+ }
+ break;
+ case SWT.ICON:
+ if (OS.IsWinCE) {
+ init(srcImage.data);
+ } else {
+ handle = OS.CopyImage(srcImage.handle, OS.IMAGE_ICON, rect.width, rect.height, 0);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ }
+ break;
+ default:
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ }
+ break;
+ }
+ case SWT.IMAGE_DISABLE: {
+ ImageData data = srcImage.getImageData();
+ PaletteData palette = data.palette;
+ RGB[] rgbs = new RGB[3];
+ rgbs[0] = device.getSystemColor(SWT.COLOR_BLACK).getRGB();
+ rgbs[1] = device.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW).getRGB();
+ rgbs[2] = device.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND).getRGB();
+ ImageData newData = new ImageData(rect.width, rect.height, 8, new PaletteData(rgbs));
+ newData.alpha = data.alpha;
+ newData.alphaData = data.alphaData;
+ newData.maskData = data.maskData;
+ newData.maskPad = data.maskPad;
+ if (data.transparentPixel != -1) newData.transparentPixel = 0;
+
+ /* Convert the pixels. */
+ int[] scanline = new int[rect.width];
+ int[] maskScanline = null;
+ ImageData mask = null;
+ if (data.maskData != null) mask = data.getTransparencyMask();
+ if (mask != null) maskScanline = new int[rect.width];
+ int redMask = palette.redMask;
+ int greenMask = palette.greenMask;
+ int blueMask = palette.blueMask;
+ int redShift = palette.redShift;
+ int greenShift = palette.greenShift;
+ int blueShift = palette.blueShift;
+ for (int y=0; y<rect.height; y++) {
+ int offset = y * newData.bytesPerLine;
+ data.getPixels(0, y, rect.width, scanline, 0);
+ if (mask != null) mask.getPixels(0, y, rect.width, maskScanline, 0);
+ for (int x=0; x<rect.width; x++) {
+ int pixel = scanline[x];
+ if (!((data.transparentPixel != -1 && pixel == data.transparentPixel) || (mask != null && maskScanline[x] == 0))) {
+ int red, green, blue;
+ if (palette.isDirect) {
+ red = pixel & redMask;
+ red = (redShift < 0) ? red >>> -redShift : red << redShift;
+ green = pixel & greenMask;
+ green = (greenShift < 0) ? green >>> -greenShift : green << greenShift;
+ blue = pixel & blueMask;
+ blue = (blueShift < 0) ? blue >>> -blueShift : blue << blueShift;
+ } else {
+ red = palette.colors[pixel].red;
+ green = palette.colors[pixel].green;
+ blue = palette.colors[pixel].blue;
+ }
+ int intensity = red * red + green * green + blue * blue;
+ if (intensity < 98304) {
+ newData.data[offset] = (byte)1;
+ } else {
+ newData.data[offset] = (byte)2;
+ }
+ }
+ offset++;
+ }
+ }
+ init (newData);
+ break;
+ }
+ case SWT.IMAGE_GRAY: {
+ ImageData data = srcImage.getImageData();
+ PaletteData palette = data.palette;
+ ImageData newData = data;
+ if (!palette.isDirect) {
+ /* Convert the palette entries to gray. */
+ RGB [] rgbs = palette.getRGBs();
+ for (int i=0; i<rgbs.length; i++) {
+ if (data.transparentPixel != i) {
+ RGB color = rgbs [i];
+ int red = color.red;
+ int green = color.green;
+ int blue = color.blue;
+ int intensity = (red+red+green+green+green+green+green+blue) >> 3;
+ color.red = color.green = color.blue = intensity;
+ }
+ }
+ newData.palette = new PaletteData(rgbs);
+ } else {
+ /* Create a 8 bit depth image data with a gray palette. */
+ RGB[] rgbs = new RGB[256];
+ for (int i=0; i<rgbs.length; i++) {
+ rgbs[i] = new RGB(i, i, i);
+ }
+ newData = new ImageData(rect.width, rect.height, 8, new PaletteData(rgbs));
+ newData.alpha = data.alpha;
+ newData.alphaData = data.alphaData;
+ newData.maskData = data.maskData;
+ newData.maskPad = data.maskPad;
+ if (data.transparentPixel != -1) newData.transparentPixel = 254;
+
+ /* Convert the pixels. */
+ int[] scanline = new int[rect.width];
+ int redMask = palette.redMask;
+ int greenMask = palette.greenMask;
+ int blueMask = palette.blueMask;
+ int redShift = palette.redShift;
+ int greenShift = palette.greenShift;
+ int blueShift = palette.blueShift;
+ for (int y=0; y<rect.height; y++) {
+ int offset = y * newData.bytesPerLine;
+ data.getPixels(0, y, rect.width, scanline, 0);
+ for (int x=0; x<rect.width; x++) {
+ int pixel = scanline[x];
+ if (pixel != data.transparentPixel) {
+ int red = pixel & redMask;
+ red = (redShift < 0) ? red >>> -redShift : red << redShift;
+ int green = pixel & greenMask;
+ green = (greenShift < 0) ? green >>> -greenShift : green << greenShift;
+ int blue = pixel & blueMask;
+ blue = (blueShift < 0) ? blue >>> -blueShift : blue << blueShift;
+ int intensity = (red+red+green+green+green+green+green+blue) >> 3;
+ if (newData.transparentPixel == intensity) intensity = 255;
+ newData.data[offset] = (byte)intensity;
+ } else {
+ newData.data[offset] = (byte)254;
+ }
+ offset++;
+ }
+ }
+ }
+ init (newData);
+ break;
+ }
+ default:
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ init();
+}
+
+/**
+ * Constructs an empty instance of this class with the
+ * width and height of the specified rectangle. The result
+ * may be drawn upon by creating a GC and using any of its
+ * drawing operations, as shown in the following example:
+ * <pre>
+ * Image i = new Image(device, boundsRectangle);
+ * GC gc = new GC(i);
+ * gc.drawRectangle(0, 0, 50, 50);
+ * gc.dispose();
+ * </pre>
+ * <p>
+ * Note: Some platforms may have a limitation on the size
+ * of image that can be created (size depends on width, height,
+ * and depth). For example, Windows 95, 98, and ME do not allow
+ * images larger than 16M.
+ * </p>
+ *
+ * @param device the device on which to create the image
+ * @param bounds a rectangle specifying the image's width and height (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the bounds rectangle is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if either the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, Rectangle bounds) {
+ super(device);
+ if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(bounds.width, bounds.height);
+ init();
+}
+
+/**
+ * Constructs an instance of this class from the given
+ * <code>ImageData</code>.
+ *
+ * @param device the device on which to create the image
+ * @param data the image data to create the image from (must not be null)
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the image data is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_UNSUPPORTED_DEPTH - if the depth of the ImageData is not supported</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, ImageData data) {
+ super(device);
+ init(data);
+ init();
+}
+
+/**
+ * Constructs an instance of this class, whose type is
+ * <code>SWT.ICON</code>, from the two given <code>ImageData</code>
+ * objects. The two images must be the same size. Pixel transparency
+ * in either image will be ignored.
+ * <p>
+ * The mask image should contain white wherever the icon is to be visible,
+ * and black wherever the icon is to be transparent. In addition,
+ * the source image should contain black wherever the icon is to be
+ * transparent.
+ * </p>
+ *
+ * @param device the device on which to create the icon
+ * @param source the color data for the icon
+ * @param mask the mask data for the icon
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if either the source or mask is null </li>
+ * <li>ERROR_INVALID_ARGUMENT - if source and mask are different sizes</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image(Device device, ImageData source, ImageData mask) {
+ super(device);
+ if (source == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (mask == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (source.width != mask.width || source.height != mask.height) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ mask = ImageData.convertMask(mask);
+ init(this.device, this, source, mask);
+ init();
+}
+
+/**
+ * Constructs an instance of this class by loading its representation
+ * from the specified input stream. Throws an error if an error
+ * occurs while loading the image, or if the result is an image
+ * of an unsupported type. Application code is still responsible
+ * for closing the input stream.
+ * <p>
+ * This constructor is provided for convenience when loading a single
+ * image only. If the stream contains multiple images, only the first
+ * one will be loaded. To load multiple images, use
+ * <code>ImageLoader.load()</code>.
+ * </p><p>
+ * This constructor may be used to load a resource as follows:
+ * </p>
+ * <pre>
+ * static Image loadImage (Display display, Class clazz, String string) {
+ * InputStream stream = clazz.getResourceAsStream (string);
+ * if (stream == null) return null;
+ * Image image = null;
+ * try {
+ * image = new Image (display, stream);
+ * } catch (SWTException ex) {
+ * } finally {
+ * try {
+ * stream.close ();
+ * } catch (IOException ex) {}
+ * }
+ * return image;
+ * }
+ * </pre>
+ *
+ * @param device the device on which to create the image
+ * @param stream the input stream to load the image from
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the stream is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_IO - if an IO error occurs while reading from the stream</li>
+ * <li>ERROR_INVALID_IMAGE - if the image stream contains invalid data </li>
+ * <li>ERROR_UNSUPPORTED_DEPTH - if the image stream describes an image with an unsupported depth</li>
+ * <li>ERROR_UNSUPPORTED_FORMAT - if the image stream contains an unrecognized format</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image (Device device, InputStream stream) {
+ super(device);
+ init(new ImageData(stream));
+ init();
+}
+
+/**
+ * Constructs an instance of this class by loading its representation
+ * from the file with the specified name. Throws an error if an error
+ * occurs while loading the image, or if the result is an image
+ * of an unsupported type.
+ * <p>
+ * This constructor is provided for convenience when loading
+ * a single image only. If the specified file contains
+ * multiple images, only the first one will be used.
+ *
+ * @param device the device on which to create the image
+ * @param filename the name of the file to load the image from
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the file name is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_IO - if an IO error occurs while reading from the file</li>
+ * <li>ERROR_INVALID_IMAGE - if the image file contains invalid data </li>
+ * <li>ERROR_UNSUPPORTED_DEPTH - if the image file describes an image with an unsupported depth</li>
+ * <li>ERROR_UNSUPPORTED_FORMAT - if the image file contains an unrecognized format</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for image creation</li>
+ * </ul>
+ */
+public Image (Device device, String filename) {
+ super(device);
+ if (filename == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ initNative(filename);
+ if (this.handle == 0) init(new ImageData(filename));
+ init();
+}
+
+void initNative(String filename) {
+ boolean gdip = true;
+ try {
+ device.checkGDIP();
+ } catch (SWTException e) {
+ gdip = false;
+ }
+ /*
+ * Bug in GDI+. For some reason, Bitmap.LockBits() segment faults
+ * when loading GIF files in 64-bit Windows. The fix is to not use
+ * GDI+ image loading in this case.
+ */
+ if (gdip && OS.PTR_SIZEOF == 8 && filename.toLowerCase().endsWith(".gif")) gdip = false;
+ if (gdip) {
+ int length = filename.length();
+ char[] chars = new char[length+1];
+ filename.getChars(0, length, chars, 0);
+ int /*long*/ bitmap = Gdip.Bitmap_new(chars, false);
+ if (bitmap != 0) {
+ int error = SWT.ERROR_NO_HANDLES;
+ int status = Gdip.Image_GetLastStatus(bitmap);
+ if (status == 0) {
+ if (filename.toLowerCase().endsWith(".ico")) {
+ this.type = SWT.ICON;
+ int /*long*/[] hicon = new int /*long*/[1];
+ status = Gdip.Bitmap_GetHICON(bitmap, hicon);
+ this.handle = hicon[0];
+ } else {
+ this.type = SWT.BITMAP;
+ int width = Gdip.Image_GetWidth(bitmap);
+ int height = Gdip.Image_GetHeight(bitmap);
+ int pixelFormat = Gdip.Image_GetPixelFormat(bitmap);
+ switch (pixelFormat) {
+ case Gdip.PixelFormat16bppRGB555:
+ case Gdip.PixelFormat16bppRGB565:
+ this.handle = createDIB(width, height, 16);
+ break;
+ case Gdip.PixelFormat24bppRGB:
+ this.handle = createDIB(width, height, 24);
+ break;
+ case Gdip.PixelFormat32bppRGB:
+ // These will loose either precision or transparency
+ case Gdip.PixelFormat16bppGrayScale:
+ case Gdip.PixelFormat48bppRGB:
+ case Gdip.PixelFormat32bppPARGB:
+ case Gdip.PixelFormat64bppARGB:
+ case Gdip.PixelFormat64bppPARGB:
+ this.handle = createDIB(width, height, 32);
+ break;
+ }
+ if (this.handle != 0) {
+ /*
+ * This performs better than getting the bits with Bitmap.LockBits(),
+ * but it cannot be used when there is transparency.
+ */
+ int /*long*/ hDC = device.internal_new_GC(null);
+ int /*long*/ srcHDC = OS.CreateCompatibleDC(hDC);
+ int /*long*/ oldSrcBitmap = OS.SelectObject(srcHDC, this.handle);
+ int /*long*/ graphics = Gdip.Graphics_new(srcHDC);
+ if (graphics != 0) {
+ Rect rect = new Rect();
+ rect.Width = width;
+ rect.Height = height;
+ status = Gdip.Graphics_DrawImage(graphics, bitmap, rect, 0, 0, width, height, Gdip.UnitPixel, 0, 0, 0);
+ if (status != 0) {
+ error = SWT.ERROR_INVALID_IMAGE;
+ OS.DeleteObject(handle);
+ this.handle = 0;
+ }
+ Gdip.Graphics_delete(graphics);
+ }
+ OS.SelectObject(srcHDC, oldSrcBitmap);
+ OS.DeleteDC(srcHDC);
+ device.internal_dispose_GC(hDC, null);
+ } else {
+ int /*long*/ lockedBitmapData = Gdip.BitmapData_new();
+ if (lockedBitmapData != 0) {
+ status = Gdip.Bitmap_LockBits(bitmap, 0, 0, pixelFormat, lockedBitmapData);
+ if (status == 0) {
+ BitmapData bitmapData = new BitmapData();
+ Gdip.MoveMemory(bitmapData, lockedBitmapData);
+ int stride = bitmapData.Stride;
+ int /*long*/ pixels = bitmapData.Scan0;
+ int depth = 0, scanlinePad = 4, transparentPixel = -1;
+ switch (bitmapData.PixelFormat) {
+ case Gdip.PixelFormat1bppIndexed: depth = 1; break;
+ case Gdip.PixelFormat4bppIndexed: depth = 4; break;
+ case Gdip.PixelFormat8bppIndexed: depth = 8; break;
+ case Gdip.PixelFormat16bppARGB1555:
+ case Gdip.PixelFormat16bppRGB555:
+ case Gdip.PixelFormat16bppRGB565: depth = 16; break;
+ case Gdip.PixelFormat24bppRGB: depth = 24; break;
+ case Gdip.PixelFormat32bppRGB:
+ case Gdip.PixelFormat32bppARGB: depth = 32; break;
+ }
+ if (depth != 0) {
+ PaletteData paletteData = null;
+ switch (bitmapData.PixelFormat) {
+ case Gdip.PixelFormat1bppIndexed:
+ case Gdip.PixelFormat4bppIndexed:
+ case Gdip.PixelFormat8bppIndexed:
+ int paletteSize = Gdip.Image_GetPaletteSize(bitmap);
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ int /*long*/ palette = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, paletteSize);
+ if (palette == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.Image_GetPalette(bitmap, palette, paletteSize);
+ ColorPalette colorPalette = new ColorPalette();
+ Gdip.MoveMemory(colorPalette, palette, ColorPalette.sizeof);
+ int[] entries = new int[colorPalette.Count];
+ OS.MoveMemory(entries, palette + 8, entries.length * 4);
+ OS.HeapFree(hHeap, 0, palette);
+ RGB[] rgbs = new RGB[colorPalette.Count];
+ paletteData = new PaletteData(rgbs);
+ for (int i = 0; i < entries.length; i++) {
+ if (((entries[i] >> 24) & 0xFF) == 0 && (colorPalette.Flags & Gdip.PaletteFlagsHasAlpha) != 0) {
+ transparentPixel = i;
+ }
+ rgbs[i] = new RGB(((entries[i] & 0xFF0000) >> 16), ((entries[i] & 0xFF00) >> 8), ((entries[i] & 0xFF) >> 0));
+ }
+ break;
+ case Gdip.PixelFormat16bppARGB1555:
+ case Gdip.PixelFormat16bppRGB555: paletteData = new PaletteData(0x7C00, 0x3E0, 0x1F); break;
+ case Gdip.PixelFormat16bppRGB565: paletteData = new PaletteData(0xF800, 0x7E0, 0x1F); break;
+ case Gdip.PixelFormat24bppRGB: paletteData = new PaletteData(0xFF, 0xFF00, 0xFF0000); break;
+ case Gdip.PixelFormat32bppRGB:
+ case Gdip.PixelFormat32bppARGB: paletteData = new PaletteData(0xFF00, 0xFF0000, 0xFF000000); break;
+ }
+ byte[] data = new byte[stride * height], alphaData = null;
+ OS.MoveMemory(data, pixels, data.length);
+ switch (bitmapData.PixelFormat) {
+ case Gdip.PixelFormat16bppARGB1555:
+ alphaData = new byte[width * height];
+ for (int i = 1, j = 0; i < data.length; i += 2, j++) {
+ alphaData[j] = (byte)((data[i] & 0x80) != 0 ? 255 : 0);
+ }
+ break;
+ case Gdip.PixelFormat32bppARGB:
+ alphaData = new byte[width * height];
+ for (int i = 3, j = 0; i < data.length; i += 4, j++) {
+ alphaData[j] = data[i];
+ }
+ break;
+ }
+ ImageData img = new ImageData(width, height, depth, paletteData, scanlinePad, data);
+ img.transparentPixel = transparentPixel;
+ img.alphaData = alphaData;
+ init(img);
+ }
+ Gdip.Bitmap_UnlockBits(bitmap, lockedBitmapData);
+ } else {
+ error = SWT.ERROR_INVALID_IMAGE;
+ }
+ Gdip.BitmapData_delete(lockedBitmapData);
+ }
+ }
+ }
+ }
+ Gdip.Bitmap_delete(bitmap);
+ if (status == 0) {
+ if (this.handle == 0) SWT.error(error);
+ }
+ }
+ }
+}
+
+/**
+ * Create a DIB from a DDB without using GetDIBits. Note that
+ * the DDB should not be selected into a HDC.
+ */
+int /*long*/ createDIBFromDDB(int /*long*/ hDC, int /*long*/ hBitmap, int width, int height) {
+
+ /* Determine the DDB depth */
+ int bits = OS.GetDeviceCaps (hDC, OS.BITSPIXEL);
+ int planes = OS.GetDeviceCaps (hDC, OS.PLANES);
+ int depth = bits * planes;
+
+ /* Determine the DIB palette */
+ boolean isDirect = depth > 8;
+ RGB[] rgbs = null;
+ if (!isDirect) {
+ int numColors = 1 << depth;
+ byte[] logPalette = new byte[4 * numColors];
+ OS.GetPaletteEntries(device.hPalette, 0, numColors, logPalette);
+ rgbs = new RGB[numColors];
+ for (int i = 0; i < numColors; i++) {
+ rgbs[i] = new RGB(logPalette[i] & 0xFF, logPalette[i + 1] & 0xFF, logPalette[i + 2] & 0xFF);
+ }
+ }
+
+ boolean useBitfields = OS.IsWinCE && (depth == 16 || depth == 32);
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = width;
+ bmiHeader.biHeight = -height;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = (short)depth;
+ if (useBitfields) bmiHeader.biCompression = OS.BI_BITFIELDS;
+ else bmiHeader.biCompression = OS.BI_RGB;
+ byte[] bmi;
+ if (isDirect) bmi = new byte[BITMAPINFOHEADER.sizeof + (useBitfields ? 12 : 0)];
+ else bmi = new byte[BITMAPINFOHEADER.sizeof + rgbs.length * 4];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+
+ /* Set the rgb colors into the bitmap info */
+ int offset = BITMAPINFOHEADER.sizeof;
+ if (isDirect) {
+ if (useBitfields) {
+ int redMask = 0;
+ int greenMask = 0;
+ int blueMask = 0;
+ switch (depth) {
+ case 16:
+ redMask = 0x7C00;
+ greenMask = 0x3E0;
+ blueMask = 0x1F;
+ /* little endian */
+ bmi[offset] = (byte)((redMask & 0xFF) >> 0);
+ bmi[offset + 1] = (byte)((redMask & 0xFF00) >> 8);
+ bmi[offset + 2] = (byte)((redMask & 0xFF0000) >> 16);
+ bmi[offset + 3] = (byte)((redMask & 0xFF000000) >> 24);
+ bmi[offset + 4] = (byte)((greenMask & 0xFF) >> 0);
+ bmi[offset + 5] = (byte)((greenMask & 0xFF00) >> 8);
+ bmi[offset + 6] = (byte)((greenMask & 0xFF0000) >> 16);
+ bmi[offset + 7] = (byte)((greenMask & 0xFF000000) >> 24);
+ bmi[offset + 8] = (byte)((blueMask & 0xFF) >> 0);
+ bmi[offset + 9] = (byte)((blueMask & 0xFF00) >> 8);
+ bmi[offset + 10] = (byte)((blueMask & 0xFF0000) >> 16);
+ bmi[offset + 11] = (byte)((blueMask & 0xFF000000) >> 24);
+ break;
+ case 32:
+ redMask = 0xFF00;
+ greenMask = 0xFF0000;
+ blueMask = 0xFF000000;
+ /* big endian */
+ bmi[offset] = (byte)((redMask & 0xFF000000) >> 24);
+ bmi[offset + 1] = (byte)((redMask & 0xFF0000) >> 16);
+ bmi[offset + 2] = (byte)((redMask & 0xFF00) >> 8);
+ bmi[offset + 3] = (byte)((redMask & 0xFF) >> 0);
+ bmi[offset + 4] = (byte)((greenMask & 0xFF000000) >> 24);
+ bmi[offset + 5] = (byte)((greenMask & 0xFF0000) >> 16);
+ bmi[offset + 6] = (byte)((greenMask & 0xFF00) >> 8);
+ bmi[offset + 7] = (byte)((greenMask & 0xFF) >> 0);
+ bmi[offset + 8] = (byte)((blueMask & 0xFF000000) >> 24);
+ bmi[offset + 9] = (byte)((blueMask & 0xFF0000) >> 16);
+ bmi[offset + 10] = (byte)((blueMask & 0xFF00) >> 8);
+ bmi[offset + 11] = (byte)((blueMask & 0xFF) >> 0);
+ break;
+ default:
+ SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+ }
+ }
+ } else {
+ for (int j = 0; j < rgbs.length; j++) {
+ bmi[offset] = (byte)rgbs[j].blue;
+ bmi[offset + 1] = (byte)rgbs[j].green;
+ bmi[offset + 2] = (byte)rgbs[j].red;
+ bmi[offset + 3] = 0;
+ offset += 4;
+ }
+ }
+ int /*long*/[] pBits = new int /*long*/[1];
+ int /*long*/ hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
+ if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+
+ /* Bitblt DDB into DIB */
+ int /*long*/ hdcSource = OS.CreateCompatibleDC(hDC);
+ int /*long*/ hdcDest = OS.CreateCompatibleDC(hDC);
+ int /*long*/ hOldSrc = OS.SelectObject(hdcSource, hBitmap);
+ int /*long*/ hOldDest = OS.SelectObject(hdcDest, hDib);
+ OS.BitBlt(hdcDest, 0, 0, width, height, hdcSource, 0, 0, OS.SRCCOPY);
+ OS.SelectObject(hdcSource, hOldSrc);
+ OS.SelectObject(hdcDest, hOldDest);
+ OS.DeleteDC(hdcSource);
+ OS.DeleteDC(hdcDest);
+
+ return hDib;
+}
+
+int /*long*/ [] createGdipImage() {
+ switch (type) {
+ case SWT.BITMAP: {
+ if (alpha != -1 || alphaData != null || transparentPixel != -1) {
+ BITMAP bm = new BITMAP();
+ OS.GetObject(handle, BITMAP.sizeof, bm);
+ int imgWidth = bm.bmWidth;
+ int imgHeight = bm.bmHeight;
+ int /*long*/ hDC = device.internal_new_GC(null);
+ int /*long*/ srcHdc = OS.CreateCompatibleDC(hDC);
+ int /*long*/ oldSrcBitmap = OS.SelectObject(srcHdc, handle);
+ int /*long*/ memHdc = OS.CreateCompatibleDC(hDC);
+ int /*long*/ memDib = createDIB(imgWidth, imgHeight, 32);
+ if (memDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ oldMemBitmap = OS.SelectObject(memHdc, memDib);
+ BITMAP dibBM = new BITMAP();
+ OS.GetObject(memDib, BITMAP.sizeof, dibBM);
+ int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
+ OS.BitBlt(memHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, 0, OS.SRCCOPY);
+ byte red = 0, green = 0, blue = 0;
+ if (transparentPixel != -1) {
+ if (bm.bmBitsPixel <= 8) {
+ byte[] color = new byte[4];
+ OS.GetDIBColorTable(srcHdc, transparentPixel, 1, color);
+ blue = color[0];
+ green = color[1];
+ red = color[2];
+ } else {
+ switch (bm.bmBitsPixel) {
+ case 16:
+ int blueMask = 0x1F;
+ int blueShift = ImageData.getChannelShift(blueMask);
+ byte[] blues = ImageData.ANY_TO_EIGHT[ImageData.getChannelWidth(blueMask, blueShift)];
+ blue = blues[(transparentPixel & blueMask) >> blueShift];
+ int greenMask = 0x3E0;
+ int greenShift = ImageData.getChannelShift(greenMask);
+ byte[] greens = ImageData.ANY_TO_EIGHT[ImageData.getChannelWidth(greenMask, greenShift)];
+ green = greens[(transparentPixel & greenMask) >> greenShift];
+ int redMask = 0x7C00;
+ int redShift = ImageData.getChannelShift(redMask);
+ byte[] reds = ImageData.ANY_TO_EIGHT[ImageData.getChannelWidth(redMask, redShift)];
+ red = reds[(transparentPixel & redMask) >> redShift];
+ break;
+ case 24:
+ blue = (byte)((transparentPixel & 0xFF0000) >> 16);
+ green = (byte)((transparentPixel & 0xFF00) >> 8);
+ red = (byte)(transparentPixel & 0xFF);
+ break;
+ case 32:
+ blue = (byte)((transparentPixel & 0xFF000000) >>> 24);
+ green = (byte)((transparentPixel & 0xFF0000) >> 16);
+ red = (byte)((transparentPixel & 0xFF00) >> 8);
+ break;
+ }
+ }
+ }
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ OS.SelectObject(memHdc, oldMemBitmap);
+ OS.DeleteObject(srcHdc);
+ OS.DeleteObject(memHdc);
+ byte[] srcData = new byte[sizeInBytes];
+ OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
+ OS.DeleteObject(memDib);
+ device.internal_dispose_GC(hDC, null);
+ if (alpha != -1) {
+ for (int y = 0, dp = 0; y < imgHeight; ++y) {
+ for (int x = 0; x < imgWidth; ++x) {
+ srcData[dp + 3] = (byte)alpha;
+ dp += 4;
+ }
+ }
+ } else if (alphaData != null) {
+ for (int y = 0, dp = 0, ap = 0; y < imgHeight; ++y) {
+ for (int x = 0; x < imgWidth; ++x) {
+ srcData[dp + 3] = alphaData[ap++];
+ dp += 4;
+ }
+ }
+ } else if (transparentPixel != -1) {
+ for (int y = 0, dp = 0; y < imgHeight; ++y) {
+ for (int x = 0; x < imgWidth; ++x) {
+ if (srcData[dp] == blue && srcData[dp + 1] == green && srcData[dp + 2] == red) {
+ srcData[dp + 3] = (byte)0;
+ } else {
+ srcData[dp + 3] = (byte)0xFF;
+ }
+ dp += 4;
+ }
+ }
+ }
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ int /*long*/ pixels = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, srcData.length);
+ if (pixels == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.MoveMemory(pixels, srcData, sizeInBytes);
+ return new int /*long*/ []{Gdip.Bitmap_new(imgWidth, imgHeight, dibBM.bmWidthBytes, Gdip.PixelFormat32bppARGB, pixels), pixels};
+ }
+ return new int /*long*/ []{Gdip.Bitmap_new(handle, 0), 0};
+ }
+ case SWT.ICON: {
+ /*
+ * Bug in GDI+. Creating a new GDI+ Bitmap from a HICON segment faults
+ * when the icon width is bigger than the icon height. The fix is to
+ * detect this and create a PixelFormat32bppARGB image instead.
+ */
+ ICONINFO iconInfo = new ICONINFO();
+ if (OS.IsWinCE) {
+ GetIconInfo(this, iconInfo);
+ } else {
+ OS.GetIconInfo(handle, iconInfo);
+ }
+ int /*long*/ hBitmap = iconInfo.hbmColor;
+ if (hBitmap == 0) hBitmap = iconInfo.hbmMask;
+ BITMAP bm = new BITMAP();
+ OS.GetObject(hBitmap, BITMAP.sizeof, bm);
+ int imgWidth = bm.bmWidth;
+ int imgHeight = hBitmap == iconInfo.hbmMask ? bm.bmHeight / 2 : bm.bmHeight;
+ int /*long*/ img = 0, pixels = 0;
+ /*
+ * Bug in GDI+. Bitmap_new() segments fault if the image width
+ * is greater than the image height.
+ *
+ * Note that it also fails to generated an appropriate alpha
+ * channel when the icon depth is 32.
+ */
+ if (imgWidth > imgHeight || bm.bmBitsPixel == 32) {
+ int /*long*/ hDC = device.internal_new_GC(null);
+ int /*long*/ srcHdc = OS.CreateCompatibleDC(hDC);
+ int /*long*/ oldSrcBitmap = OS.SelectObject(srcHdc, hBitmap);
+ int /*long*/ memHdc = OS.CreateCompatibleDC(hDC);
+ int /*long*/ memDib = createDIB(imgWidth, imgHeight, 32);
+ if (memDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ oldMemBitmap = OS.SelectObject(memHdc, memDib);
+ BITMAP dibBM = new BITMAP();
+ OS.GetObject(memDib, BITMAP.sizeof, dibBM);
+ OS.BitBlt(memHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, hBitmap == iconInfo.hbmMask ? imgHeight : 0, OS.SRCCOPY);
+ OS.SelectObject(memHdc, oldMemBitmap);
+ OS.DeleteObject(memHdc);
+ byte[] srcData = new byte[dibBM.bmWidthBytes * dibBM.bmHeight];
+ OS.MoveMemory(srcData, dibBM.bmBits, srcData.length);
+ OS.DeleteObject(memDib);
+ OS.SelectObject(srcHdc, iconInfo.hbmMask);
+ for (int y = 0, dp = 3; y < imgHeight; ++y) {
+ for (int x = 0; x < imgWidth; ++x) {
+ if (srcData[dp] == 0) {
+ if (OS.GetPixel(srcHdc, x, y) != 0) {
+ srcData[dp] = (byte)0;
+ } else {
+ srcData[dp] = (byte)0xFF;
+ }
+ }
+ dp += 4;
+ }
+ }
+ OS.SelectObject(srcHdc, oldSrcBitmap);
+ OS.DeleteObject(srcHdc);
+ device.internal_dispose_GC(hDC, null);
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ pixels = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, srcData.length);
+ if (pixels == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.MoveMemory(pixels, srcData, srcData.length);
+ img = Gdip.Bitmap_new(imgWidth, imgHeight, dibBM.bmWidthBytes, Gdip.PixelFormat32bppARGB, pixels);
+ } else {
+ img = Gdip.Bitmap_new(handle);
+ }
+ if (iconInfo.hbmColor != 0) OS.DeleteObject(iconInfo.hbmColor);
+ if (iconInfo.hbmMask != 0) OS.DeleteObject(iconInfo.hbmMask);
+ return new int /*long*/ []{img, pixels};
+ }
+ default: SWT.error(SWT.ERROR_INVALID_IMAGE);
+ }
+ return null;
+}
+
+void destroy () {
+ if (memGC != null) memGC.dispose();
+ if (type == SWT.ICON) {
+ if (OS.IsWinCE) data = null;
+ OS.DestroyIcon (handle);
+ } else {
+ OS.DeleteObject (handle);
+ }
+ handle = 0;
+ memGC = null;
+}
+
+/**
+ * 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 boolean equals (Object object) {
+ if (object == this) return true;
+ if (!(object instanceof Image)) return false;
+ Image image = (Image) object;
+ return device == image.device && handle == image.handle;
+}
+
+/**
+ * Returns the color to which to map the transparent pixel, or null if
+ * the receiver has no transparent pixel.
+ * <p>
+ * There are certain uses of Images that do not support transparency
+ * (for example, setting an image into a button or label). In these cases,
+ * it may be desired to simulate transparency by using the background
+ * color of the widget to paint the transparent pixels of the image.
+ * Use this method to check which color will be used in these cases
+ * in place of transparency. This value may be set with setBackground().
+ * <p>
+ *
+ * @return the background color of the image, or null if there is no transparency in the image
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Color getBackground() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (transparentPixel == -1) return null;
+
+ /* Get the HDC for the device */
+ int /*long*/ hDC = device.internal_new_GC(null);
+
+ /* Compute the background color */
+ BITMAP bm = new BITMAP();
+ OS.GetObject(handle, BITMAP.sizeof, bm);
+ int /*long*/ hdcMem = OS.CreateCompatibleDC(hDC);
+ int /*long*/ hOldObject = OS.SelectObject(hdcMem, handle);
+ int red = 0, green = 0, blue = 0;
+ if (bm.bmBitsPixel <= 8) {
+ if (OS.IsWinCE) {
+ byte[] pBits = new byte[1];
+ OS.MoveMemory(pBits, bm.bmBits, 1);
+ byte oldValue = pBits[0];
+ int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF;
+ pBits[0] = (byte)((transparentPixel << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask));
+ OS.MoveMemory(bm.bmBits, pBits, 1);
+ int color = OS.GetPixel(hdcMem, 0, 0);
+ pBits[0] = oldValue;
+ OS.MoveMemory(bm.bmBits, pBits, 1);
+ blue = (color & 0xFF0000) >> 16;
+ green = (color & 0xFF00) >> 8;
+ red = color & 0xFF;
+ } else {
+ byte[] color = new byte[4];
+ OS.GetDIBColorTable(hdcMem, transparentPixel, 1, color);
+ blue = color[0] & 0xFF;
+ green = color[1] & 0xFF;
+ red = color[2] & 0xFF;
+ }
+ } else {
+ switch (bm.bmBitsPixel) {
+ case 16:
+ blue = (transparentPixel & 0x1F) << 3;
+ green = (transparentPixel & 0x3E0) >> 2;
+ red = (transparentPixel & 0x7C00) >> 7;
+ break;
+ case 24:
+ blue = (transparentPixel & 0xFF0000) >> 16;
+ green = (transparentPixel & 0xFF00) >> 8;
+ red = transparentPixel & 0xFF;
+ break;
+ case 32:
+ blue = (transparentPixel & 0xFF000000) >>> 24;
+ green = (transparentPixel & 0xFF0000) >> 16;
+ red = (transparentPixel & 0xFF00) >> 8;
+ break;
+ default:
+ return null;
+ }
+ }
+ OS.SelectObject(hdcMem, hOldObject);
+ OS.DeleteDC(hdcMem);
+
+ /* Release the HDC for the device */
+ device.internal_dispose_GC(hDC, null);
+ return Color.win32_new(device, (blue << 16) | (green << 8) | red);
+}
+
+/**
+ * Returns the bounds of the receiver. The rectangle will always
+ * have x and y values of 0, and the width and height of the
+ * image.
+ *
+ * @return a rectangle specifying the image's bounds
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
+ * </ul>
+ */
+public Rectangle getBounds() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width != -1 && height != -1) {
+ return new Rectangle(0, 0, width, height);
+ }
+ switch (type) {
+ case SWT.BITMAP:
+ BITMAP bm = new BITMAP();
+ OS.GetObject(handle, BITMAP.sizeof, bm);
+ return new Rectangle(0, 0, width = bm.bmWidth, height = bm.bmHeight);
+ case SWT.ICON:
+ if (OS.IsWinCE) {
+ return new Rectangle(0, 0, width = data.width, height = data.height);
+ } else {
+ ICONINFO info = new ICONINFO();
+ OS.GetIconInfo(handle, info);
+ int /*long*/ hBitmap = info.hbmColor;
+ if (hBitmap == 0) hBitmap = info.hbmMask;
+ bm = new BITMAP();
+ OS.GetObject(hBitmap, BITMAP.sizeof, bm);
+ if (hBitmap == info.hbmMask) bm.bmHeight /= 2;
+ if (info.hbmColor != 0) OS.DeleteObject(info.hbmColor);
+ if (info.hbmMask != 0) OS.DeleteObject(info.hbmMask);
+ return new Rectangle(0, 0, width = bm.bmWidth, height = bm.bmHeight);
+ }
+ default:
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ return null;
+ }
+}
+
+/**
+ * Returns an <code>ImageData</code> based on the receiver
+ * Modifications made to this <code>ImageData</code> will not
+ * affect the Image.
+ *
+ * @return an <code>ImageData</code> containing the image's data and attributes
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_INVALID_IMAGE - if the image is not a bitmap or an icon</li>
+ * </ul>
+ *
+ * @see ImageData
+ */
+public ImageData getImageData() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ BITMAP bm;
+ int depth, width, height;
+ switch (type) {
+ case SWT.ICON: {
+ if (OS.IsWinCE) return data;
+ ICONINFO info = new ICONINFO();
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ OS.GetIconInfo(handle, info);
+ /* Get the basic BITMAP information */
+ int /*long*/ hBitmap = info.hbmColor;
+ if (hBitmap == 0) hBitmap = info.hbmMask;
+ bm = new BITMAP();
+ OS.GetObject(hBitmap, BITMAP.sizeof, bm);
+ depth = bm.bmPlanes * bm.bmBitsPixel;
+ width = bm.bmWidth;
+ if (hBitmap == info.hbmMask) bm.bmHeight /= 2;
+ height = bm.bmHeight;
+ int numColors = 0;
+ if (depth <= 8) numColors = 1 << depth;
+ /* Create the BITMAPINFO */
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = width;
+ bmiHeader.biHeight = -height;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = (short)depth;
+ bmiHeader.biCompression = OS.BI_RGB;
+ byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+
+ /* Get the HDC for the device */
+ int /*long*/ hDC = device.internal_new_GC(null);
+
+ /* Create the DC and select the bitmap */
+ int /*long*/ hBitmapDC = OS.CreateCompatibleDC(hDC);
+ int /*long*/ hOldBitmap = OS.SelectObject(hBitmapDC, hBitmap);
+ /* Select the palette if necessary */
+ int /*long*/ oldPalette = 0;
+ if (depth <= 8) {
+ int /*long*/ hPalette = device.hPalette;
+ if (hPalette != 0) {
+ oldPalette = OS.SelectPalette(hBitmapDC, hPalette, false);
+ OS.RealizePalette(hBitmapDC);
+ }
+ }
+ /* Find the size of the image and allocate data */
+ int imageSize;
+ /* Call with null lpBits to get the image size */
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ OS.GetDIBits(hBitmapDC, hBitmap, 0, height, 0, bmi, OS.DIB_RGB_COLORS);
+ OS.MoveMemory(bmiHeader, bmi, BITMAPINFOHEADER.sizeof);
+ imageSize = bmiHeader.biSizeImage;
+ byte[] data = new byte[imageSize];
+ /* Get the bitmap data */
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ int /*long*/ lpvBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize);
+ if (lpvBits == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ OS.GetDIBits(hBitmapDC, hBitmap, 0, height, lpvBits, bmi, OS.DIB_RGB_COLORS);
+ OS.MoveMemory(data, lpvBits, imageSize);
+ /* Calculate the palette */
+ PaletteData palette = null;
+ if (depth <= 8) {
+ RGB[] rgbs = new RGB[numColors];
+ int srcIndex = 40;
+ for (int i = 0; i < numColors; i++) {
+ rgbs[i] = new RGB(bmi[srcIndex + 2] & 0xFF, bmi[srcIndex + 1] & 0xFF, bmi[srcIndex] & 0xFF);
+ srcIndex += 4;
+ }
+ palette = new PaletteData(rgbs);
+ } else if (depth == 16) {
+ palette = new PaletteData(0x7C00, 0x3E0, 0x1F);
+ } else if (depth == 24) {
+ palette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
+ } else if (depth == 32) {
+ palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ } else {
+ SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+ }
+
+ /* Do the mask */
+ byte [] maskData = null;
+ if (info.hbmColor == 0) {
+ /* Do the bottom half of the mask */
+ maskData = new byte[imageSize];
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ OS.GetDIBits(hBitmapDC, hBitmap, height, height, lpvBits, bmi, OS.DIB_RGB_COLORS);
+ OS.MoveMemory(maskData, lpvBits, imageSize);
+ } else {
+ /* Do the entire mask */
+ /* Create the BITMAPINFO */
+ bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = width;
+ bmiHeader.biHeight = -height;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = 1;
+ bmiHeader.biCompression = OS.BI_RGB;
+ bmi = new byte[BITMAPINFOHEADER.sizeof + 8];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+
+ /* First color black, second color white */
+ int offset = BITMAPINFOHEADER.sizeof;
+ bmi[offset + 4] = bmi[offset + 5] = bmi[offset + 6] = (byte)0xFF;
+ bmi[offset + 7] = 0;
+ OS.SelectObject(hBitmapDC, info.hbmMask);
+ /* Call with null lpBits to get the image size */
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ OS.GetDIBits(hBitmapDC, info.hbmMask, 0, height, 0, bmi, OS.DIB_RGB_COLORS);
+ OS.MoveMemory(bmiHeader, bmi, BITMAPINFOHEADER.sizeof);
+ imageSize = bmiHeader.biSizeImage;
+ maskData = new byte[imageSize];
+ int /*long*/ lpvMaskBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize);
+ if (lpvMaskBits == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ OS.GetDIBits(hBitmapDC, info.hbmMask, 0, height, lpvMaskBits, bmi, OS.DIB_RGB_COLORS);
+ OS.MoveMemory(maskData, lpvMaskBits, imageSize);
+ OS.HeapFree(hHeap, 0, lpvMaskBits);
+ /* Loop to invert the mask */
+ for (int i = 0; i < maskData.length; i++) {
+ maskData[i] ^= -1;
+ }
+ /* Make sure mask scanlinePad is 2 */
+ int maskPad;
+ int bpl = imageSize / height;
+ for (maskPad = 1; maskPad < 128; maskPad++) {
+ int calcBpl = (((width + 7) / 8) + (maskPad - 1)) / maskPad * maskPad;
+ if (calcBpl == bpl) break;
+ }
+ maskData = ImageData.convertPad(maskData, width, height, 1, maskPad, 2);
+ }
+ /* Clean up */
+ OS.HeapFree(hHeap, 0, lpvBits);
+ OS.SelectObject(hBitmapDC, hOldBitmap);
+ if (oldPalette != 0) {
+ OS.SelectPalette(hBitmapDC, oldPalette, false);
+ OS.RealizePalette(hBitmapDC);
+ }
+ OS.DeleteDC(hBitmapDC);
+
+ /* Release the HDC for the device */
+ device.internal_dispose_GC(hDC, null);
+
+ if (info.hbmColor != 0) OS.DeleteObject(info.hbmColor);
+ if (info.hbmMask != 0) OS.DeleteObject(info.hbmMask);
+ /* Construct and return the ImageData */
+ ImageData imageData = new ImageData(width, height, depth, palette, 4, data);
+ imageData.maskData = maskData;
+ imageData.maskPad = 2;
+ return imageData;
+ }
+ case SWT.BITMAP: {
+ /* Get the basic BITMAP information */
+ bm = new BITMAP();
+ OS.GetObject(handle, BITMAP.sizeof, bm);
+ depth = bm.bmPlanes * bm.bmBitsPixel;
+ width = bm.bmWidth;
+ height = bm.bmHeight;
+ /* Find out whether this is a DIB or a DDB. */
+ boolean isDib = (bm.bmBits != 0);
+ /* Get the HDC for the device */
+ int /*long*/ hDC = device.internal_new_GC(null);
+
+ /*
+ * Feature in WinCE. GetDIBits is not available in WinCE. The
+ * workaround is to create a temporary DIB from the DDB and use
+ * the bmBits field of DIBSECTION to retrieve the image data.
+ */
+ int /*long*/ handle = this.handle;
+ if (OS.IsWinCE) {
+ if (!isDib) {
+ boolean mustRestore = false;
+ if (memGC != null && !memGC.isDisposed()) {
+ memGC.flush ();
+ mustRestore = true;
+ GCData data = memGC.data;
+ if (data.hNullBitmap != 0) {
+ OS.SelectObject(memGC.handle, data.hNullBitmap);
+ data.hNullBitmap = 0;
+ }
+ }
+ handle = createDIBFromDDB(hDC, this.handle, width, height);
+ if (mustRestore) {
+ int /*long*/ hOldBitmap = OS.SelectObject(memGC.handle, this.handle);
+ memGC.data.hNullBitmap = hOldBitmap;
+ }
+ isDib = true;
+ }
+ }
+ DIBSECTION dib = null;
+ if (isDib) {
+ dib = new DIBSECTION();
+ OS.GetObject(handle, DIBSECTION.sizeof, dib);
+ }
+ /* Calculate number of colors */
+ int numColors = 0;
+ if (depth <= 8) {
+ if (isDib) {
+ numColors = dib.biClrUsed;
+ } else {
+ numColors = 1 << depth;
+ }
+ }
+ /* Create the BITMAPINFO */
+ byte[] bmi = null;
+ BITMAPINFOHEADER bmiHeader = null;
+ if (!isDib) {
+ bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = width;
+ bmiHeader.biHeight = -height;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = (short)depth;
+ bmiHeader.biCompression = OS.BI_RGB;
+ bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+ }
+
+ /* Create the DC and select the bitmap */
+ int /*long*/ hBitmapDC = OS.CreateCompatibleDC(hDC);
+ int /*long*/ hOldBitmap = OS.SelectObject(hBitmapDC, handle);
+ /* Select the palette if necessary */
+ int /*long*/ oldPalette = 0;
+ if (!isDib && depth <= 8) {
+ int /*long*/ hPalette = device.hPalette;
+ if (hPalette != 0) {
+ oldPalette = OS.SelectPalette(hBitmapDC, hPalette, false);
+ OS.RealizePalette(hBitmapDC);
+ }
+ }
+ /* Find the size of the image and allocate data */
+ int imageSize;
+ if (isDib) {
+ imageSize = dib.biSizeImage;
+ } else {
+ /* Call with null lpBits to get the image size */
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ OS.GetDIBits(hBitmapDC, handle, 0, height, 0, bmi, OS.DIB_RGB_COLORS);
+ OS.MoveMemory(bmiHeader, bmi, BITMAPINFOHEADER.sizeof);
+ imageSize = bmiHeader.biSizeImage;
+ }
+ byte[] data = new byte[imageSize];
+ /* Get the bitmap data */
+ if (isDib) {
+ if (OS.IsWinCE && this.handle != handle) {
+ /* get image data from the temporary DIB */
+ OS.MoveMemory(data, dib.bmBits, imageSize);
+ } else {
+ OS.MoveMemory(data, bm.bmBits, imageSize);
+ }
+ } else {
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ int /*long*/ lpvBits = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, imageSize);
+ if (lpvBits == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ OS.GetDIBits(hBitmapDC, handle, 0, height, lpvBits, bmi, OS.DIB_RGB_COLORS);
+ OS.MoveMemory(data, lpvBits, imageSize);
+ OS.HeapFree(hHeap, 0, lpvBits);
+ }
+ /* Calculate the palette */
+ PaletteData palette = null;
+ if (depth <= 8) {
+ RGB[] rgbs = new RGB[numColors];
+ if (isDib) {
+ if (OS.IsWinCE) {
+ /*
+ * Feature on WinCE. GetDIBColorTable is not supported.
+ * The workaround is to set a pixel to the desired
+ * palette index and use getPixel to get the corresponding
+ * RGB value.
+ */
+ int red = 0, green = 0, blue = 0;
+ byte[] pBits = new byte[1];
+ OS.MoveMemory(pBits, bm.bmBits, 1);
+ byte oldValue = pBits[0];
+ int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF;
+ for (int i = 0; i < numColors; i++) {
+ pBits[0] = (byte)((i << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask));
+ OS.MoveMemory(bm.bmBits, pBits, 1);
+ int color = OS.GetPixel(hBitmapDC, 0, 0);
+ blue = (color & 0xFF0000) >> 16;
+ green = (color & 0xFF00) >> 8;
+ red = color & 0xFF;
+ rgbs[i] = new RGB(red, green, blue);
+ }
+ pBits[0] = oldValue;
+ OS.MoveMemory(bm.bmBits, pBits, 1);
+ } else {
+ byte[] colors = new byte[numColors * 4];
+ OS.GetDIBColorTable(hBitmapDC, 0, numColors, colors);
+ int colorIndex = 0;
+ for (int i = 0; i < rgbs.length; i++) {
+ rgbs[i] = new RGB(colors[colorIndex + 2] & 0xFF, colors[colorIndex + 1] & 0xFF, colors[colorIndex] & 0xFF);
+ colorIndex += 4;
+ }
+ }
+ } else {
+ int srcIndex = BITMAPINFOHEADER.sizeof;
+ for (int i = 0; i < numColors; i++) {
+ rgbs[i] = new RGB(bmi[srcIndex + 2] & 0xFF, bmi[srcIndex + 1] & 0xFF, bmi[srcIndex] & 0xFF);
+ srcIndex += 4;
+ }
+ }
+ palette = new PaletteData(rgbs);
+ } else if (depth == 16) {
+ palette = new PaletteData(0x7C00, 0x3E0, 0x1F);
+ } else if (depth == 24) {
+ palette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
+ } else if (depth == 32) {
+ palette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ } else {
+ SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+ }
+ /* Clean up */
+ OS.SelectObject(hBitmapDC, hOldBitmap);
+ if (oldPalette != 0) {
+ OS.SelectPalette(hBitmapDC, oldPalette, false);
+ OS.RealizePalette(hBitmapDC);
+ }
+ if (OS.IsWinCE) {
+ if (handle != this.handle) {
+ /* free temporary DIB */
+ OS.DeleteObject (handle);
+ }
+ }
+ OS.DeleteDC(hBitmapDC);
+
+ /* Release the HDC for the device */
+ device.internal_dispose_GC(hDC, null);
+
+ /* Construct and return the ImageData */
+ ImageData imageData = new ImageData(width, height, depth, palette, 4, data);
+ imageData.transparentPixel = this.transparentPixel;
+ imageData.alpha = alpha;
+ if (alpha == -1 && alphaData != null) {
+ imageData.alphaData = new byte[alphaData.length];
+ System.arraycopy(alphaData, 0, imageData.alphaData, 0, alphaData.length);
+ }
+ return imageData;
+ }
+ default:
+ SWT.error(SWT.ERROR_INVALID_IMAGE);
+ return null;
+ }
+}
+
+/**
+ * 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
+ *
+ * @see #equals
+ */
+public int hashCode () {
+ return (int)/*64*/handle;
+}
+
+void init(int width, int height) {
+ if (width <= 0 || height <= 0) {
+ SWT.error (SWT.ERROR_INVALID_ARGUMENT);
+ }
+ type = SWT.BITMAP;
+ int /*long*/ hDC = device.internal_new_GC(null);
+ handle = OS.CreateCompatibleBitmap(hDC, width, height);
+ /*
+ * Feature in Windows. CreateCompatibleBitmap() may fail
+ * for large images. The fix is to create a DIB section
+ * in that case.
+ */
+ if (handle == 0) {
+ int bits = OS.GetDeviceCaps(hDC, OS.BITSPIXEL);
+ int planes = OS.GetDeviceCaps(hDC, OS.PLANES);
+ int depth = bits * planes;
+ if (depth < 16) depth = 16;
+ handle = createDIB(width, height, depth);
+ }
+ if (handle != 0) {
+ int /*long*/ memDC = OS.CreateCompatibleDC(hDC);
+ int /*long*/ hOldBitmap = OS.SelectObject(memDC, handle);
+ OS.PatBlt(memDC, 0, 0, width, height, OS.PATCOPY);
+ OS.SelectObject(memDC, hOldBitmap);
+ OS.DeleteDC(memDC);
+ }
+ device.internal_dispose_GC(hDC, null);
+ if (handle == 0) {
+ SWT.error(SWT.ERROR_NO_HANDLES, null, device.getLastError());
+ }
+}
+
+static int /*long*/ createDIB(int width, int height, int depth) {
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = width;
+ bmiHeader.biHeight = -height;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = (short)depth;
+ if (OS.IsWinCE) bmiHeader.biCompression = OS.BI_BITFIELDS;
+ else bmiHeader.biCompression = OS.BI_RGB;
+ byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + (OS.IsWinCE ? 12 : 0)];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+ /* Set the rgb colors into the bitmap info */
+ if (OS.IsWinCE) {
+ int redMask = 0xFF00;
+ int greenMask = 0xFF0000;
+ int blueMask = 0xFF000000;
+ /* big endian */
+ int offset = BITMAPINFOHEADER.sizeof;
+ bmi[offset] = (byte)((redMask & 0xFF000000) >> 24);
+ bmi[offset + 1] = (byte)((redMask & 0xFF0000) >> 16);
+ bmi[offset + 2] = (byte)((redMask & 0xFF00) >> 8);
+ bmi[offset + 3] = (byte)((redMask & 0xFF) >> 0);
+ bmi[offset + 4] = (byte)((greenMask & 0xFF000000) >> 24);
+ bmi[offset + 5] = (byte)((greenMask & 0xFF0000) >> 16);
+ bmi[offset + 6] = (byte)((greenMask & 0xFF00) >> 8);
+ bmi[offset + 7] = (byte)((greenMask & 0xFF) >> 0);
+ bmi[offset + 8] = (byte)((blueMask & 0xFF000000) >> 24);
+ bmi[offset + 9] = (byte)((blueMask & 0xFF0000) >> 16);
+ bmi[offset + 10] = (byte)((blueMask & 0xFF00) >> 8);
+ bmi[offset + 11] = (byte)((blueMask & 0xFF) >> 0);
+ }
+
+ int /*long*/[] pBits = new int /*long*/[1];
+ return OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
+}
+
+/**
+ * Feature in WinCE. GetIconInfo is not available in WinCE.
+ * The workaround is to cache the object ImageData for images
+ * of type SWT.ICON. The bitmaps hbmMask and hbmColor can then
+ * be reconstructed by using our version of getIconInfo.
+ * This function takes an ICONINFO object and sets the fields
+ * hbmMask and hbmColor with the corresponding bitmaps it has
+ * created.
+ * Note. These bitmaps must be freed - as they would have to be
+ * if the regular GetIconInfo had been used.
+ */
+static void GetIconInfo(Image image, ICONINFO info) {
+ int /*long*/ [] result = init(image.device, null, image.data);
+ info.hbmColor = result[0];
+ info.hbmMask = result[1];
+}
+
+static int /*long*/ [] init(Device device, Image image, ImageData i) {
+ /*
+ * BUG in Windows 98:
+ * A monochrome DIBSection will display as solid black
+ * on Windows 98 machines, even though it contains the
+ * correct data. The fix is to convert 1-bit ImageData
+ * into 4-bit ImageData before creating the image.
+ */
+ /* Windows does not support 2-bit images. Convert to 4-bit image. */
+ if ((OS.IsWin95 && i.depth == 1 && i.getTransparencyType() != SWT.TRANSPARENCY_MASK) || i.depth == 2) {
+ ImageData img = new ImageData(i.width, i.height, 4, i.palette);
+ ImageData.blit(ImageData.BLIT_SRC,
+ i.data, i.depth, i.bytesPerLine, i.getByteOrder(), 0, 0, i.width, i.height, null, null, null,
+ ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+ img.data, img.depth, img.bytesPerLine, i.getByteOrder(), 0, 0, img.width, img.height, null, null, null,
+ false, false);
+ img.transparentPixel = i.transparentPixel;
+ img.maskPad = i.maskPad;
+ img.maskData = i.maskData;
+ img.alpha = i.alpha;
+ img.alphaData = i.alphaData;
+ i = img;
+ }
+ /*
+ * Windows supports 16-bit mask of (0x7C00, 0x3E0, 0x1F),
+ * 24-bit mask of (0xFF0000, 0xFF00, 0xFF) and 32-bit mask
+ * (0x00FF0000, 0x0000FF00, 0x000000FF) as documented in
+ * MSDN BITMAPINFOHEADER. Make sure the image is
+ * Windows-supported.
+ */
+ /*
+ * Note on WinCE. CreateDIBSection requires the biCompression
+ * field of the BITMAPINFOHEADER to be set to BI_BITFIELDS for
+ * 16 and 32 bit direct images (see MSDN for CreateDIBSection).
+ * In this case, the color mask can be set to any value. For
+ * consistency, it is set to the same mask used by non WinCE
+ * platforms in BI_RGB mode.
+ */
+ if (i.palette.isDirect) {
+ final PaletteData palette = i.palette;
+ final int redMask = palette.redMask;
+ final int greenMask = palette.greenMask;
+ final int blueMask = palette.blueMask;
+ int newDepth = i.depth;
+ int newOrder = ImageData.MSB_FIRST;
+ PaletteData newPalette = null;
+
+ switch (i.depth) {
+ case 8:
+ newDepth = 16;
+ newOrder = ImageData.LSB_FIRST;
+ newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
+ break;
+ case 16:
+ newOrder = ImageData.LSB_FIRST;
+ if (!(redMask == 0x7C00 && greenMask == 0x3E0 && blueMask == 0x1F)) {
+ newPalette = new PaletteData(0x7C00, 0x3E0, 0x1F);
+ }
+ break;
+ case 24:
+ if (!(redMask == 0xFF && greenMask == 0xFF00 && blueMask == 0xFF0000)) {
+ newPalette = new PaletteData(0xFF, 0xFF00, 0xFF0000);
+ }
+ break;
+ case 32:
+ if (!(redMask == 0xFF00 && greenMask == 0xFF0000 && blueMask == 0xFF000000)) {
+ newPalette = new PaletteData(0xFF00, 0xFF0000, 0xFF000000);
+ }
+ break;
+ default:
+ SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH);
+ }
+ if (newPalette != null) {
+ ImageData img = new ImageData(i.width, i.height, newDepth, newPalette);
+ ImageData.blit(ImageData.BLIT_SRC,
+ i.data, i.depth, i.bytesPerLine, i.getByteOrder(), 0, 0, i.width, i.height, redMask, greenMask, blueMask,
+ ImageData.ALPHA_OPAQUE, null, 0, 0, 0,
+ img.data, img.depth, img.bytesPerLine, newOrder, 0, 0, img.width, img.height, newPalette.redMask, newPalette.greenMask, newPalette.blueMask,
+ false, false);
+ if (i.transparentPixel != -1) {
+ img.transparentPixel = newPalette.getPixel(palette.getRGB(i.transparentPixel));
+ }
+ img.maskPad = i.maskPad;
+ img.maskData = i.maskData;
+ img.alpha = i.alpha;
+ img.alphaData = i.alphaData;
+ i = img;
+ }
+ }
+ /* Construct bitmap info header by hand */
+ RGB[] rgbs = i.palette.getRGBs();
+ boolean useBitfields = OS.IsWinCE && (i.depth == 16 || i.depth == 32);
+ BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
+ bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
+ bmiHeader.biWidth = i.width;
+ bmiHeader.biHeight = -i.height;
+ bmiHeader.biPlanes = 1;
+ bmiHeader.biBitCount = (short)i.depth;
+ if (useBitfields) bmiHeader.biCompression = OS.BI_BITFIELDS;
+ else bmiHeader.biCompression = OS.BI_RGB;
+ bmiHeader.biClrUsed = rgbs == null ? 0 : rgbs.length;
+ byte[] bmi;
+ if (i.palette.isDirect)
+ bmi = new byte[BITMAPINFOHEADER.sizeof + (useBitfields ? 12 : 0)];
+ else
+ bmi = new byte[BITMAPINFOHEADER.sizeof + rgbs.length * 4];
+ OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
+ /* Set the rgb colors into the bitmap info */
+ int offset = BITMAPINFOHEADER.sizeof;
+ if (i.palette.isDirect) {
+ if (useBitfields) {
+ PaletteData palette = i.palette;
+ int redMask = palette.redMask;
+ int greenMask = palette.greenMask;
+ int blueMask = palette.blueMask;
+ /*
+ * The color masks must be written based on the
+ * endianness of the ImageData.
+ */
+ if (i.getByteOrder() == ImageData.LSB_FIRST) {
+ bmi[offset] = (byte)((redMask & 0xFF) >> 0);
+ bmi[offset + 1] = (byte)((redMask & 0xFF00) >> 8);
+ bmi[offset + 2] = (byte)((redMask & 0xFF0000) >> 16);
+ bmi[offset + 3] = (byte)((redMask & 0xFF000000) >> 24);
+ bmi[offset + 4] = (byte)((greenMask & 0xFF) >> 0);
+ bmi[offset + 5] = (byte)((greenMask & 0xFF00) >> 8);
+ bmi[offset + 6] = (byte)((greenMask & 0xFF0000) >> 16);
+ bmi[offset + 7] = (byte)((greenMask & 0xFF000000) >> 24);
+ bmi[offset + 8] = (byte)((blueMask & 0xFF) >> 0);
+ bmi[offset + 9] = (byte)((blueMask & 0xFF00) >> 8);
+ bmi[offset + 10] = (byte)((blueMask & 0xFF0000) >> 16);
+ bmi[offset + 11] = (byte)((blueMask & 0xFF000000) >> 24);
+ } else {
+ bmi[offset] = (byte)((redMask & 0xFF000000) >> 24);
+ bmi[offset + 1] = (byte)((redMask & 0xFF0000) >> 16);
+ bmi[offset + 2] = (byte)((redMask & 0xFF00) >> 8);
+ bmi[offset + 3] = (byte)((redMask & 0xFF) >> 0);
+ bmi[offset + 4] = (byte)((greenMask & 0xFF000000) >> 24);
+ bmi[offset + 5] = (byte)((greenMask & 0xFF0000) >> 16);
+ bmi[offset + 6] = (byte)((greenMask & 0xFF00) >> 8);
+ bmi[offset + 7] = (byte)((greenMask & 0xFF) >> 0);
+ bmi[offset + 8] = (byte)((blueMask & 0xFF000000) >> 24);
+ bmi[offset + 9] = (byte)((blueMask & 0xFF0000) >> 16);
+ bmi[offset + 10] = (byte)((blueMask & 0xFF00) >> 8);
+ bmi[offset + 11] = (byte)((blueMask & 0xFF) >> 0);
+ }
+ }
+ } else {
+ for (int j = 0; j < rgbs.length; j++) {
+ bmi[offset] = (byte)rgbs[j].blue;
+ bmi[offset + 1] = (byte)rgbs[j].green;
+ bmi[offset + 2] = (byte)rgbs[j].red;
+ bmi[offset + 3] = 0;
+ offset += 4;
+ }
+ }
+ int /*long*/[] pBits = new int /*long*/[1];
+ int /*long*/ hDib = OS.CreateDIBSection(0, bmi, OS.DIB_RGB_COLORS, pBits, 0, 0);
+ if (hDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ /* In case of a scanline pad other than 4, do the work to convert it */
+ byte[] data = i.data;
+ if (i.scanlinePad != 4 && (i.bytesPerLine % 4 != 0)) {
+ data = ImageData.convertPad(data, i.width, i.height, i.depth, i.scanlinePad, 4);
+ }
+ OS.MoveMemory(pBits[0], data, data.length);
+
+ int /*long*/ [] result = null;
+ if (i.getTransparencyType() == SWT.TRANSPARENCY_MASK) {
+ /* Get the HDC for the device */
+ int /*long*/ hDC = device.internal_new_GC(null);
+
+ /* Create the color bitmap */
+ int /*long*/ hdcSrc = OS.CreateCompatibleDC(hDC);
+ OS.SelectObject(hdcSrc, hDib);
+ int /*long*/ hBitmap = OS.CreateCompatibleBitmap(hDC, i.width, i.height);
+ if (hBitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ hdcDest = OS.CreateCompatibleDC(hDC);
+ OS.SelectObject(hdcDest, hBitmap);
+ OS.BitBlt(hdcDest, 0, 0, i.width, i.height, hdcSrc, 0, 0, OS.SRCCOPY);
+
+ /* Release the HDC for the device */
+ device.internal_dispose_GC(hDC, null);
+
+ /* Create the mask. Windows requires icon masks to have a scanline pad of 2. */
+ byte[] maskData = ImageData.convertPad(i.maskData, i.width, i.height, 1, i.maskPad, 2);
+ int /*long*/ hMask = OS.CreateBitmap(i.width, i.height, 1, 1, maskData);
+ if (hMask == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.SelectObject(hdcSrc, hMask);
+ OS.PatBlt(hdcSrc, 0, 0, i.width, i.height, OS.DSTINVERT);
+ OS.DeleteDC(hdcSrc);
+ OS.DeleteDC(hdcDest);
+ OS.DeleteObject(hDib);
+
+ if (image == null) {
+ result = new int /*long*/ []{hBitmap, hMask};
+ } else {
+ /* Create the icon */
+ ICONINFO info = new ICONINFO();
+ info.fIcon = true;
+ info.hbmColor = hBitmap;
+ info.hbmMask = hMask;
+ int /*long*/ hIcon = OS.CreateIconIndirect(info);
+ if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.DeleteObject(hBitmap);
+ OS.DeleteObject(hMask);
+ image.handle = hIcon;
+ image.type = SWT.ICON;
+ if (OS.IsWinCE) image.data = i;
+ }
+ } else {
+ if (image == null) {
+ result = new int /*long*/ []{hDib};
+ } else {
+ image.handle = hDib;
+ image.type = SWT.BITMAP;
+ image.transparentPixel = i.transparentPixel;
+ if (image.transparentPixel == -1) {
+ image.alpha = i.alpha;
+ if (i.alpha == -1 && i.alphaData != null) {
+ int length = i.alphaData.length;
+ image.alphaData = new byte[length];
+ System.arraycopy(i.alphaData, 0, image.alphaData, 0, length);
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static int /*long*/ [] init(Device device, Image image, ImageData source, ImageData mask) {
+ /* Create a temporary image and locate the black pixel */
+ ImageData imageData;
+ int blackIndex = 0;
+ if (source.palette.isDirect) {
+ imageData = new ImageData(source.width, source.height, source.depth, source.palette);
+ } else {
+ RGB black = new RGB(0, 0, 0);
+ RGB[] rgbs = source.getRGBs();
+ if (source.transparentPixel != -1) {
+ /*
+ * The source had transparency, so we can use the transparent pixel
+ * for black.
+ */
+ RGB[] newRGBs = new RGB[rgbs.length];
+ System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length);
+ if (source.transparentPixel >= newRGBs.length) {
+ /* Grow the palette with black */
+ rgbs = new RGB[source.transparentPixel + 1];
+ System.arraycopy(newRGBs, 0, rgbs, 0, newRGBs.length);
+ for (int i = newRGBs.length; i <= source.transparentPixel; i++) {
+ rgbs[i] = new RGB(0, 0, 0);
+ }
+ } else {
+ newRGBs[source.transparentPixel] = black;
+ rgbs = newRGBs;
+ }
+ blackIndex = source.transparentPixel;
+ imageData = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs));
+ } else {
+ while (blackIndex < rgbs.length) {
+ if (rgbs[blackIndex].equals(black)) break;
+ blackIndex++;
+ }
+ if (blackIndex == rgbs.length) {
+ /*
+ * We didn't find black in the palette, and there is no transparent
+ * pixel we can use.
+ */
+ if ((1 << source.depth) > rgbs.length) {
+ /* We can grow the palette and add black */
+ RGB[] newRGBs = new RGB[rgbs.length + 1];
+ System.arraycopy(rgbs, 0, newRGBs, 0, rgbs.length);
+ newRGBs[rgbs.length] = black;
+ rgbs = newRGBs;
+ } else {
+ /* No room to grow the palette */
+ blackIndex = -1;
+ }
+ }
+ imageData = new ImageData(source.width, source.height, source.depth, new PaletteData(rgbs));
+ }
+ }
+ if (blackIndex == -1) {
+ /* There was no black in the palette, so just copy the data over */
+ System.arraycopy(source.data, 0, imageData.data, 0, imageData.data.length);
+ } else {
+ /* Modify the source image to contain black wherever the mask is 0 */
+ int[] imagePixels = new int[imageData.width];
+ int[] maskPixels = new int[mask.width];
+ for (int y = 0; y < imageData.height; y++) {
+ source.getPixels(0, y, imageData.width, imagePixels, 0);
+ mask.getPixels(0, y, mask.width, maskPixels, 0);
+ for (int i = 0; i < imagePixels.length; i++) {
+ if (maskPixels[i] == 0) imagePixels[i] = blackIndex;
+ }
+ imageData.setPixels(0, y, source.width, imagePixels, 0);
+ }
+ }
+ imageData.maskPad = mask.scanlinePad;
+ imageData.maskData = mask.data;
+ return init(device, image, imageData);
+}
+void init(ImageData i) {
+ if (i == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(device, this, i);
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Image</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param data the platform specific GC data
+ * @return the platform specific GC handle
+ */
+public int /*long*/ internal_new_GC (GCData data) {
+ if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ /*
+ * Create a new GC that can draw into the image.
+ * Only supported for bitmaps.
+ */
+ if (type != SWT.BITMAP || memGC != null) {
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+
+ /* Create a compatible HDC for the device */
+ int /*long*/ hDC = device.internal_new_GC(null);
+ int /*long*/ imageDC = OS.CreateCompatibleDC(hDC);
+ device.internal_dispose_GC(hDC, null);
+ if (imageDC == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+
+ if (data != null) {
+ /* Set the GCData fields */
+ int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+ if ((data.style & mask) != 0) {
+ data.layout = (data.style & SWT.RIGHT_TO_LEFT) != 0 ? OS.LAYOUT_RTL : 0;
+ } else {
+ data.style |= SWT.LEFT_TO_RIGHT;
+ }
+ data.device = device;
+ data.image = this;
+ data.font = device.systemFont;
+ }
+ return imageDC;
+}
+
+/**
+ * Invokes platform specific functionality to dispose a GC handle.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Image</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param hDC the platform specific GC handle
+ * @param data the platform specific GC data
+ */
+public void internal_dispose_GC (int /*long*/ hDC, GCData data) {
+ OS.DeleteDC(hDC);
+}
+
+/**
+ * Returns <code>true</code> if the image has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the image.
+ * When an image has been disposed, it is an error to
+ * invoke any other method using the image.
+ *
+ * @return <code>true</code> when the image is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Sets the color to which to map the transparent pixel.
+ * <p>
+ * There are certain uses of <code>Images</code> that do not support
+ * transparency (for example, setting an image into a button or label).
+ * In these cases, it may be desired to simulate transparency by using
+ * the background color of the widget to paint the transparent pixels
+ * of the image. This method specifies the color that will be used in
+ * these cases. For example:
+ * <pre>
+ * Button b = new Button();
+ * image.setBackground(b.getBackground());
+ * b.setImage(image);
+ * </pre>
+ * </p><p>
+ * The image may be modified by this operation (in effect, the
+ * transparent regions may be filled with the supplied color). Hence
+ * this operation is not reversible and it is not legal to call
+ * this function twice or with a null argument.
+ * </p><p>
+ * This method has no effect if the receiver does not have a transparent
+ * pixel value.
+ * </p>
+ *
+ * @param color the color to use when a transparent pixel is specified
+ *
+ * @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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setBackground(Color color) {
+ /*
+ * Note. Not implemented on WinCE.
+ */
+ if (OS.IsWinCE) return;
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (transparentPixel == -1) return;
+ transparentColor = -1;
+
+ /* Get the HDC for the device */
+ int /*long*/ hDC = device.internal_new_GC(null);
+
+ /* Change the background color in the image */
+ BITMAP bm = new BITMAP();
+ OS.GetObject(handle, BITMAP.sizeof, bm);
+ int /*long*/ hdcMem = OS.CreateCompatibleDC(hDC);
+ OS.SelectObject(hdcMem, handle);
+ int maxColors = 1 << bm.bmBitsPixel;
+ byte[] colors = new byte[maxColors * 4];
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ int numColors = OS.GetDIBColorTable(hdcMem, 0, maxColors, colors);
+ int offset = transparentPixel * 4;
+ colors[offset] = (byte)color.getBlue();
+ colors[offset + 1] = (byte)color.getGreen();
+ colors[offset + 2] = (byte)color.getRed();
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ OS.SetDIBColorTable(hdcMem, 0, numColors, colors);
+ OS.DeleteDC(hdcMem);
+
+ /* Release the HDC for the device */
+ device.internal_dispose_GC(hDC, null);
+}
+
+/**
+ * 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 "Image {*DISPOSED*}";
+ return "Image {" + handle + "}";
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new image.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Image</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the color
+ * @param type the type of the image (<code>SWT.BITMAP</code> or <code>SWT.ICON</code>)
+ * @param handle the OS handle for the image
+ * @return a new image object containing the specified device, type and handle
+ */
+public static Image win32_new(Device device, int type, int /*long*/ handle) {
+ Image image = new Image(device);
+ image.type = type;
+ image.handle = handle;
+ return image;
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Path.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Path.java
new file mode 100644
index 0000000000..db666da42b
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Path.java
@@ -0,0 +1,602 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent paths through the two-dimensional
+ * coordinate system. Paths do not have to be continuous, and can be
+ * described using lines, rectangles, arcs, cubic or quadratic bezier curves,
+ * glyphs, or other paths.
+ * <p>
+ * Application code must explicitly invoke the <code>Path.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ * <p>
+ * This class requires the operating system's advanced graphics subsystem
+ * which may not be available on some platforms.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#path">Path, Pattern snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: GraphicsExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.1
+ */
+public class Path extends Resource {
+
+ /**
+ * the OS resource for the Path
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int /*long*/ handle;
+
+ PointF currentPoint = new PointF(), startPoint = new PointF();
+
+/**
+ * Constructs a new empty Path.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the path
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the path could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Path (Device device) {
+ super(device);
+ this.device.checkGDIP();
+ handle = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+}
+
+/**
+ * Constructs a new Path that is a copy of <code>path</code>. If
+ * <code>flatness</code> is less than or equal to zero, an unflatten
+ * copy of the path is created. Otherwise, it specifies the maximum
+ * error between the path and its flatten copy. Smaller numbers give
+ * better approximation.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the path
+ * @param path the path to make a copy
+ * @param flatness the flatness value
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the path is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the path has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the path could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ * @since 3.4
+ */
+public Path (Device device, Path path, float flatness) {
+ super(device);
+ if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ flatness = Math.max(0, flatness);
+ handle = Gdip.GraphicsPath_Clone(path.handle);
+ if (flatness != 0) Gdip.GraphicsPath_Flatten(handle, 0, flatness);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+}
+
+/**
+ * Constructs a new Path with the specifed PathData.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the path
+ * @param data the data for the path
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device</li>
+ * <li>ERROR_NULL_ARGUMENT - if the data is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the path could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ * @since 3.4
+ */
+public Path (Device device, PathData data) {
+ this(device);
+ if (data == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ init(data);
+}
+
+/**
+ * Adds to the receiver a circular or elliptical arc that lies within
+ * the specified rectangular area.
+ * <p>
+ * The resulting arc begins at <code>startAngle</code> and extends
+ * for <code>arcAngle</code> degrees.
+ * 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
+ * @param y the y coordinate of the upper-left corner of the arc
+ * @param width the width of the arc
+ * @param height the height of the arc
+ * @param startAngle the beginning angle
+ * @param arcAngle the angular extent of the arc, relative to the start angle
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void addArc(float x, float y, float width, float height, float startAngle, float arcAngle) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width < 0) {
+ x = x + width;
+ width = -width;
+ }
+ if (height < 0) {
+ y = y + height;
+ height = -height;
+ }
+ if (width == 0 || height == 0 || arcAngle == 0) return;
+ if (width == height) {
+ Gdip.GraphicsPath_AddArc(handle, x, y, width, height, -startAngle, -arcAngle);
+ } else {
+ int /*long*/ path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
+ if (path == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int /*long*/ matrix = Gdip.Matrix_new(width, 0, 0, height, x, y);
+ if (matrix == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.GraphicsPath_AddArc(path, 0, 0, 1, 1, -startAngle, -arcAngle);
+ Gdip.GraphicsPath_Transform(path, matrix);
+ Gdip.GraphicsPath_AddPath(handle, path, true);
+ Gdip.Matrix_delete(matrix);
+ Gdip.GraphicsPath_delete(path);
+ }
+ Gdip.GraphicsPath_GetLastPoint(handle, currentPoint);
+}
+
+/**
+ * Adds to the receiver the path described by the parameter.
+ *
+ * @param path the path to add to the receiver
+ *
+ * @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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void addPath(Path path) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ //TODO - expose connect?
+ Gdip.GraphicsPath_AddPath(handle, path.handle, false);
+ currentPoint.X = path.currentPoint.X;
+ currentPoint.Y = path.currentPoint.Y;
+}
+
+/**
+ * Adds to the receiver the rectangle specified by x, y, width and height.
+ *
+ * @param x the x coordinate of the rectangle to add
+ * @param y the y coordinate of the rectangle to add
+ * @param width the width of the rectangle to add
+ * @param height the height of the rectangle to add
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void addRectangle(float x, float y, float width, float height) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ RectF rect = new RectF();
+ rect.X = x;
+ rect.Y = y;
+ rect.Width = width;
+ rect.Height = height;
+ Gdip.GraphicsPath_AddRectangle(handle, rect);
+ currentPoint.X = x;
+ currentPoint.Y = y;
+}
+
+/**
+ * Adds to the receiver the pattern of glyphs generated by drawing
+ * the given string using the given font starting at the point (x, y).
+ *
+ * @param string the text to use
+ * @param x the x coordinate of the starting point
+ * @param y the y coordinate of the starting point
+ * @param font the font to use
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the font is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void addString(String string, float x, float y, Font font) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (font == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ int length = string.length();
+ char[] buffer = new char[length];
+ string.getChars(0, length, buffer, 0);
+ int /*long*/ hDC = device.internal_new_GC(null);
+ int /*long*/ [] family = new int /*long*/ [1];
+ int /*long*/ gdipFont = GC.createGdipFont(hDC, font.handle, 0, device.fontCollection, family, null);
+ PointF point = new PointF();
+ point.X = x - (Gdip.Font_GetSize(gdipFont) / 6);
+ point.Y = y;
+ int style = Gdip.Font_GetStyle(gdipFont);
+ float size = Gdip.Font_GetSize(gdipFont);
+ Gdip.GraphicsPath_AddString(handle, buffer, length, family[0], style, size, point, 0);
+ Gdip.GraphicsPath_GetLastPoint(handle, currentPoint);
+ Gdip.FontFamily_delete(family[0]);
+ Gdip.Font_delete(gdipFont);
+ device.internal_dispose_GC(hDC, null);
+}
+
+/**
+ * Closes the current sub path by adding to the receiver a line
+ * from the current point of the path back to the starting point
+ * of the sub path.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void close() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ Gdip.GraphicsPath_CloseFigure(handle);
+ /*
+ * Feature in GDI+. CloseFigure() does affect the last
+ * point, so GetLastPoint() does not return the starting
+ * point of the subpath after calling CloseFigure(). The
+ * fix is to remember the subpath starting point and use
+ * it instead.
+ */
+ currentPoint.X = startPoint.X;
+ currentPoint.Y = startPoint.Y;
+}
+
+/**
+ * Returns <code>true</code> if the specified point is contained by
+ * the receiver and false otherwise.
+ * <p>
+ * If outline is <code>true</code>, the point (x, y) checked for containment in
+ * the receiver's outline. If outline is <code>false</code>, the point is
+ * checked to see if it is contained within the bounds of the (closed) area
+ * covered by the receiver.
+ *
+ * @param x the x coordinate of the point to test for containment
+ * @param y the y coordinate of the point to test for containment
+ * @param gc the GC to use when testing for containment
+ * @param outline controls whether to check the outline or contained area of the path
+ * @return <code>true</code> if the path contains the point and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the gc has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean contains(float x, float y, GC gc, boolean outline) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ //TODO - should use GC transformation
+ gc.initGdip();
+ gc.checkGC(GC.LINE_CAP | GC.LINE_JOIN | GC.LINE_STYLE | GC.LINE_WIDTH);
+ int mode = OS.GetPolyFillMode(gc.handle) == OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate;
+ Gdip.GraphicsPath_SetFillMode(handle, mode);
+ if (outline) {
+ return Gdip.GraphicsPath_IsOutlineVisible(handle, x, y, gc.data.gdipPen, gc.data.gdipGraphics);
+ } else {
+ return Gdip.GraphicsPath_IsVisible(handle, x, y, gc.data.gdipGraphics);
+ }
+}
+
+/**
+ * Adds to the receiver a cubic bezier curve based on the parameters.
+ *
+ * @param cx1 the x coordinate of the first control point of the spline
+ * @param cy1 the y coordinate of the first control of the spline
+ * @param cx2 the x coordinate of the second control of the spline
+ * @param cy2 the y coordinate of the second control of the spline
+ * @param x the x coordinate of the end point of the spline
+ * @param y the y coordinate of the end point of the spline
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void cubicTo(float cx1, float cy1, float cx2, float cy2, float x, float y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ Gdip.GraphicsPath_AddBezier(handle, currentPoint.X, currentPoint.Y, cx1, cy1, cx2, cy2, x, y);
+ Gdip.GraphicsPath_GetLastPoint(handle, currentPoint);
+}
+
+void destroy() {
+ Gdip.GraphicsPath_delete(handle);
+ handle = 0;
+}
+
+/**
+ * Replaces the first four elements in the parameter with values that
+ * describe the smallest rectangle that will completely contain the
+ * receiver (i.e. the bounding box).
+ *
+ * @param bounds the array to hold the result
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the bounding box</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void getBounds(float[] bounds) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (bounds == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (bounds.length < 4) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ RectF rect = new RectF();
+ Gdip.GraphicsPath_GetBounds(handle, rect, 0, 0);
+ bounds[0] = rect.X;
+ bounds[1] = rect.Y;
+ bounds[2] = rect.Width;
+ bounds[3] = rect.Height;
+}
+
+/**
+ * Replaces the first two elements in the parameter with values that
+ * describe the current point of the path.
+ *
+ * @param point the array to hold the result
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the end point</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void getCurrentPoint(float[] point) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (point == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (point.length < 2) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ point[0] = currentPoint.X;
+ point[1] = currentPoint.Y;
+}
+
+/**
+ * Returns a device independent representation of the receiver.
+ *
+ * @return the PathData for the receiver
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see PathData
+ */
+public PathData getPathData() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ int count = Gdip.GraphicsPath_GetPointCount(handle);
+ byte[] gdipTypes = new byte[count];
+ float[] points = new float[count * 2];
+ Gdip.GraphicsPath_GetPathTypes(handle, gdipTypes, count);
+ Gdip.GraphicsPath_GetPathPoints(handle, points, count);
+ byte[] types = new byte[count * 2];
+ int index = 0, typesIndex = 0;
+ while (index < count) {
+ byte type = gdipTypes[index];
+ boolean close = false;
+ switch (type & Gdip.PathPointTypePathTypeMask) {
+ case Gdip.PathPointTypeStart:
+ types[typesIndex++] = SWT.PATH_MOVE_TO;
+ close = (type & Gdip.PathPointTypeCloseSubpath) != 0;
+ index += 1;
+ break;
+ case Gdip.PathPointTypeLine:
+ types[typesIndex++] = SWT.PATH_LINE_TO;
+ close = (type & Gdip.PathPointTypeCloseSubpath) != 0;
+ index += 1;
+ break;
+ case Gdip.PathPointTypeBezier:
+ types[typesIndex++] = SWT.PATH_CUBIC_TO;
+ close = (gdipTypes[index + 2] & Gdip.PathPointTypeCloseSubpath) != 0;
+ index += 3;
+ break;
+ default:
+ index++;
+ }
+ if (close) {
+ types[typesIndex++] = SWT.PATH_CLOSE;
+ }
+ }
+ if (typesIndex != types.length) {
+ byte[] newTypes = new byte[typesIndex];
+ System.arraycopy(types, 0, newTypes, 0, typesIndex);
+ types = newTypes;
+ }
+ PathData result = new PathData();
+ result.types = types;
+ result.points = points;
+ return result;
+}
+
+/**
+ * Adds to the receiver a line from the current point to
+ * the point specified by (x, y).
+ *
+ * @param x the x coordinate of the end of the line to add
+ * @param y the y coordinate of the end of the line to add
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void lineTo(float x, float y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ Gdip.GraphicsPath_AddLine(handle, currentPoint.X, currentPoint.Y, x, y);
+ Gdip.GraphicsPath_GetLastPoint(handle, currentPoint);
+}
+
+void init(PathData data) {
+ byte[] types = data.types;
+ float[] points = data.points;
+ for (int i = 0, j = 0; i < types.length; i++) {
+ switch (types[i]) {
+ case SWT.PATH_MOVE_TO:
+ moveTo(points[j++], points[j++]);
+ break;
+ case SWT.PATH_LINE_TO:
+ lineTo(points[j++], points[j++]);
+ break;
+ case SWT.PATH_CUBIC_TO:
+ cubicTo(points[j++], points[j++], points[j++], points[j++], points[j++], points[j++]);
+ break;
+ case SWT.PATH_QUAD_TO:
+ quadTo(points[j++], points[j++], points[j++], points[j++]);
+ break;
+ case SWT.PATH_CLOSE:
+ close();
+ break;
+ default:
+ dispose();
+ SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ }
+ }
+}
+
+/**
+ * Returns <code>true</code> if the Path has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the Path.
+ * When a Path has been disposed, it is an error to
+ * invoke any other method using the Path.
+ *
+ * @return <code>true</code> when the Path is disposed, and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Sets the current point of the receiver to the point
+ * specified by (x, y). Note that this starts a new
+ * sub path.
+ *
+ * @param x the x coordinate of the new end point
+ * @param y the y coordinate of the new end point
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void moveTo(float x, float y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ Gdip.GraphicsPath_StartFigure(handle);
+ currentPoint.X = startPoint.X = x;
+ currentPoint.Y = startPoint.Y = y;
+}
+
+/**
+ * Adds to the receiver a quadratic curve based on the parameters.
+ *
+ * @param cx the x coordinate of the control point of the spline
+ * @param cy the y coordinate of the control point of the spline
+ * @param x the x coordinate of the end point of the spline
+ * @param y the y coordinate of the end point of the spline
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void quadTo(float cx, float cy, float x, float y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ float cx1 = currentPoint.X + 2 * (cx - currentPoint.X) / 3;
+ float cy1 = currentPoint.Y + 2 * (cy - currentPoint.Y) / 3;
+ float cx2 = cx1 + (x - currentPoint.X) / 3;
+ float cy2 = cy1 + (y - currentPoint.Y) / 3;
+ Gdip.GraphicsPath_AddBezier(handle, currentPoint.X, currentPoint.Y, cx1, cy1, cx2, cy2, x, y);
+ Gdip.GraphicsPath_GetLastPoint(handle, currentPoint);
+}
+
+/**
+ * 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 "Path {*DISPOSED*}";
+ return "Path {" + handle + "}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Pattern.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Pattern.java
new file mode 100644
index 0000000000..406fcec965
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Pattern.java
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.win32.*;
+
+/**
+ * Instances of this class represent patterns to use while drawing. Patterns
+ * can be specified either as bitmaps or gradients.
+ * <p>
+ * Application code must explicitly invoke the <code>Pattern.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ * <p>
+ * This class requires the operating system's advanced graphics subsystem
+ * which may not be available on some platforms.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#path">Path, Pattern snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: GraphicsExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.1
+ */
+public class Pattern extends Resource {
+
+ /**
+ * the OS resource for the Pattern
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int /*long*/ handle;
+
+/**
+ * Constructs a new Pattern given an image. Drawing with the resulting
+ * pattern will cause the image to be tiled over the resulting area.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the pattern
+ * @param image the image that the pattern will draw
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device, or the image is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Pattern(Device device, Image image) {
+ super(device);
+ if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ this.device.checkGDIP();
+ int /*long*/[] gdipImage = image.createGdipImage();
+ int /*long*/ img = gdipImage[0];
+ int width = Gdip.Image_GetWidth(img);
+ int height = Gdip.Image_GetHeight(img);
+ handle = Gdip.TextureBrush_new(img, Gdip.WrapModeTile, 0, 0, width, height);
+ Gdip.Bitmap_delete(img);
+ if (gdipImage[1] != 0) {
+ int /*long*/ hHeap = OS.GetProcessHeap ();
+ OS.HeapFree(hHeap, 0, gdipImage[1]);
+ }
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+}
+
+/**
+ * Constructs a new Pattern that represents a linear, two color
+ * gradient. Drawing with the pattern will cause the resulting area to be
+ * tiled with the gradient specified by the arguments.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the pattern
+ * @param x1 the x coordinate of the starting corner of the gradient
+ * @param y1 the y coordinate of the starting corner of the gradient
+ * @param x2 the x coordinate of the ending corner of the gradient
+ * @param y2 the y coordinate of the ending corner of the gradient
+ * @param color1 the starting color of the gradient
+ * @param color2 the ending color of the gradient
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device,
+ * or if either color1 or color2 is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if either color1 or color2 has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Pattern(Device device, float x1, float y1, float x2, float y2, Color color1, Color color2) {
+ this(device, x1, y1, x2, y2, color1, 0xFF, color2, 0xFF);
+}
+
+/**
+ * Constructs a new Pattern that represents a linear, two color
+ * gradient. Drawing with the pattern will cause the resulting area to be
+ * tiled with the gradient specified by the arguments.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the pattern
+ * @param x1 the x coordinate of the starting corner of the gradient
+ * @param y1 the y coordinate of the starting corner of the gradient
+ * @param x2 the x coordinate of the ending corner of the gradient
+ * @param y2 the y coordinate of the ending corner of the gradient
+ * @param color1 the starting color of the gradient
+ * @param alpha1 the starting alpha value of the gradient
+ * @param color2 the ending color of the gradient
+ * @param alpha2 the ending alpha value of the gradient
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the device is null and there is no current device,
+ * or if either color1 or color2 is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if either color1 or color2 has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the pattern could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ *
+ * @since 3.2
+ */
+public Pattern(Device device, float x1, float y1, float x2, float y2, Color color1, int alpha1, Color color2, int alpha2) {
+ super(device);
+ if (color1 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (color1.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (color2 == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (color2.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ this.device.checkGDIP();
+ int colorRef1 = color1.handle;
+ int rgb = ((colorRef1 >> 16) & 0xFF) | (colorRef1 & 0xFF00) | ((colorRef1 & 0xFF) << 16);
+ int /*long*/ foreColor = Gdip.Color_new((alpha1 & 0xFF) << 24 | rgb);
+ if (x1 == x2 && y1 == y2) {
+ handle = Gdip.SolidBrush_new(foreColor);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ } else {
+ int colorRef2 = color2.handle;
+ rgb = ((colorRef2 >> 16) & 0xFF) | (colorRef2 & 0xFF00) | ((colorRef2 & 0xFF) << 16);
+ int /*long*/ backColor = Gdip.Color_new((alpha2 & 0xFF) << 24 | rgb);
+ PointF p1 = new PointF();
+ p1.X = x1;
+ p1.Y = y1;
+ PointF p2 = new PointF();
+ p2.X = x2;
+ p2.Y = y2;
+ handle = Gdip.LinearGradientBrush_new(p1, p2, foreColor, backColor);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ if (alpha1 != 0xFF || alpha2 != 0xFF) {
+ int a = (int)((alpha1 & 0xFF) * 0.5f + (alpha2 & 0xFF) * 0.5f);
+ int r = (int)(((colorRef1 & 0xFF) >> 0) * 0.5f + ((colorRef2 & 0xFF) >> 0) * 0.5f);
+ int g = (int)(((colorRef1 & 0xFF00) >> 8) * 0.5f + ((colorRef2 & 0xFF00) >> 8) * 0.5f);
+ int b = (int)(((colorRef1 & 0xFF0000) >> 16) * 0.5f + ((colorRef2 & 0xFF0000) >> 16) * 0.5f);
+ int /*long*/ midColor = Gdip.Color_new(a << 24 | r << 16 | g << 8 | b);
+ Gdip.LinearGradientBrush_SetInterpolationColors(handle, new int /*long*/ []{foreColor, midColor, backColor}, new float[]{0, 0.5f, 1}, 3);
+ Gdip.Color_delete(midColor);
+ }
+ Gdip.Color_delete(backColor);
+ }
+ Gdip.Color_delete(foreColor);
+ init();
+}
+
+void destroy() {
+ int type = Gdip.Brush_GetType(handle);
+ switch (type) {
+ case Gdip.BrushTypeSolidColor:
+ Gdip.SolidBrush_delete(handle);
+ break;
+ case Gdip.BrushTypeHatchFill:
+ Gdip.HatchBrush_delete(handle);
+ break;
+ case Gdip.BrushTypeLinearGradient:
+ Gdip.LinearGradientBrush_delete(handle);
+ break;
+ case Gdip.BrushTypeTextureFill:
+ Gdip.TextureBrush_delete(handle);
+ break;
+ }
+ handle = 0;
+}
+
+/**
+ * Returns <code>true</code> if the Pattern has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the Pattern.
+ * When a Pattern has been disposed, it is an error to
+ * invoke any other method using the Pattern.
+ *
+ * @return <code>true</code> when the Pattern is disposed, and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * 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 "Pattern {*DISPOSED*}";
+ return "Pattern {" + handle + "}";
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java
new file mode 100755
index 0000000000..5c6383328a
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Region.java
@@ -0,0 +1,597 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+
+/**
+ * Instances of this class represent areas of an x-y coordinate
+ * system that are aggregates of the areas covered by a number
+ * of polygons.
+ * <p>
+ * Application code must explicitly invoke the <code>Region.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: GraphicsExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+
+public final class Region extends Resource {
+
+ /**
+ * the OS resource for the region
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int /*long*/ handle;
+
+/**
+ * Constructs a new empty region.
+ *
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for region creation</li>
+ * </ul>
+ */
+public Region () {
+ this(null);
+}
+
+/**
+ * Constructs a new empty region.
+ * <p>
+ * You must dispose the region when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the region
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle could not be obtained for region creation</li>
+ * </ul>
+ *
+ * @see #dispose
+ *
+ * @since 3.0
+ */
+public Region (Device device) {
+ super(device);
+ handle = OS.CreateRectRgn (0, 0, 0, 0);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+}
+
+/**
+ * Constructs a new region given a handle to the operating
+ * system resources that it should represent.
+ *
+ * @param handle the handle for the result
+ */
+Region(Device device, int handle) {
+ super(device);
+ this.handle = handle;
+}
+
+/**
+ * Adds the given polygon to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param pointArray points that describe the polygon to merge with the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+*
+ */
+public void add (int[] pointArray) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ int /*long*/ polyRgn = OS.CreatePolygonRgn(pointArray, pointArray.length / 2, OS.ALTERNATE);
+ OS.CombineRgn (handle, handle, polyRgn, OS.RGN_OR);
+ OS.DeleteObject (polyRgn);
+}
+
+/**
+ * Adds the given rectangle to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param rect the rectangle to merge with the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void add (Rectangle rect) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ add (rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * Adds the given rectangle to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param x the x coordinate of the rectangle
+ * @param y the y coordinate of the rectangle
+ * @param width the width coordinate of the rectangle
+ * @param height the height coordinate of the rectangle
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void add (int x, int y, int width, int height) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ int /*long*/ rectRgn = OS.CreateRectRgn (x, y, x + width, y + height);
+ OS.CombineRgn (handle, handle, rectRgn, OS.RGN_OR);
+ OS.DeleteObject (rectRgn);
+}
+
+/**
+ * Adds all of the polygons which make up the area covered
+ * by the argument to the collection of polygons the receiver
+ * maintains to describe its area.
+ *
+ * @param region the region to merge
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void add (Region region) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ OS.CombineRgn (handle, handle, region.handle, OS.RGN_OR);
+}
+
+/**
+ * Returns <code>true</code> if the point specified by the
+ * arguments is inside the area specified by the receiver,
+ * and <code>false</code> otherwise.
+ *
+ * @param x the x coordinate of the point to test for containment
+ * @param y the y coordinate of the point to test for containment
+ * @return <code>true</code> if the region contains the point and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean contains (int x, int y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return OS.PtInRegion (handle, x, y);
+}
+
+/**
+ * Returns <code>true</code> if the given point is inside the
+ * area specified by the receiver, and <code>false</code>
+ * otherwise.
+ *
+ * @param pt the point to test for containment
+ * @return <code>true</code> if the region contains the point and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean contains (Point pt) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ return contains(pt.x, pt.y);
+}
+
+void destroy () {
+ OS.DeleteObject(handle);
+ handle = 0;
+}
+
+/**
+ * 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 boolean equals (Object object) {
+ if (this == object) return true;
+ if (!(object instanceof Region)) return false;
+ Region rgn = (Region)object;
+ return handle == rgn.handle;
+}
+
+/**
+ * Returns a rectangle which represents the rectangular
+ * union of the collection of polygons the receiver
+ * maintains to describe its area.
+ *
+ * @return a bounding rectangle for the region
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Rectangle#union
+ */
+public Rectangle getBounds() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ RECT rect = new RECT();
+ OS.GetRgnBox(handle, rect);
+ return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+}
+
+/**
+ * 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
+ *
+ * @see #equals
+ */
+public int hashCode () {
+ return (int)/*64*/handle;
+}
+
+/**
+ * Intersects the given rectangle to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param rect the rectangle to intersect with the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void intersect (Rectangle rect) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ intersect (rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * Intersects the given rectangle to the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param x the x coordinate of the rectangle
+ * @param y the y coordinate of the rectangle
+ * @param width the width coordinate of the rectangle
+ * @param height the height coordinate of the rectangle
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void intersect (int x, int y, int width, int height) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ int /*long*/ rectRgn = OS.CreateRectRgn (x, y, x + width, y + height);
+ OS.CombineRgn (handle, handle, rectRgn, OS.RGN_AND);
+ OS.DeleteObject (rectRgn);
+}
+
+/**
+ * Intersects all of the polygons which make up the area covered
+ * by the argument to the collection of polygons the receiver
+ * maintains to describe its area.
+ *
+ * @param region the region to intersect
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void intersect (Region region) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ OS.CombineRgn (handle, handle, region.handle, OS.RGN_AND);
+}
+
+/**
+ * Returns <code>true</code> if the rectangle described by the
+ * arguments intersects with any of the polygons the receiver
+ * maintains to describe its area, and <code>false</code> otherwise.
+ *
+ * @param x the x coordinate of the origin of the rectangle
+ * @param y the y coordinate of the origin of the rectangle
+ * @param width the width of the rectangle
+ * @param height the height of the rectangle
+ * @return <code>true</code> if the rectangle intersects with the receiver, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Rectangle#intersects(Rectangle)
+ */
+public boolean intersects (int x, int y, int width, int height) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ RECT r = new RECT ();
+ OS.SetRect (r, x, y, x + width, y + height);
+ return OS.RectInRegion (handle, r);
+}
+
+/**
+ * Returns <code>true</code> if the given rectangle intersects
+ * with any of the polygons the receiver maintains to describe
+ * its area and <code>false</code> otherwise.
+ *
+ * @param rect the rectangle to test for intersection
+ * @return <code>true</code> if the rectangle intersects with the receiver, and <code>false</code> otherwise
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see Rectangle#intersects(Rectangle)
+ */
+public boolean intersects (Rectangle rect) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ return intersects(rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * Returns <code>true</code> if the region has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the region.
+ * When a region has been disposed, it is an error to
+ * invoke any other method using the region.
+ *
+ * @return <code>true</code> when the region is disposed, and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Returns <code>true</code> if the receiver does not cover any
+ * area in the (x, y) coordinate plane, and <code>false</code> if
+ * the receiver does cover some area in the plane.
+ *
+ * @return <code>true</code> if the receiver is empty, and <code>false</code> otherwise
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public boolean isEmpty () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ RECT rect = new RECT ();
+ int result = OS.GetRgnBox (handle, rect);
+ if (result == OS.NULLREGION) return true;
+ return ((rect.right - rect.left) <= 0) || ((rect.bottom - rect.top) <= 0);
+}
+
+/**
+ * Subtracts the given polygon from the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param pointArray points that describe the polygon to merge with the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void subtract (int[] pointArray) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
+ int /*long*/ polyRgn = OS.CreatePolygonRgn(pointArray, pointArray.length / 2, OS.ALTERNATE);
+ OS.CombineRgn (handle, handle, polyRgn, OS.RGN_DIFF);
+ OS.DeleteObject (polyRgn);
+}
+
+/**
+ * Subtracts the given rectangle from the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param rect the rectangle to subtract from the receiver
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void subtract (Rectangle rect) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ subtract (rect.x, rect.y, rect.width, rect.height);
+}
+
+/**
+ * Subtracts the given rectangle from the collection of polygons
+ * the receiver maintains to describe its area.
+ *
+ * @param x the x coordinate of the rectangle
+ * @param y the y coordinate of the rectangle
+ * @param width the width coordinate of the rectangle
+ * @param height the height coordinate of the rectangle
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the rectangle's width or height is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void subtract (int x, int y, int width, int height) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ int /*long*/ rectRgn = OS.CreateRectRgn (x, y, x + width, y + height);
+ OS.CombineRgn (handle, handle, rectRgn, OS.RGN_DIFF);
+ OS.DeleteObject (rectRgn);
+}
+
+/**
+ * Subtracts all of the polygons which make up the area covered
+ * by the argument from the collection of polygons the receiver
+ * maintains to describe its area.
+ *
+ * @param region the region to subtract
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the argument has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.0
+ */
+public void subtract (Region region) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ OS.CombineRgn (handle, handle, region.handle, OS.RGN_DIFF);
+}
+
+/**
+ * Translate all of the polygons the receiver maintains to describe
+ * its area by the specified point.
+ *
+ * @param x the x coordinate of the point to translate
+ * @param y the y coordinate of the point to translate
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void translate (int x, int y) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ OS.OffsetRgn (handle, x, y);
+}
+
+/**
+ * Translate all of the polygons the receiver maintains to describe
+ * its area by the specified point.
+ *
+ * @param pt the point to translate
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the argument is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.1
+ */
+public void translate (Point pt) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ translate (pt.x, pt.y);
+}
+
+/**
+ * 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 "Region {*DISPOSED*}";
+ return "Region {" + handle + "}";
+}
+
+/**
+ * Invokes platform specific functionality to allocate a new region.
+ * <p>
+ * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
+ * API for <code>Region</code>. It is marked public only so that it
+ * can be shared within the packages provided by SWT. It is not
+ * available on all platforms, and should never be called from
+ * application code.
+ * </p>
+ *
+ * @param device the device on which to allocate the region
+ * @param handle the handle for the region
+ * @return a new region object containing the specified device and handle
+ */
+public static Region win32_new(Device device, int handle) {
+ return new Region(device, handle);
+}
+
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java
new file mode 100644
index 0000000000..d4701a120f
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/TextLayout.java
@@ -0,0 +1,3328 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2009 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.internal.*;
+import org.eclipse.swt.internal.gdip.*;
+import org.eclipse.swt.internal.win32.*;
+import org.eclipse.swt.*;
+
+/**
+ * <code>TextLayout</code> is a graphic object that represents
+ * styled text.
+ * <p>
+ * Instances of this class provide support for drawing, cursor
+ * navigation, hit testing, text wrapping, alignment, tab expansion
+ * line breaking, etc. These are aspects required for rendering internationalized text.
+ * </p><p>
+ * Application code must explicitly invoke the <code>TextLayout#dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#textlayout">TextLayout, TextStyle snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: CustomControlExample, StyledText tab</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.0
+ */
+public final class TextLayout extends Resource {
+ Font font;
+ String text, segmentsText;
+ int lineSpacing;
+ int ascent, descent;
+ int alignment;
+ int wrapWidth;
+ int orientation;
+ int indent;
+ boolean justify;
+ int[] tabs;
+ int[] segments;
+ StyleItem[] styles;
+ int stylesCount;
+
+ StyleItem[] allRuns;
+ StyleItem[][] runs;
+ int[] lineOffset, lineY, lineWidth;
+ int /*long*/ mLangFontLink2;
+
+ static final char LTR_MARK = '\u200E', RTL_MARK = '\u200F';
+ static final int SCRIPT_VISATTR_SIZEOF = 2;
+ static final int GOFFSET_SIZEOF = 8;
+ static final byte[] CLSID_CMultiLanguage = new byte[16];
+ static final byte[] IID_IMLangFontLink2 = new byte[16];
+ static {
+ OS.IIDFromString("{275c23e2-3747-11d0-9fea-00aa003f8646}\0".toCharArray(), CLSID_CMultiLanguage);
+ OS.IIDFromString("{DCCFC162-2B38-11d2-B7EC-00C04F8F5D9A}\0".toCharArray(), IID_IMLangFontLink2);
+ }
+
+ static final int MERGE_MAX = 512;
+ static final int TOO_MANY_RUNS = 1024;
+
+ /* IME has a copy of these constants */
+ static final int UNDERLINE_IME_DOT = 1 << 16;
+ static final int UNDERLINE_IME_DASH = 2 << 16;
+ static final int UNDERLINE_IME_THICK = 3 << 16;
+
+ class StyleItem {
+ TextStyle style;
+ int start, length;
+ boolean lineBreak, softBreak, tab;
+
+ /*Script cache and analysis */
+ SCRIPT_ANALYSIS analysis;
+ int /*long*/ psc = 0;
+
+ /*Shape info (malloc when the run is shaped) */
+ int /*long*/ glyphs;
+ int glyphCount;
+ int /*long*/ clusters;
+ int /*long*/ visAttrs;
+
+ /*Place info (malloc when the run is placed) */
+ int /*long*/ advances;
+ int /*long*/ goffsets;
+ int width;
+ int ascent;
+ int descent;
+ int leading;
+ int x;
+ int underlinePos, underlineThickness;
+ int strikeoutPos, strikeoutThickness;
+
+ /* Justify info (malloc during computeRuns) */
+ int /*long*/ justify;
+
+ /* ScriptBreak */
+ int /*long*/ psla;
+
+ int /*long*/ fallbackFont;
+
+ void free() {
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ if (psc != 0) {
+ OS.ScriptFreeCache (psc);
+ OS.HeapFree(hHeap, 0, psc);
+ psc = 0;
+ }
+ if (glyphs != 0) {
+ OS.HeapFree(hHeap, 0, glyphs);
+ glyphs = 0;
+ glyphCount = 0;
+ }
+ if (clusters != 0) {
+ OS.HeapFree(hHeap, 0, clusters);
+ clusters = 0;
+ }
+ if (visAttrs != 0) {
+ OS.HeapFree(hHeap, 0, visAttrs);
+ visAttrs = 0;
+ }
+ if (advances != 0) {
+ OS.HeapFree(hHeap, 0, advances);
+ advances = 0;
+ }
+ if (goffsets != 0) {
+ OS.HeapFree(hHeap, 0, goffsets);
+ goffsets = 0;
+ }
+ if (justify != 0) {
+ OS.HeapFree(hHeap, 0, justify);
+ justify = 0;
+ }
+ if (psla != 0) {
+ OS.HeapFree(hHeap, 0, psla);
+ psla = 0;
+ }
+ if (fallbackFont != 0) {
+ OS.DeleteObject(fallbackFont);
+ fallbackFont = 0;
+ }
+ width = ascent = descent = x = 0;
+ lineBreak = softBreak = false;
+ }
+ public String toString () {
+ return "StyleItem {" + start + ", " + style + "}";
+ }
+ }
+
+/**
+ * Constructs a new instance of this class on the given device.
+ * <p>
+ * You must dispose the text layout when it is no longer required.
+ * </p>
+ *
+ * @param device the device on which to allocate the text layout
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public TextLayout (Device device) {
+ super(device);
+ wrapWidth = ascent = descent = -1;
+ lineSpacing = 0;
+ orientation = SWT.LEFT_TO_RIGHT;
+ styles = new StyleItem[2];
+ styles[0] = new StyleItem();
+ styles[1] = new StyleItem();
+ stylesCount = 2;
+ text = ""; //$NON-NLS-1$
+ int /*long*/[] ppv = new int /*long*/[1];
+ OS.OleInitialize(0);
+ if (OS.CoCreateInstance(CLSID_CMultiLanguage, 0, OS.CLSCTX_INPROC_SERVER, IID_IMLangFontLink2, ppv) == OS.S_OK) {
+ mLangFontLink2 = ppv[0];
+ }
+ init();
+}
+
+RECT addClipRect(StyleItem run, RECT clipRect, RECT rect, int selectionStart, int selectionEnd) {
+ if (rect != null) {
+ if (clipRect == null) {
+ clipRect = new RECT ();
+ OS.SetRect(clipRect, -1, rect.top, -1, rect.bottom);
+ }
+ boolean isRTL = (orientation & SWT.RIGHT_TO_LEFT) != 0;
+ if (run.start <= selectionStart && selectionStart <= run.start + run.length) {
+ if (run.analysis.fRTL ^ isRTL) {
+ clipRect.right = rect.left;
+ } else {
+ clipRect.left = rect.left;
+ }
+ }
+ if (run.start <= selectionEnd && selectionEnd <= run.start + run.length) {
+ if (run.analysis.fRTL ^ isRTL) {
+ clipRect.left = rect.right;
+ } else {
+ clipRect.right = rect.right;
+ }
+ }
+ }
+ return clipRect;
+}
+
+void breakRun(StyleItem run) {
+ if (run.psla != 0) return;
+ char[] chars = new char[run.length];
+ segmentsText.getChars(run.start, run.start + run.length, chars, 0);
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ run.psla = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, SCRIPT_LOGATTR.sizeof * chars.length);
+ if (run.psla == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.ScriptBreak(chars, chars.length, run.analysis, run.psla);
+}
+
+void checkLayout () {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+}
+
+/*
+* Compute the runs: itemize, shape, place, and reorder the runs.
+* Break paragraphs into lines, wraps the text, and initialize caches.
+*/
+void computeRuns (GC gc) {
+ if (runs != null) return;
+ int /*long*/ hDC = gc != null ? gc.handle : device.internal_new_GC(null);
+ int /*long*/ srcHdc = OS.CreateCompatibleDC(hDC);
+ allRuns = itemize();
+ for (int i=0; i<allRuns.length - 1; i++) {
+ StyleItem run = allRuns[i];
+ OS.SelectObject(srcHdc, getItemFont(run));
+ shape(srcHdc, run);
+ }
+ SCRIPT_LOGATTR logAttr = new SCRIPT_LOGATTR();
+ SCRIPT_PROPERTIES properties = new SCRIPT_PROPERTIES();
+ int lineWidth = indent, lineStart = 0, lineCount = 1;
+ for (int i=0; i<allRuns.length - 1; i++) {
+ StyleItem run = allRuns[i];
+ if (tabs != null && run.tab) {
+ int tabsLength = tabs.length, j;
+ for (j = 0; j < tabsLength; j++) {
+ if (tabs[j] > lineWidth) {
+ run.width = tabs[j] - lineWidth;
+ break;
+ }
+ }
+ if (j == tabsLength) {
+ int tabX = tabs[tabsLength-1];
+ int lastTabWidth = tabsLength > 1 ? tabs[tabsLength-1] - tabs[tabsLength-2] : tabs[0];
+ if (lastTabWidth > 0) {
+ while (tabX <= lineWidth) tabX += lastTabWidth;
+ run.width = tabX - lineWidth;
+ }
+ }
+ int length = run.length;
+ if (length > 1) {
+ int stop = j + length - 1;
+ if (stop < tabsLength) {
+ run.width += tabs[stop] - tabs[j];
+ } else {
+ if (j < tabsLength) {
+ run.width += tabs[tabsLength - 1] - tabs[j];
+ length -= (tabsLength - 1) - j;
+ }
+ int lastTabWidth = tabsLength > 1 ? tabs[tabsLength-1] - tabs[tabsLength-2] : tabs[0];
+ run.width += lastTabWidth * (length - 1);
+ }
+ }
+ }
+ if (wrapWidth != -1 && lineWidth + run.width > wrapWidth && !run.tab) {
+ int start = 0;
+ int[] piDx = new int[run.length];
+ if (run.style != null && run.style.metrics != null) {
+ piDx[0] = run.width;
+ } else {
+ OS.ScriptGetLogicalWidths(run.analysis, run.length, run.glyphCount, run.advances, run.clusters, run.visAttrs, piDx);
+ }
+ int width = 0, maxWidth = wrapWidth - lineWidth;
+ while (width + piDx[start] < maxWidth) {
+ width += piDx[start++];
+ }
+ int firstStart = start;
+ int firstIndice = i;
+ while (i >= lineStart) {
+ breakRun(run);
+ while (start >= 0) {
+ OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof);
+ if (logAttr.fSoftBreak || logAttr.fWhiteSpace) break;
+ start--;
+ }
+
+ /*
+ * Bug in Windows. For some reason Uniscribe sets the fSoftBreak flag for the first letter
+ * after a letter with an accent. This cause a break line to be set in the middle of a word.
+ * The fix is to detect the case and ignore fSoftBreak forcing the algorithm keep searching.
+ */
+ if (start == 0 && i != lineStart && !run.tab) {
+ if (logAttr.fSoftBreak && !logAttr.fWhiteSpace) {
+ OS.MoveMemory(properties, device.scripts[run.analysis.eScript], SCRIPT_PROPERTIES.sizeof);
+ int langID = properties.langid;
+ StyleItem pRun = allRuns[i - 1];
+ OS.MoveMemory(properties, device.scripts[pRun.analysis.eScript], SCRIPT_PROPERTIES.sizeof);
+ if (properties.langid == langID || langID == OS.LANG_NEUTRAL || properties.langid == OS.LANG_NEUTRAL) {
+ breakRun(pRun);
+ OS.MoveMemory(logAttr, pRun.psla + ((pRun.length - 1) * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof);
+ if (!logAttr.fWhiteSpace) start = -1;
+ }
+ }
+ }
+ if (start >= 0 || i == lineStart) break;
+ run = allRuns[--i];
+ start = run.length - 1;
+ }
+ if (start == 0 && i != lineStart && !run.tab) {
+ run = allRuns[--i];
+ } else if (start <= 0 && i == lineStart) {
+ if (lineWidth == wrapWidth && firstIndice > 0) {
+ i = firstIndice - 1;
+ run = allRuns[i];
+ start = run.length;
+ } else {
+ i = firstIndice;
+ run = allRuns[i];
+ start = Math.max(1, firstStart);
+ }
+ }
+ breakRun(run);
+ while (start < run.length) {
+ OS.MoveMemory(logAttr, run.psla + (start * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof);
+ if (!logAttr.fWhiteSpace) break;
+ start++;
+ }
+ if (0 < start && start < run.length) {
+ StyleItem newRun = new StyleItem();
+ newRun.start = run.start + start;
+ newRun.length = run.length - start;
+ newRun.style = run.style;
+ newRun.analysis = cloneScriptAnalysis(run.analysis);
+ run.free();
+ run.length = start;
+ OS.SelectObject(srcHdc, getItemFont(run));
+ run.analysis.fNoGlyphIndex = false;
+ shape (srcHdc, run);
+ OS.SelectObject(srcHdc, getItemFont(newRun));
+ newRun.analysis.fNoGlyphIndex = false;
+ shape (srcHdc, newRun);
+ StyleItem[] newAllRuns = new StyleItem[allRuns.length + 1];
+ System.arraycopy(allRuns, 0, newAllRuns, 0, i + 1);
+ System.arraycopy(allRuns, i + 1, newAllRuns, i + 2, allRuns.length - i - 1);
+ allRuns = newAllRuns;
+ allRuns[i + 1] = newRun;
+ }
+ if (i != allRuns.length - 2) {
+ run.softBreak = run.lineBreak = true;
+ }
+ }
+ lineWidth += run.width;
+ if (run.lineBreak) {
+ lineStart = i + 1;
+ lineWidth = run.softBreak ? 0 : indent;
+ lineCount++;
+ }
+ }
+ lineWidth = 0;
+ runs = new StyleItem[lineCount][];
+ lineOffset = new int[lineCount + 1];
+ lineY = new int[lineCount + 1];
+ this.lineWidth = new int[lineCount];
+ int lineRunCount = 0, line = 0;
+ int ascent = Math.max(0, this.ascent);
+ int descent = Math.max(0, this.descent);
+ StyleItem[] lineRuns = new StyleItem[allRuns.length];
+ for (int i=0; i<allRuns.length; i++) {
+ StyleItem run = allRuns[i];
+ lineRuns[lineRunCount++] = run;
+ lineWidth += run.width;
+ ascent = Math.max(ascent, run.ascent);
+ descent = Math.max(descent, run.descent);
+ if (run.lineBreak || i == allRuns.length - 1) {
+ /* Update the run metrics if the last run is a hard break. */
+ if (lineRunCount == 1 && (i == allRuns.length - 1 || !run.softBreak)) {
+ TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
+ OS.SelectObject(srcHdc, getItemFont(run));
+ OS.GetTextMetrics(srcHdc, lptm);
+ run.ascent = lptm.tmAscent;
+ run.descent = lptm.tmDescent;
+ ascent = Math.max(ascent, run.ascent);
+ descent = Math.max(descent, run.descent);
+ }
+ runs[line] = new StyleItem[lineRunCount];
+ System.arraycopy(lineRuns, 0, runs[line], 0, lineRunCount);
+
+ if (justify && wrapWidth != -1 && run.softBreak && lineWidth > 0) {
+ if (line == 0) {
+ lineWidth += indent;
+ } else {
+ StyleItem[] previousLine = runs[line - 1];
+ StyleItem previousRun = previousLine[previousLine.length - 1];
+ if (previousRun.lineBreak && !previousRun.softBreak) {
+ lineWidth += indent;
+ }
+ }
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ int newLineWidth = 0;
+ for (int j = 0; j < runs[line].length; j++) {
+ StyleItem item = runs[line][j];
+ int iDx = item.width * wrapWidth / lineWidth;
+ if (iDx != item.width) {
+ item.justify = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, item.glyphCount * 4);
+ if (item.justify == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.ScriptJustify(item.visAttrs, item.advances, item.glyphCount, iDx - item.width, 2, item.justify);
+ item.width = iDx;
+ }
+ newLineWidth += item.width;
+ }
+ lineWidth = newLineWidth;
+ }
+ this.lineWidth[line] = lineWidth;
+
+ StyleItem lastRun = runs[line][lineRunCount - 1];
+ int lastOffset = lastRun.start + lastRun.length;
+ runs[line] = reorder(runs[line], i == allRuns.length - 1);
+ lastRun = runs[line][lineRunCount - 1];
+ if (run.softBreak && run != lastRun) {
+ run.softBreak = run.lineBreak = false;
+ lastRun.softBreak = lastRun.lineBreak = true;
+ }
+
+ lineWidth = getLineIndent(line);
+ for (int j = 0; j < runs[line].length; j++) {
+ runs[line][j].x = lineWidth;
+ lineWidth += runs[line][j].width;
+ }
+ line++;
+ lineY[line] = lineY[line - 1] + ascent + descent + lineSpacing;
+ lineOffset[line] = lastOffset;
+ lineRunCount = lineWidth = 0;
+ ascent = Math.max(0, this.ascent);
+ descent = Math.max(0, this.descent);
+ }
+ }
+ if (srcHdc != 0) OS.DeleteDC(srcHdc);
+ if (gc == null) device.internal_dispose_GC(hDC, null);
+}
+
+void destroy () {
+ freeRuns();
+ font = null;
+ text = null;
+ segmentsText = null;
+ tabs = null;
+ styles = null;
+ runs = null;
+ lineOffset = null;
+ lineY = null;
+ lineWidth = null;
+ if (mLangFontLink2 != 0) {
+ /* Release() */
+ OS.VtblCall(2, mLangFontLink2);
+ mLangFontLink2 = 0;
+ }
+ OS.OleUninitialize();
+}
+
+SCRIPT_ANALYSIS cloneScriptAnalysis (SCRIPT_ANALYSIS src) {
+ SCRIPT_ANALYSIS dst = new SCRIPT_ANALYSIS();
+ dst.eScript = src.eScript;
+ dst.fRTL = src.fRTL;
+ dst.fLayoutRTL = src.fLayoutRTL;
+ dst.fLinkBefore = src.fLinkBefore;
+ dst.fLinkAfter = src.fLinkAfter;
+ dst.fLogicalOrder = src.fLogicalOrder;
+ dst.fNoGlyphIndex = src.fNoGlyphIndex;
+ dst.s = new SCRIPT_STATE();
+ dst.s.uBidiLevel = src.s.uBidiLevel;
+ dst.s.fOverrideDirection = src.s.fOverrideDirection;
+ dst.s.fInhibitSymSwap = src.s.fInhibitSymSwap;
+ dst.s.fCharShape = src.s.fCharShape;
+ dst.s.fDigitSubstitute = src.s.fDigitSubstitute;
+ dst.s.fInhibitLigate = src.s.fInhibitLigate;
+ dst.s.fDisplayZWG = src.s.fDisplayZWG;
+ dst.s.fArabicNumContext = src.s.fArabicNumContext;
+ dst.s.fGcpClusters = src.s.fGcpClusters;
+ dst.s.fReserved = src.s.fReserved;
+ dst.s.fEngineReserved = src.s.fEngineReserved;
+ return dst;
+}
+
+int[] computePolyline(int left, int top, int right, int bottom) {
+ int height = bottom - top; // can be any number
+ int width = 2 * height; // must be even
+ int peaks = Compatibility.ceil(right - left, width);
+ if (peaks == 0 && right - left > 2) {
+ peaks = 1;
+ }
+ int length = ((2 * peaks) + 1) * 2;
+ if (length < 0) return new int[0];
+
+ int[] coordinates = new int[length];
+ for (int i = 0; i < peaks; i++) {
+ int index = 4 * i;
+ coordinates[index] = left + (width * i);
+ coordinates[index+1] = bottom;
+ coordinates[index+2] = coordinates[index] + width / 2;
+ coordinates[index+3] = top;
+ }
+ coordinates[length-2] = left + (width * peaks);
+ coordinates[length-1] = bottom;
+ return coordinates;
+}
+
+int /*long*/ createGdipBrush(int pixel, int alpha) {
+ int argb = ((alpha & 0xFF) << 24) | ((pixel >> 16) & 0xFF) | (pixel & 0xFF00) | ((pixel & 0xFF) << 16);
+ int /*long*/ gdiColor = Gdip.Color_new(argb);
+ int /*long*/ brush = Gdip.SolidBrush_new(gdiColor);
+ Gdip.Color_delete(gdiColor);
+ return brush;
+}
+
+int /*long*/ createGdipBrush(Color color, int alpha) {
+ return createGdipBrush(color.handle, alpha);
+}
+
+/**
+ * Draws the receiver's text using the specified GC at the specified
+ * point.
+ *
+ * @param gc the GC to draw
+ * @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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
+ * </ul>
+ */
+public void draw (GC gc, int x, int y) {
+ draw(gc, x, y, -1, -1, null, null);
+}
+
+/**
+ * Draws the receiver's text using the specified GC at the specified
+ * point.
+ *
+ * @param gc the GC to draw
+ * @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 selectionStart the offset where the selections starts, or -1 indicating no selection
+ * @param selectionEnd the offset where the selections ends, or -1 indicating no selection
+ * @param selectionForeground selection foreground, or NULL to use the system default color
+ * @param selectionBackground selection background, or NULL to use the system default color
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
+ * </ul>
+ */
+public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground) {
+ draw(gc, x, y, selectionStart, selectionEnd, selectionForeground, selectionBackground, 0);
+}
+
+/**
+ * Draws the receiver's text using the specified GC at the specified
+ * point.
+ * <p>
+ * The parameter <code>flags</code> can include one of <code>SWT.DELIMITER_SELECTION</code>
+ * or <code>SWT.FULL_SELECTION</code> to specify the selection behavior on all lines except
+ * for the last line, and can also include <code>SWT.LAST_LINE_SELECTION</code> to extend
+ * the specified selection behavior to the last line.
+ * </p>
+ * @param gc the GC to draw
+ * @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 selectionStart the offset where the selections starts, or -1 indicating no selection
+ * @param selectionEnd the offset where the selections ends, or -1 indicating no selection
+ * @param selectionForeground selection foreground, or NULL to use the system default color
+ * @param selectionBackground selection background, or NULL to use the system default color
+ * @param flags drawing options
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the gc is null</li>
+ * </ul>
+ *
+ * @since 3.3
+ */
+public void draw (GC gc, int x, int y, int selectionStart, int selectionEnd, Color selectionForeground, Color selectionBackground, int flags) {
+ checkLayout();
+ computeRuns(gc);
+ if (gc == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (gc.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (selectionForeground != null && selectionForeground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (selectionBackground != null && selectionBackground.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ int length = text.length();
+ if (length == 0 && flags == 0) return;
+ int /*long*/ hdc = gc.handle;
+ Rectangle clip = gc.getClipping();
+ GCData data = gc.data;
+ int /*long*/ gdipGraphics = data.gdipGraphics;
+ int foreground = data.foreground;
+ int linkColor = OS.GetSysColor (OS.COLOR_HOTLIGHT);
+ int alpha = data.alpha;
+ boolean gdip = gdipGraphics != 0;
+ int /*long*/ gdipForeground = 0;
+ int /*long*/ gdipLinkColor = 0;
+ int state = 0;
+ if (gdip) {
+ gc.checkGC(GC.FOREGROUND);
+ gdipForeground = gc.getFgBrush();
+ } else {
+ state = OS.SaveDC(hdc);
+ if ((data.style & SWT.MIRRORED) != 0) {
+ OS.SetLayout(hdc, OS.GetLayout(hdc) | OS.LAYOUT_RTL);
+ }
+ }
+ boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
+ int /*long*/ gdipSelBackground = 0, gdipSelForeground = 0, gdipFont = 0, lastHFont = 0;
+ int /*long*/ selBackground = 0;
+ int selForeground = 0;
+ if (hasSelection || (flags & SWT.LAST_LINE_SELECTION) != 0) {
+ int fgSel = selectionForeground != null ? selectionForeground.handle : OS.GetSysColor (OS.COLOR_HIGHLIGHTTEXT);
+ int bgSel = selectionBackground != null ? selectionBackground.handle : OS.GetSysColor (OS.COLOR_HIGHLIGHT);
+ if (gdip) {
+ gdipSelBackground = createGdipBrush(bgSel, alpha);
+ gdipSelForeground = createGdipBrush(fgSel, alpha);
+ } else {
+ selBackground = OS.CreateSolidBrush(bgSel);
+ selForeground = fgSel;
+ }
+ if (hasSelection) {
+ selectionStart = translateOffset(Math.min(Math.max(0, selectionStart), length - 1));
+ selectionEnd = translateOffset(Math.min(Math.max(0, selectionEnd), length - 1));
+ }
+ }
+ RECT rect = new RECT();
+ OS.SetBkMode(hdc, OS.TRANSPARENT);
+ for (int line=0; line<runs.length; line++) {
+ int drawX = x + getLineIndent(line);
+ int drawY = y + lineY[line];
+ StyleItem[] lineRuns = runs[line];
+ int lineHeight = lineY[line+1] - lineY[line] - lineSpacing;
+
+ //Draw last line selection
+ if (flags != 0 && (hasSelection || (flags & SWT.LAST_LINE_SELECTION) != 0)) {
+ boolean extents = false;
+ if (line == runs.length - 1 && (flags & SWT.LAST_LINE_SELECTION) != 0) {
+ extents = true;
+ } else {
+ StyleItem run = lineRuns[lineRuns.length - 1];
+ if (run.lineBreak && !run.softBreak) {
+ if (selectionStart <= run.start && run.start <= selectionEnd) extents = true;
+ } else {
+ int endOffset = run.start + run.length - 1;
+ if (selectionStart <= endOffset && endOffset < selectionEnd && (flags & SWT.FULL_SELECTION) != 0) {
+ extents = true;
+ }
+ }
+ }
+ if (extents) {
+ int width;
+ if ((flags & SWT.FULL_SELECTION) != 0) {
+ width = OS.IsWin95 ? 0x7FFF : 0x6FFFFFF;
+ } else {
+ width = lineHeight / 3;
+ }
+ if (gdip) {
+ Gdip.Graphics_FillRectangle(gdipGraphics, gdipSelBackground, drawX + lineWidth[line], drawY, width, lineHeight);
+ } else {
+ OS.SelectObject(hdc, selBackground);
+ OS.PatBlt(hdc, drawX + lineWidth[line], drawY, width, lineHeight, OS.PATCOPY);
+ }
+ }
+ }
+ if (drawX > clip.x + clip.width) continue;
+ if (drawX + lineWidth[line] < clip.x) continue;
+
+ //Draw the background of the runs in the line
+ int alignmentX = drawX;
+ for (int i = 0; i < lineRuns.length; i++) {
+ StyleItem run = lineRuns[i];
+ if (run.length == 0) continue;
+ if (drawX > clip.x + clip.width) break;
+ if (drawX + run.width >= clip.x) {
+ if (!run.lineBreak || run.softBreak) {
+ OS.SetRect(rect, drawX, drawY, drawX + run.width, drawY + lineHeight);
+ if (gdip) {
+ drawRunBackgroundGDIP(run, gdipGraphics, rect, selectionStart, selectionEnd, alpha, gdipSelBackground, hasSelection);
+ } else {
+ drawRunBackground(run, hdc, rect, selectionStart, selectionEnd, selBackground, hasSelection);
+ }
+ }
+ }
+ drawX += run.width;
+ }
+
+ //Draw the text, underline, strikeout, and border of the runs in the line
+ int baseline = Math.max(0, this.ascent);
+ int lineUnderlinePos = 0;
+ for (int i = 0; i < lineRuns.length; i++) {
+ baseline = Math.max(baseline, lineRuns[i].ascent);
+ lineUnderlinePos = Math.min(lineUnderlinePos, lineRuns[i].underlinePos);
+ }
+ RECT borderClip = null, underlineClip = null, strikeoutClip = null, pRect = null;
+ drawX = alignmentX;
+ for (int i = 0; i < lineRuns.length; i++) {
+ StyleItem run = lineRuns[i];
+ TextStyle style = run.style;
+ boolean hasAdorners = style != null && (style.underline || style.strikeout || style.borderStyle != SWT.NONE);
+ if (run.length == 0) continue;
+ if (drawX > clip.x + clip.width && !hasAdorners) break;
+ if (drawX + run.width >= clip.x || hasAdorners) {
+ boolean skipTab = run.tab && !hasAdorners;
+ if (!skipTab && (!run.lineBreak || run.softBreak) && !(style != null && style.metrics != null)) {
+ OS.SetRect(rect, drawX, drawY, drawX + run.width, drawY + lineHeight);
+ if (gdip) {
+ int /*long*/ hFont = getItemFont(run);
+ if (hFont != lastHFont) {
+ lastHFont = hFont;
+ if (gdipFont != 0) Gdip.Font_delete(gdipFont);
+ gdipFont = Gdip.Font_new(hdc, hFont);
+ if (gdipFont == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ if (!Gdip.Font_IsAvailable(gdipFont)) {
+ Gdip.Font_delete(gdipFont);
+ gdipFont = 0;
+ }
+ }
+ int /*long*/ gdipFg = gdipForeground;
+ if (style != null && style.underline && style.underlineStyle == SWT.UNDERLINE_LINK) {
+ if (gdipLinkColor == 0) gdipLinkColor = createGdipBrush(linkColor, alpha);
+ gdipFg = gdipLinkColor;
+ }
+ if (gdipFont != 0) {
+ pRect = drawRunTextGDIP(gdipGraphics, run, rect, gdipFont, baseline, gdipFg, gdipSelForeground, selectionStart, selectionEnd, alpha);
+ } else {
+ int fg = style != null && style.underline && style.underlineStyle == SWT.UNDERLINE_LINK ? linkColor : foreground;
+ pRect = drawRunTextGDIPRaster(gdipGraphics, run, rect, baseline, fg, selForeground, selectionStart, selectionEnd);
+ }
+ underlineClip = drawUnderlineGDIP(gdipGraphics, x, drawY + baseline, lineUnderlinePos, drawY + lineHeight, lineRuns, i, gdipFg, gdipSelForeground, underlineClip, pRect, selectionStart, selectionEnd, alpha);
+ strikeoutClip = drawStrikeoutGDIP(gdipGraphics, x, drawY + baseline, lineRuns, i, gdipFg, gdipSelForeground, strikeoutClip, pRect, selectionStart, selectionEnd, alpha);
+ borderClip = drawBorderGDIP(gdipGraphics, x, drawY, lineHeight, lineRuns, i, gdipFg, gdipSelForeground, borderClip, pRect, selectionStart, selectionEnd, alpha);
+ } else {
+ int fg = style != null && style.underline && style.underlineStyle == SWT.UNDERLINE_LINK ? linkColor : foreground;
+ pRect = drawRunText(hdc, run, rect, baseline, fg, selForeground, selectionStart, selectionEnd);
+ underlineClip = drawUnderline(hdc, x, drawY + baseline, lineUnderlinePos, drawY + lineHeight, lineRuns, i, fg, selForeground, underlineClip, pRect, selectionStart, selectionEnd);
+ strikeoutClip = drawStrikeout(hdc, x, drawY + baseline, lineRuns, i, fg, selForeground, strikeoutClip, pRect, selectionStart, selectionEnd);
+ borderClip = drawBorder(hdc, x, drawY, lineHeight, lineRuns, i, fg, selForeground, borderClip, pRect, selectionStart, selectionEnd);
+ }
+ }
+ }
+ drawX += run.width;
+ }
+ }
+ if (gdipSelBackground != 0) Gdip.SolidBrush_delete(gdipSelBackground);
+ if (gdipSelForeground != 0) Gdip.SolidBrush_delete(gdipSelForeground);
+ if (gdipLinkColor != 0) Gdip.SolidBrush_delete(gdipLinkColor);
+ if (gdipFont != 0) Gdip.Font_delete(gdipFont);
+ if (state != 0) OS.RestoreDC(hdc, state);
+ if (selBackground != 0) OS.DeleteObject (selBackground);
+}
+
+RECT drawBorder(int /*long*/ hdc, int x, int y, int lineHeight, StyleItem[] line, int index, int color, int selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd) {
+ StyleItem run = line[index];
+ TextStyle style = run.style;
+ if (style == null) return null;
+ if (style.borderStyle == SWT.NONE) return null;
+ clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd);
+ if (index + 1 >= line.length || !style.isAdherentBorder(line[index + 1].style)) {
+ int left = run.x;
+ int start = run.start;
+ int end = run.start + run.length - 1;
+ for (int i = index; i > 0 && style.isAdherentBorder(line[i - 1].style); i--) {
+ left = line[i - 1].x;
+ start = Math.min(start, line[i - 1].start);
+ end = Math.max(end, line[i - 1].start + line[i - 1].length - 1);
+ }
+ boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
+ boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd;
+ if (style.borderColor != null) {
+ color = style.borderColor.handle;
+ clipRect = null;
+ } else {
+ if (fullSelection) {
+ color = selectionColor;
+ clipRect = null;
+ } else {
+ if (style.foreground != null) {
+ color = style.foreground.handle;
+ }
+ }
+ }
+ int lineWidth = 1;
+ int lineStyle = OS.PS_SOLID;
+ switch (style.borderStyle) {
+ case SWT.BORDER_SOLID: break;
+ case SWT.BORDER_DASH: lineStyle = OS.PS_DASH; break;
+ case SWT.BORDER_DOT: lineStyle = OS.PS_DOT; break;
+ }
+ int /*long*/ oldBrush = OS.SelectObject(hdc, OS.GetStockObject(OS.NULL_BRUSH));
+ LOGBRUSH logBrush = new LOGBRUSH();
+ logBrush.lbStyle = OS.BS_SOLID;
+ logBrush.lbColor = /*64*/(int)color;
+ int /*long*/ newPen = OS.ExtCreatePen(lineStyle | OS.PS_GEOMETRIC, Math.max(1, lineWidth), logBrush, 0, null);
+ int /*long*/ oldPen = OS.SelectObject(hdc, newPen);
+ OS.Rectangle(hdc, x + left, y, x + run.x + run.width, y + lineHeight);
+ OS.SelectObject(hdc, oldPen);
+ OS.DeleteObject(newPen);
+ if (clipRect != null) {
+ int state = OS.SaveDC(hdc);
+ if (clipRect.left == -1) clipRect.left = 0;
+ if (clipRect.right == -1) clipRect.right = 0x7ffff;
+ OS.IntersectClipRect(hdc, clipRect.left, clipRect.top, clipRect.right, clipRect.bottom);
+ logBrush.lbColor = /*64*/(int)selectionColor;
+ int /*long*/ selPen = OS.ExtCreatePen (lineStyle | OS.PS_GEOMETRIC, Math.max(1, lineWidth), logBrush, 0, null);
+ oldPen = OS.SelectObject(hdc, selPen);
+ OS.Rectangle(hdc, x + left, y, x + run.x + run.width, y + lineHeight);
+ OS.RestoreDC(hdc, state);
+ OS.SelectObject(hdc, oldPen);
+ OS.DeleteObject(selPen);
+ }
+ OS.SelectObject(hdc, oldBrush);
+ return null;
+ }
+ return clipRect;
+}
+
+RECT drawBorderGDIP(int /*long*/ graphics, int x, int y, int lineHeight, StyleItem[] line, int index, int /*long*/ color, int /*long*/ selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, int alpha) {
+ StyleItem run = line[index];
+ TextStyle style = run.style;
+ if (style == null) return null;
+ if (style.borderStyle == SWT.NONE) return null;
+ clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd);
+ if (index + 1 >= line.length || !style.isAdherentBorder(line[index + 1].style)) {
+ int left = run.x;
+ int start = run.start;
+ int end = run.start + run.length - 1;
+ for (int i = index; i > 0 && style.isAdherentBorder(line[i - 1].style); i--) {
+ left = line[i - 1].x;
+ start = Math.min(start, line[i - 1].start);
+ end = Math.max(end, line[i - 1].start + line[i - 1].length - 1);
+ }
+ boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
+ boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd;
+ int /*long*/ brush = color;
+ if (style.borderColor != null) {
+ brush = createGdipBrush(style.borderColor, alpha);
+ clipRect = null;
+ } else {
+ if (fullSelection) {
+ brush = selectionColor;
+ clipRect = null;
+ } else {
+ if (style.foreground != null) {
+ brush = createGdipBrush(style.foreground, alpha);
+ }
+ }
+ }
+ int lineWidth = 1;
+ int lineStyle = Gdip.DashStyleSolid;
+ switch (style.borderStyle) {
+ case SWT.BORDER_SOLID: break;
+ case SWT.BORDER_DASH: lineStyle = Gdip.DashStyleDash; break;
+ case SWT.BORDER_DOT: lineStyle = Gdip.DashStyleDot; break;
+ }
+ int /*long*/ pen = Gdip.Pen_new(brush, lineWidth);
+ Gdip.Pen_SetDashStyle(pen, lineStyle);
+ Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeNone);
+ if (clipRect != null) {
+ int gstate = Gdip.Graphics_Save(graphics);
+ if (clipRect.left == -1) clipRect.left = 0;
+ if (clipRect.right == -1) clipRect.right = 0x7ffff;
+ Rect gdipRect = new Rect();
+ gdipRect.X = clipRect.left;
+ gdipRect.Y = clipRect.top;
+ gdipRect.Width = clipRect.right - clipRect.left;
+ gdipRect.Height = clipRect.bottom - clipRect.top;
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude);
+ Gdip.Graphics_DrawRectangle(graphics, pen, x + left, y, run.x + run.width - left - 1, lineHeight - 1);
+ Gdip.Graphics_Restore(graphics, gstate);
+ gstate = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect);
+ int /*long*/ selPen = Gdip.Pen_new(selectionColor, lineWidth);
+ Gdip.Pen_SetDashStyle(selPen, lineStyle);
+ Gdip.Graphics_DrawRectangle(graphics, selPen, x + left, y, run.x + run.width - left - 1, lineHeight - 1);
+ Gdip.Pen_delete(selPen);
+ Gdip.Graphics_Restore(graphics, gstate);
+ } else {
+ Gdip.Graphics_DrawRectangle(graphics, pen, x + left, y, run.x + run.width - left - 1, lineHeight - 1);
+ }
+ Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeHalf);
+ Gdip.Pen_delete(pen);
+ if (brush != selectionColor && brush != color) Gdip.SolidBrush_delete(brush);
+ return null;
+ }
+ return clipRect;
+}
+
+void drawRunBackground(StyleItem run, int /*long*/ hdc, RECT rect, int selectionStart, int selectionEnd, int /*long*/ selBrush, boolean hasSelection) {
+ int end = run.start + run.length - 1;
+ boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end;
+ if (fullSelection) {
+ OS.SelectObject(hdc, selBrush);
+ OS.PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY);
+ } else {
+ if (run.style != null && run.style.background != null) {
+ int bg = run.style.background.handle;
+ int /*long*/ hBrush = OS.CreateSolidBrush (bg);
+ int /*long*/ oldBrush = OS.SelectObject(hdc, hBrush);
+ OS.PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY);
+ OS.SelectObject(hdc, oldBrush);
+ OS.DeleteObject(hBrush);
+ }
+ boolean partialSelection = hasSelection && !(selectionStart > end || run.start > selectionEnd);
+ if (partialSelection) {
+ getPartialSelection(run, selectionStart, selectionEnd, rect);
+ OS.SelectObject(hdc, selBrush);
+ OS.PatBlt(hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY);
+ }
+ }
+}
+
+void drawRunBackgroundGDIP(StyleItem run, int /*long*/ graphics, RECT rect, int selectionStart, int selectionEnd, int alpha, int /*long*/ selBrush, boolean hasSelection) {
+ int end = run.start + run.length - 1;
+ boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end;
+ if (fullSelection) {
+ Gdip.Graphics_FillRectangle(graphics, selBrush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+ } else {
+ if (run.style != null && run.style.background != null) {
+ int /*long*/ brush = createGdipBrush(run.style.background, alpha);
+ Gdip.Graphics_FillRectangle(graphics, brush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+ Gdip.SolidBrush_delete(brush);
+ }
+ boolean partialSelection = hasSelection && !(selectionStart > end || run.start > selectionEnd);
+ if (partialSelection) {
+ getPartialSelection(run, selectionStart, selectionEnd, rect);
+ if (rect.left > rect.right) {
+ int tmp = rect.left;
+ rect.left = rect.right;
+ rect.right = tmp;
+ }
+ Gdip.Graphics_FillRectangle(graphics, selBrush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+ }
+ }
+}
+
+RECT drawRunText(int /*long*/ hdc, StyleItem run, RECT rect, int baseline, int color, int selectionColor, int selectionStart, int selectionEnd) {
+ int end = run.start + run.length - 1;
+ boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
+ boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end;
+ boolean partialSelection = hasSelection && !fullSelection && !(selectionStart > end || run.start > selectionEnd);
+ int offset = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? -1 : 0;
+ int x = rect.left + offset;
+ int y = rect.top + (baseline - run.ascent);
+ int /*long*/ hFont = getItemFont(run);
+ OS.SelectObject(hdc, hFont);
+ if (fullSelection) {
+ color = selectionColor;
+ } else {
+ if (run.style != null && run.style.foreground != null) {
+ color = run.style.foreground.handle;
+ }
+ }
+ OS.SetTextColor(hdc, color);
+ OS.ScriptTextOut(hdc, run.psc, x, y, 0, null, run.analysis , 0, 0, run.glyphs, run.glyphCount, run.advances, run.justify, run.goffsets);
+ if (partialSelection) {
+ getPartialSelection(run, selectionStart, selectionEnd, rect);
+ OS.SetTextColor(hdc, selectionColor);
+ OS.ScriptTextOut(hdc, run.psc, x, y, OS.ETO_CLIPPED, rect, run.analysis , 0, 0, run.glyphs, run.glyphCount, run.advances, run.justify, run.goffsets);
+ }
+ return fullSelection || partialSelection ? rect : null;
+}
+
+RECT drawRunTextGDIP(int /*long*/ graphics, StyleItem run, RECT rect, int /*long*/ gdipFont, int baseline, int /*long*/ color, int /*long*/ selectionColor, int selectionStart, int selectionEnd, int alpha) {
+ int end = run.start + run.length - 1;
+ boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
+ boolean fullSelection = hasSelection && selectionStart <= run.start && selectionEnd >= end;
+ boolean partialSelection = hasSelection && !fullSelection && !(selectionStart > end || run.start > selectionEnd);
+ int drawY = rect.top + baseline;
+ int drawX = rect.left;
+ int /*long*/ brush = color;
+ if (fullSelection) {
+ brush = selectionColor;
+ } else {
+ if (run.style != null && run.style.foreground != null) {
+ brush = createGdipBrush(run.style.foreground, alpha);
+ }
+ }
+ int gstate = 0;
+ Rect gdipRect = null;
+ if (partialSelection) {
+ gdipRect = new Rect();
+ getPartialSelection(run, selectionStart, selectionEnd, rect);
+ gdipRect.X = rect.left;
+ gdipRect.Y = rect.top;
+ gdipRect.Width = rect.right - rect.left;
+ gdipRect.Height = rect.bottom - rect.top;
+ gstate = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude);
+ }
+ int gstateMirrored = 0;
+ boolean isMirrored = (orientation & SWT.RIGHT_TO_LEFT) != 0;
+ if (isMirrored) {
+ switch (Gdip.Brush_GetType(brush)) {
+ case Gdip.BrushTypeLinearGradient:
+ Gdip.LinearGradientBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.LinearGradientBrush_TranslateTransform(brush, -2 * drawX - run.width, 0, Gdip.MatrixOrderPrepend);
+ break;
+ case Gdip.BrushTypeTextureFill:
+ Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.TextureBrush_TranslateTransform(brush, -2 * drawX - run.width, 0, Gdip.MatrixOrderPrepend);
+ break;
+ }
+ gstateMirrored = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_ScaleTransform(graphics, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_TranslateTransform(graphics, -2 * drawX - run.width, 0, Gdip.MatrixOrderPrepend);
+ }
+ int[] advances = new int[run.glyphCount];
+ float[] points = new float[run.glyphCount * 2];
+ OS.memmove(advances, run.justify != 0 ? run.justify : run.advances, run.glyphCount * 4);
+ int glyphX = drawX;
+ for (int h = 0, j = 0; h < advances.length; h++) {
+ points[j++] = glyphX;
+ points[j++] = drawY;
+ glyphX += advances[h];
+ }
+ Gdip.Graphics_DrawDriverString(graphics, run.glyphs, run.glyphCount, gdipFont, brush, points, 0, 0);
+ if (partialSelection) {
+ if (isMirrored) {
+ Gdip.Graphics_Restore(graphics, gstateMirrored);
+ }
+ Gdip.Graphics_Restore(graphics, gstate);
+ gstate = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect);
+ if (isMirrored) {
+ gstateMirrored = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_ScaleTransform(graphics, -1, 1, Gdip.MatrixOrderPrepend);
+ Gdip.Graphics_TranslateTransform(graphics, -2 * drawX - run.width, 0, Gdip.MatrixOrderPrepend);
+ }
+ Gdip.Graphics_DrawDriverString(graphics, run.glyphs, run.glyphCount, gdipFont, selectionColor, points, 0, 0);
+ Gdip.Graphics_Restore(graphics, gstate);
+ }
+ if (isMirrored) {
+ switch (Gdip.Brush_GetType(brush)) {
+ case Gdip.BrushTypeLinearGradient:
+ Gdip.LinearGradientBrush_ResetTransform(brush);
+ break;
+ case Gdip.BrushTypeTextureFill:
+ Gdip.TextureBrush_ResetTransform(brush);
+ break;
+ }
+ Gdip.Graphics_Restore(graphics, gstateMirrored);
+ }
+ if (brush != selectionColor && brush != color) Gdip.SolidBrush_delete(brush);
+ return fullSelection || partialSelection ? rect : null;
+}
+
+RECT drawRunTextGDIPRaster(int /*long*/ graphics, StyleItem run, RECT rect, int baseline, int color, int selectionColor, int selectionStart, int selectionEnd) {
+ int /*long*/ clipRgn = 0;
+ Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeNone);
+ int /*long*/ rgn = Gdip.Region_new();
+ if (rgn == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.Graphics_GetClip(graphics, rgn);
+ if (!Gdip.Region_IsInfinite(rgn, graphics)) {
+ clipRgn = Gdip.Region_GetHRGN(rgn, graphics);
+ }
+ Gdip.Region_delete(rgn);
+ Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeHalf);
+ float[] lpXform = null;
+ int /*long*/ matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
+ if (matrix == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ Gdip.Graphics_GetTransform(graphics, matrix);
+ if (!Gdip.Matrix_IsIdentity(matrix)) {
+ lpXform = new float[6];
+ Gdip.Matrix_GetElements(matrix, lpXform);
+ }
+ Gdip.Matrix_delete(matrix);
+ int /*long*/ hdc = Gdip.Graphics_GetHDC(graphics);
+ int state = OS.SaveDC(hdc);
+ if (lpXform != null) {
+ OS.SetGraphicsMode(hdc, OS.GM_ADVANCED);
+ OS.SetWorldTransform(hdc, lpXform);
+ }
+ if (clipRgn != 0) {
+ OS.SelectClipRgn(hdc, clipRgn);
+ OS.DeleteObject(clipRgn);
+ }
+ if ((orientation & SWT.RIGHT_TO_LEFT) != 0) {
+ OS.SetLayout(hdc, OS.GetLayout(hdc) | OS.LAYOUT_RTL);
+ }
+ OS.SetBkMode(hdc, OS.TRANSPARENT);
+ RECT pRect = drawRunText(hdc, run, rect, baseline, color, selectionColor, selectionStart, selectionEnd);
+ OS.RestoreDC(hdc, state);
+ Gdip.Graphics_ReleaseHDC(graphics, hdc);
+ return pRect;
+}
+
+RECT drawStrikeout(int /*long*/ hdc, int x, int baseline, StyleItem[] line, int index, int color, int selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd) {
+ StyleItem run = line[index];
+ TextStyle style = run.style;
+ if (style == null) return null;
+ if (!style.strikeout) return null;
+ clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd);
+ if (index + 1 >= line.length || !style.isAdherentStrikeout(line[index + 1].style)) {
+ int left = run.x;
+ int start = run.start;
+ int end = run.start + run.length - 1;
+ for (int i = index; i > 0 && style.isAdherentStrikeout(line[i - 1].style); i--) {
+ left = line[i - 1].x;
+ start = Math.min(start, line[i - 1].start);
+ end = Math.max(end, line[i - 1].start + line[i - 1].length - 1);
+ }
+ boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
+ boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd;
+ if (style.strikeoutColor != null) {
+ color = style.strikeoutColor.handle;
+ clipRect = null;
+ } else {
+ if (fullSelection) {
+ color = selectionColor;
+ clipRect = null;
+ } else {
+ if (style.foreground != null) {
+ color = style.foreground.handle;
+ }
+ }
+ }
+ RECT rect = new RECT();
+ OS.SetRect(rect, x + left, baseline - run.strikeoutPos, x + run.x + run.width, baseline - run.strikeoutPos + run.strikeoutThickness);
+ int /*long*/ brush = OS.CreateSolidBrush(color);
+ OS.FillRect(hdc, rect, brush);
+ OS.DeleteObject(brush);
+ if (clipRect != null) {
+ int /*long*/ selBrush = OS.CreateSolidBrush(selectionColor);
+ if (clipRect.left == -1) clipRect.left = 0;
+ if (clipRect.right == -1) clipRect.right = 0x7ffff;
+ OS.SetRect(clipRect, Math.max(rect.left, clipRect.left), rect.top, Math.min(rect.right, clipRect.right), rect.bottom);
+ OS.FillRect(hdc, clipRect, selBrush);
+ OS.DeleteObject(selBrush);
+ }
+ return null;
+ }
+ return clipRect;
+}
+
+RECT drawStrikeoutGDIP(int /*long*/ graphics, int x, int baseline, StyleItem[] line, int index, int /*long*/ color, int /*long*/ selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, int alpha) {
+ StyleItem run = line[index];
+ TextStyle style = run.style;
+ if (style == null) return null;
+ if (!style.strikeout) return null;
+ clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd);
+ if (index + 1 >= line.length || !style.isAdherentStrikeout(line[index + 1].style)) {
+ int left = run.x;
+ int start = run.start;
+ int end = run.start + run.length - 1;
+ for (int i = index; i > 0 && style.isAdherentStrikeout(line[i - 1].style); i--) {
+ left = line[i - 1].x;
+ start = Math.min(start, line[i - 1].start);
+ end = Math.max(end, line[i - 1].start + line[i - 1].length - 1);
+ }
+ boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
+ boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd;
+ int /*long*/ brush = color;
+ if (style.strikeoutColor != null) {
+ brush = createGdipBrush(style.strikeoutColor, alpha);
+ clipRect = null;
+ } else {
+ if (fullSelection) {
+ color = selectionColor;
+ clipRect = null;
+ } else {
+ if (style.foreground != null) {
+ brush = createGdipBrush(style.foreground, alpha);
+ }
+ }
+ }
+ if (clipRect != null) {
+ int gstate = Gdip.Graphics_Save(graphics);
+ if (clipRect.left == -1) clipRect.left = 0;
+ if (clipRect.right == -1) clipRect.right = 0x7ffff;
+ Rect gdipRect = new Rect();
+ gdipRect.X = clipRect.left;
+ gdipRect.Y = clipRect.top;
+ gdipRect.Width = clipRect.right - clipRect.left;
+ gdipRect.Height = clipRect.bottom - clipRect.top;
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude);
+ Gdip.Graphics_FillRectangle(graphics, brush, x + left, baseline - run.strikeoutPos, run.x + run.width - left, run.strikeoutThickness);
+ Gdip.Graphics_Restore(graphics, gstate);
+ gstate = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect);
+ Gdip.Graphics_FillRectangle(graphics, selectionColor, x + left, baseline - run.strikeoutPos, run.x + run.width - left, run.strikeoutThickness);
+ Gdip.Graphics_Restore(graphics, gstate);
+ } else {
+ Gdip.Graphics_FillRectangle(graphics, brush, x + left, baseline - run.strikeoutPos, run.x + run.width - left, run.strikeoutThickness);
+ }
+ if (brush != selectionColor && brush != color) Gdip.SolidBrush_delete(brush);
+ return null;
+ }
+ return clipRect;
+}
+
+RECT drawUnderline(int /*long*/ hdc, int x, int baseline, int lineUnderlinePos, int lineBottom, StyleItem[] line, int index, int color, int selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd) {
+ StyleItem run = line[index];
+ TextStyle style = run.style;
+ if (style == null) return null;
+ if (!style.underline) return null;
+ clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd);
+ if (index + 1 >= line.length || !style.isAdherentUnderline(line[index + 1].style)) {
+ int left = run.x;
+ int start = run.start;
+ int end = run.start + run.length - 1;
+ for (int i = index; i > 0 && style.isAdherentUnderline(line[i - 1].style); i--) {
+ left = line[i - 1].x;
+ start = Math.min(start, line[i - 1].start);
+ end = Math.max(end, line[i - 1].start + line[i - 1].length - 1);
+ }
+ boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
+ boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd;
+ if (style.underlineColor != null) {
+ color = style.underlineColor.handle;
+ clipRect = null;
+ } else {
+ if (fullSelection) {
+ color = selectionColor;
+ clipRect = null;
+ } else {
+ if (style.foreground != null) {
+ color = style.foreground.handle;
+ }
+ }
+ }
+ RECT rect = new RECT();
+ OS.SetRect(rect, x + left, baseline - lineUnderlinePos, x + run.x + run.width, baseline - lineUnderlinePos + run.underlineThickness);
+ if (clipRect != null) {
+ if (clipRect.left == -1) clipRect.left = 0;
+ if (clipRect.right == -1) clipRect.right = 0x7ffff;
+ OS.SetRect(clipRect, Math.max(rect.left, clipRect.left), rect.top, Math.min(rect.right, clipRect.right), rect.bottom);
+ }
+ switch (style.underlineStyle) {
+ case SWT.UNDERLINE_SQUIGGLE:
+ case SWT.UNDERLINE_ERROR: {
+ int squigglyThickness = 1;
+ int squigglyHeight = 2 * squigglyThickness;
+ int squigglyY = Math.min(rect.top - squigglyHeight / 2, lineBottom - squigglyHeight - 1);
+ int[] points = computePolyline(rect.left, squigglyY, rect.right, squigglyY + squigglyHeight);
+ int /*long*/ pen = OS.CreatePen(OS.PS_SOLID, squigglyThickness, color);
+ int /*long*/ oldPen = OS.SelectObject(hdc, pen);
+ int state = OS.SaveDC(hdc);
+ OS.IntersectClipRect(hdc, rect.left, squigglyY, rect.right + 1, squigglyY + squigglyHeight + 1);
+ OS.Polyline(hdc, points, points.length / 2);
+ int length = points.length;
+ if (length >= 2 && squigglyThickness <= 1) {
+ OS.SetPixel (hdc, points[length - 2], points[length - 1], color);
+ }
+ OS.SelectObject(hdc, oldPen);
+ OS.DeleteObject(pen);
+ OS.RestoreDC(hdc, state);
+ if (clipRect != null) {
+ pen = OS.CreatePen(OS.PS_SOLID, squigglyThickness, selectionColor);
+ oldPen = OS.SelectObject(hdc, pen);
+ state = OS.SaveDC(hdc);
+ OS.IntersectClipRect(hdc, clipRect.left, squigglyY, clipRect.right + 1, squigglyY + squigglyHeight + 1);
+ OS.Polyline(hdc, points, points.length / 2);
+ if (length >= 2 && squigglyThickness <= 1) {
+ OS.SetPixel (hdc, points[length - 2], points[length - 1], selectionColor);
+ }
+ OS.SelectObject(hdc, oldPen);
+ OS.DeleteObject(pen);
+ OS.RestoreDC(hdc, state);
+ }
+ break;
+ }
+ case SWT.UNDERLINE_SINGLE:
+ case SWT.UNDERLINE_DOUBLE:
+ case SWT.UNDERLINE_LINK:
+ case UNDERLINE_IME_THICK:
+ if (style.underlineStyle == UNDERLINE_IME_THICK) {
+ rect.top -= run.underlineThickness;
+ if (clipRect != null) clipRect.top -= run.underlineThickness;
+ }
+ int bottom = style.underlineStyle == SWT.UNDERLINE_DOUBLE ? rect.bottom + run.underlineThickness * 2 : rect.bottom;
+ if (bottom > lineBottom) {
+ OS.OffsetRect(rect, 0, lineBottom - bottom);
+ if (clipRect != null) OS.OffsetRect(clipRect, 0, lineBottom - bottom);
+ }
+ int /*long*/ brush = OS.CreateSolidBrush(color);
+ OS.FillRect(hdc, rect, brush);
+ if (style.underlineStyle == SWT.UNDERLINE_DOUBLE) {
+ OS.SetRect(rect, rect.left, rect.top + run.underlineThickness * 2, rect.right, rect.bottom + run.underlineThickness * 2);
+ OS.FillRect(hdc, rect, brush);
+ }
+ OS.DeleteObject(brush);
+ if (clipRect != null) {
+ int /*long*/ selBrush = OS.CreateSolidBrush(selectionColor);
+ OS.FillRect(hdc, clipRect, selBrush);
+ if (style.underlineStyle == SWT.UNDERLINE_DOUBLE) {
+ OS.SetRect(clipRect, clipRect.left, rect.top, clipRect.right, rect.bottom);
+ OS.FillRect(hdc, clipRect, selBrush);
+ }
+ OS.DeleteObject(selBrush);
+ }
+ break;
+ case UNDERLINE_IME_DASH:
+ case UNDERLINE_IME_DOT: {
+ int penStyle = style.underlineStyle == UNDERLINE_IME_DASH ? OS.PS_DASH : OS.PS_DOT;
+ int /*long*/ pen = OS.CreatePen(penStyle, 1, color);
+ int /*long*/ oldPen = OS.SelectObject(hdc, pen);
+ OS.SetRect(rect, rect.left, baseline + run.descent, rect.right, baseline + run.descent + run.underlineThickness);
+ OS.MoveToEx(hdc, rect.left, rect.top, 0);
+ OS.LineTo(hdc, rect.right, rect.top);
+ OS.SelectObject(hdc, oldPen);
+ OS.DeleteObject(pen);
+ if (clipRect != null) {
+ pen = OS.CreatePen(penStyle, 1, selectionColor);
+ oldPen = OS.SelectObject(hdc, pen);
+ OS.SetRect(clipRect, clipRect.left, rect.top, clipRect.right, rect.bottom);
+ OS.MoveToEx(hdc, clipRect.left, clipRect.top, 0);
+ OS.LineTo(hdc, clipRect.right, clipRect.top);
+ OS.SelectObject(hdc, oldPen);
+ OS.DeleteObject(pen);
+ }
+ break;
+ }
+ }
+ return null;
+ }
+ return clipRect;
+}
+
+RECT drawUnderlineGDIP (int /*long*/ graphics, int x, int baseline, int lineUnderlinePos, int lineBottom, StyleItem[] line, int index, int /*long*/ color, int /*long*/ selectionColor, RECT clipRect, RECT pRect, int selectionStart, int selectionEnd, int alpha) {
+ StyleItem run = line[index];
+ TextStyle style = run.style;
+ if (style == null) return null;
+ if (!style.underline) return null;
+ clipRect = addClipRect(run, clipRect, pRect, selectionStart, selectionEnd);
+ if (index + 1 >= line.length || !style.isAdherentUnderline(line[index + 1].style)) {
+ int left = run.x;
+ int start = run.start;
+ int end = run.start + run.length - 1;
+ for (int i = index; i > 0 && style.isAdherentUnderline(line[i - 1].style); i--) {
+ left = line[i - 1].x;
+ start = Math.min(start, line[i - 1].start);
+ end = Math.max(end, line[i - 1].start + line[i - 1].length - 1);
+ }
+ boolean hasSelection = selectionStart <= selectionEnd && selectionStart != -1 && selectionEnd != -1;
+ boolean fullSelection = hasSelection && selectionStart <= start && end <= selectionEnd;
+ int /*long*/ brush = color;
+ if (style.underlineColor != null) {
+ brush = createGdipBrush(style.underlineColor, alpha);
+ clipRect = null;
+ } else {
+ if (fullSelection) {
+ brush = selectionColor;
+ clipRect = null;
+ } else {
+ if (style.foreground != null) {
+ brush = createGdipBrush(style.foreground, alpha);
+ }
+ }
+ }
+ RECT rect = new RECT();
+ OS.SetRect(rect, x + left, baseline - lineUnderlinePos, x + run.x + run.width, baseline - lineUnderlinePos + run.underlineThickness);
+ Rect gdipRect = null;
+ if (clipRect != null) {
+ if (clipRect.left == -1) clipRect.left = 0;
+ if (clipRect.right == -1) clipRect.right = 0x7ffff;
+ OS.SetRect(clipRect, Math.max(rect.left, clipRect.left), rect.top, Math.min(rect.right, clipRect.right), rect.bottom);
+ gdipRect = new Rect();
+ gdipRect.X = clipRect.left;
+ gdipRect.Y = clipRect.top;
+ gdipRect.Width = clipRect.right - clipRect.left;
+ gdipRect.Height = clipRect.bottom - clipRect.top;
+ }
+ int gstate = 0;
+ Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeNone);
+ switch (style.underlineStyle) {
+ case SWT.UNDERLINE_SQUIGGLE:
+ case SWT.UNDERLINE_ERROR: {
+ int squigglyThickness = 1;
+ int squigglyHeight = 2 * squigglyThickness;
+ int squigglyY = Math.min(rect.top - squigglyHeight / 2, lineBottom - squigglyHeight - 1);
+ int[] points = computePolyline(rect.left, squigglyY, rect.right, squigglyY + squigglyHeight);
+ int /*long*/ pen = Gdip.Pen_new(brush, squigglyThickness);
+ gstate = Gdip.Graphics_Save(graphics);
+ if (gdipRect != null) {
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude);
+ } else {
+ Rect r = new Rect();
+ r.X = rect.left;
+ r.Y = squigglyY;
+ r.Width = rect.right - rect.left;
+ r.Height = squigglyHeight + 1;
+ Gdip.Graphics_SetClip(graphics, r, Gdip.CombineModeIntersect);
+ }
+ Gdip.Graphics_DrawLines(graphics, pen, points, points.length / 2);
+ if (gdipRect != null) {
+ int /*long*/ selPen = Gdip.Pen_new(selectionColor, squigglyThickness);
+ Gdip.Graphics_Restore(graphics, gstate);
+ gstate = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect);
+ Gdip.Graphics_DrawLines(graphics, selPen, points, points.length / 2);
+ Gdip.Pen_delete(selPen);
+ }
+ Gdip.Graphics_Restore(graphics, gstate);
+ Gdip.Pen_delete(pen);
+ if (gstate != 0) Gdip.Graphics_Restore(graphics, gstate);
+ break;
+ }
+ case SWT.UNDERLINE_SINGLE:
+ case SWT.UNDERLINE_DOUBLE:
+ case SWT.UNDERLINE_LINK:
+ case UNDERLINE_IME_THICK:
+ if (style.underlineStyle == UNDERLINE_IME_THICK) {
+ rect.top -= run.underlineThickness;
+ }
+ int bottom = style.underlineStyle == SWT.UNDERLINE_DOUBLE ? rect.bottom + run.underlineThickness * 2 : rect.bottom;
+ if (bottom > lineBottom) {
+ OS.OffsetRect(rect, 0, lineBottom - bottom);
+ }
+ if (gdipRect != null) {
+ gdipRect.Y = rect.top;
+ if (style.underlineStyle == UNDERLINE_IME_THICK) {
+ gdipRect.Height = run.underlineThickness * 2;
+ }
+ if (style.underlineStyle == SWT.UNDERLINE_DOUBLE) {
+ gdipRect.Height = run.underlineThickness * 3;
+ }
+ gstate = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude);
+ }
+ Gdip.Graphics_FillRectangle(graphics, brush, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+ if (style.underlineStyle == SWT.UNDERLINE_DOUBLE) {
+ Gdip.Graphics_FillRectangle(graphics, brush, rect.left, rect.top + run.underlineThickness * 2, rect.right - rect.left, rect.bottom - rect.top);
+ }
+ if (gdipRect != null) {
+ Gdip.Graphics_Restore(graphics, gstate);
+ gstate = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect);
+ Gdip.Graphics_FillRectangle(graphics, selectionColor, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
+ if (style.underlineStyle == SWT.UNDERLINE_DOUBLE) {
+ Gdip.Graphics_FillRectangle(graphics, selectionColor, rect.left, rect.top + run.underlineThickness * 2, rect.right - rect.left, rect.bottom - rect.top);
+ }
+ Gdip.Graphics_Restore(graphics, gstate);
+ }
+ break;
+ case UNDERLINE_IME_DOT:
+ case UNDERLINE_IME_DASH: {
+ int /*long*/ pen = Gdip.Pen_new(brush, 1);
+ int dashStyle = style.underlineStyle == UNDERLINE_IME_DOT ? Gdip.DashStyleDot : Gdip.DashStyleDash;
+ Gdip.Pen_SetDashStyle(pen, dashStyle);
+ if (gdipRect != null) {
+ gstate = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeExclude);
+ }
+ Gdip.Graphics_DrawLine(graphics, pen, rect.left, baseline + run.descent, run.width - run.length, baseline + run.descent);
+ if (gdipRect != null) {
+ Gdip.Graphics_Restore(graphics, gstate);
+ gstate = Gdip.Graphics_Save(graphics);
+ Gdip.Graphics_SetClip(graphics, gdipRect, Gdip.CombineModeIntersect);
+ int /*long*/ selPen = Gdip.Pen_new(brush, 1);
+ Gdip.Pen_SetDashStyle(selPen, dashStyle);
+ Gdip.Graphics_DrawLine(graphics, selPen, rect.left, baseline + run.descent, run.width - run.length, baseline + run.descent);
+ Gdip.Graphics_Restore(graphics, gstate);
+ Gdip.Pen_delete(selPen);
+ }
+ Gdip.Pen_delete(pen);
+ break;
+ }
+ }
+ if (brush != selectionColor && brush != color) Gdip.SolidBrush_delete(brush);
+ Gdip.Graphics_SetPixelOffsetMode(graphics, Gdip.PixelOffsetModeHalf);
+ return null;
+ }
+ return clipRect;
+}
+
+void freeRuns () {
+ if (allRuns == null) return;
+ for (int i=0; i<allRuns.length; i++) {
+ StyleItem run = allRuns[i];
+ run.free();
+ }
+ allRuns = null;
+ runs = null;
+ segmentsText = null;
+}
+
+/**
+ * Returns the receiver's horizontal text alignment, which will be one
+ * of <code>SWT.LEFT</code>, <code>SWT.CENTER</code> or
+ * <code>SWT.RIGHT</code>.
+ *
+ * @return the alignment used to positioned text horizontally
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getAlignment () {
+ checkLayout();
+ return alignment;
+}
+
+/**
+ * Returns the ascent of the receiver.
+ *
+ * @return the ascent
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getDescent()
+ * @see #setDescent(int)
+ * @see #setAscent(int)
+ * @see #getLineMetrics(int)
+ */
+public int getAscent () {
+ checkLayout();
+ return ascent;
+}
+
+/**
+ * Returns the bounds of the receiver. The width returned is either the
+ * width of the longest line or the width set using {@link TextLayout#setWidth(int)}.
+ * To obtain the text bounds of a line use {@link TextLayout#getLineBounds(int)}.
+ *
+ * @return the bounds of the receiver
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setWidth(int)
+ * @see #getLineBounds(int)
+ */
+public Rectangle getBounds () {
+ checkLayout();
+ computeRuns(null);
+ int width = 0;
+ if (wrapWidth != -1) {
+ width = wrapWidth;
+ } else {
+ for (int line=0; line<runs.length; line++) {
+ width = Math.max(width, lineWidth[line] + getLineIndent(line));
+ }
+ }
+ return new Rectangle (0, 0, width, lineY[lineY.length - 1]);
+}
+
+/**
+ * Returns the bounds for the specified range of characters. The
+ * bounds is the smallest rectangle that encompasses all characters
+ * in the range. The start and end offsets are inclusive and will be
+ * clamped if out of range.
+ *
+ * @param start the start offset
+ * @param end the end offset
+ * @return the bounds of the character range
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getBounds (int start, int end) {
+ checkLayout();
+ computeRuns(null);
+ int length = text.length();
+ if (length == 0) return new Rectangle(0, 0, 0, 0);
+ if (start > end) return new Rectangle(0, 0, 0, 0);
+ start = Math.min(Math.max(0, start), length - 1);
+ end = Math.min(Math.max(0, end), length - 1);
+ start = translateOffset(start);
+ end = translateOffset(end);
+ int left = 0x7fffffff, right = 0;
+ int top = 0x7fffffff, bottom = 0;
+ boolean isRTL = (orientation & SWT.RIGHT_TO_LEFT) != 0;
+ for (int i = 0; i < allRuns.length - 1; i++) {
+ StyleItem run = allRuns[i];
+ int runEnd = run.start + run.length;
+ if (runEnd <= start) continue;
+ if (run.start > end) break;
+ int runLead = run.x;
+ int runTrail = run.x + run.width;
+ if (run.start <= start && start < runEnd) {
+ int cx = 0;
+ if (run.style != null && run.style.metrics != null) {
+ GlyphMetrics metrics = run.style.metrics;
+ cx = metrics.width * (start - run.start);
+ } else if (!run.tab) {
+ int[] piX = new int[1];
+ int /*long*/ advances = run.justify != 0 ? run.justify : run.advances;
+ OS.ScriptCPtoX(start - run.start, false, run.length, run.glyphCount, run.clusters, run.visAttrs, advances, run.analysis, piX);
+ cx = isRTL ? run.width - piX[0] : piX[0];
+ }
+ if (run.analysis.fRTL ^ isRTL) {
+ runTrail = run.x + cx;
+ } else {
+ runLead = run.x + cx;
+ }
+ }
+ if (run.start <= end && end < runEnd) {
+ int cx = run.width;
+ if (run.style != null && run.style.metrics != null) {
+ GlyphMetrics metrics = run.style.metrics;
+ cx = metrics.width * (end - run.start + 1);
+ } else if (!run.tab) {
+ int[] piX = new int[1];
+ int /*long*/ advances = run.justify != 0 ? run.justify : run.advances;
+ OS.ScriptCPtoX(end - run.start, true, run.length, run.glyphCount, run.clusters, run.visAttrs, advances, run.analysis, piX);
+ cx = isRTL ? run.width - piX[0] : piX[0];
+ }
+ if (run.analysis.fRTL ^ isRTL) {
+ runLead = run.x + cx;
+ } else {
+ runTrail = run.x + cx;
+ }
+ }
+ int lineIndex = 0;
+ while (lineIndex < runs.length && lineOffset[lineIndex + 1] <= run.start) {
+ lineIndex++;
+ }
+ left = Math.min(left, runLead);
+ right = Math.max(right, runTrail);
+ top = Math.min(top, lineY[lineIndex]);
+ bottom = Math.max(bottom, lineY[lineIndex + 1] - lineSpacing);
+ }
+ return new Rectangle(left, top, right - left, bottom - top);
+}
+
+/**
+ * Returns the descent of the receiver.
+ *
+ * @return the descent
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getAscent()
+ * @see #setAscent(int)
+ * @see #setDescent(int)
+ * @see #getLineMetrics(int)
+ */
+public int getDescent () {
+ checkLayout();
+ return descent;
+}
+
+/**
+ * Returns the default font currently being used by the receiver
+ * to draw and measure text.
+ *
+ * @return the receiver's font
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Font getFont () {
+ checkLayout();
+ return font;
+}
+
+/**
+* Returns the receiver's indent.
+*
+* @return the receiver's indent
+*
+* @exception SWTException <ul>
+* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+* </ul>
+*
+* @since 3.2
+*/
+public int getIndent () {
+ checkLayout();
+ return indent;
+}
+
+/**
+* Returns the receiver's justification.
+*
+* @return the receiver's justification
+*
+* @exception SWTException <ul>
+* <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+* </ul>
+*
+* @since 3.2
+*/
+public boolean getJustify () {
+ checkLayout();
+ return justify;
+}
+
+int /*long*/ getItemFont (StyleItem item) {
+ if (item.fallbackFont != 0) return item.fallbackFont;
+ if (item.style != null && item.style.font != null) {
+ return item.style.font.handle;
+ }
+ if (this.font != null) {
+ return this.font.handle;
+ }
+ return device.systemFont.handle;
+}
+
+/**
+ * Returns the embedding level for the specified character offset. The
+ * embedding level is usually used to determine the directionality of a
+ * character in bidirectional text.
+ *
+ * @param offset the character offset
+ * @return the embedding level
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ */
+public int getLevel (int offset) {
+ checkLayout();
+ computeRuns(null);
+ int length = text.length();
+ if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ offset = translateOffset(offset);
+ for (int i=1; i<allRuns.length; i++) {
+ if (allRuns[i].start > offset) {
+ return allRuns[i - 1].analysis.s.uBidiLevel;
+ }
+ }
+ return (orientation & SWT.RIGHT_TO_LEFT) != 0 ? 1 : 0;
+}
+
+/**
+ * Returns the bounds of the line for the specified line index.
+ *
+ * @param lineIndex the line index
+ * @return the line bounds
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the line index is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public Rectangle getLineBounds(int lineIndex) {
+ checkLayout();
+ computeRuns(null);
+ if (!(0 <= lineIndex && lineIndex < runs.length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ int x = getLineIndent(lineIndex);
+ int y = lineY[lineIndex];
+ int width = lineWidth[lineIndex];
+ int height = lineY[lineIndex + 1] - y - lineSpacing;
+ return new Rectangle (x, y, width, height);
+}
+
+/**
+ * Returns the receiver's line count. This includes lines caused
+ * by wrapping.
+ *
+ * @return the line count
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineCount () {
+ checkLayout();
+ computeRuns(null);
+ return runs.length;
+}
+
+int getLineIndent (int lineIndex) {
+ int lineIndent = 0;
+ if (lineIndex == 0) {
+ lineIndent = indent;
+ } else {
+ StyleItem[] previousLine = runs[lineIndex - 1];
+ StyleItem previousRun = previousLine[previousLine.length - 1];
+ if (previousRun.lineBreak && !previousRun.softBreak) {
+ lineIndent = indent;
+ }
+ }
+ if (wrapWidth != -1) {
+ boolean partialLine = true;
+ if (justify) {
+ StyleItem[] lineRun = runs[lineIndex];
+ if (lineRun[lineRun.length - 1].softBreak) {
+ partialLine = false;
+ }
+ }
+ if (partialLine) {
+ int lineWidth = this.lineWidth[lineIndex] + lineIndent;
+ switch (alignment) {
+ case SWT.CENTER: lineIndent += (wrapWidth - lineWidth) / 2; break;
+ case SWT.RIGHT: lineIndent += wrapWidth - lineWidth; break;
+ }
+ }
+ }
+ return lineIndent;
+}
+
+/**
+ * Returns the index of the line that contains the specified
+ * character offset.
+ *
+ * @param offset the character offset
+ * @return the line index
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getLineIndex (int offset) {
+ checkLayout();
+ computeRuns(null);
+ int length = text.length();
+ if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ offset = translateOffset(offset);
+ for (int line=0; line<runs.length; line++) {
+ if (lineOffset[line + 1] > offset) {
+ return line;
+ }
+ }
+ return runs.length - 1;
+}
+
+/**
+ * Returns the font metrics for the specified line index.
+ *
+ * @param lineIndex the line index
+ * @return the font metrics
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the line index is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public FontMetrics getLineMetrics (int lineIndex) {
+ checkLayout();
+ computeRuns(null);
+ if (!(0 <= lineIndex && lineIndex < runs.length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ int /*long*/ hDC = device.internal_new_GC(null);
+ int /*long*/ srcHdc = OS.CreateCompatibleDC(hDC);
+ TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
+ OS.SelectObject(srcHdc, font != null ? font.handle : device.systemFont.handle);
+ OS.GetTextMetrics(srcHdc, lptm);
+ OS.DeleteDC(srcHdc);
+ device.internal_dispose_GC(hDC, null);
+
+ int ascent = Math.max(lptm.tmAscent, this.ascent);
+ int descent = Math.max(lptm.tmDescent, this.descent);
+ int leading = lptm.tmInternalLeading;
+ if (text.length() != 0) {
+ StyleItem[] lineRuns = runs[lineIndex];
+ for (int i = 0; i<lineRuns.length; i++) {
+ StyleItem run = lineRuns[i];
+ if (run.ascent > ascent) {
+ ascent = run.ascent;
+ leading = run.leading;
+ }
+ descent = Math.max(descent, run.descent);
+ }
+ }
+ lptm.tmAscent = ascent;
+ lptm.tmDescent = descent;
+ lptm.tmHeight = ascent + descent;
+ lptm.tmInternalLeading = leading;
+ lptm.tmAveCharWidth = 0;
+ return FontMetrics.win32_new(lptm);
+}
+
+/**
+ * Returns the line offsets. Each value in the array is the
+ * offset for the first character in a line except for the last
+ * value, which contains the length of the text.
+ *
+ * @return the line offsets
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int[] getLineOffsets () {
+ checkLayout();
+ computeRuns(null);
+ int[] offsets = new int[lineOffset.length];
+ for (int i = 0; i < offsets.length; i++) {
+ offsets[i] = untranslateOffset(lineOffset[i]);
+ }
+ return offsets;
+}
+
+/**
+ * Returns the location for the specified character offset. The
+ * <code>trailing</code> argument indicates whether the offset
+ * corresponds to the leading or trailing edge of the cluster.
+ *
+ * @param offset the character offset
+ * @param trailing the trailing flag
+ * @return the location of the character offset
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getOffset(Point, int[])
+ * @see #getOffset(int, int, int[])
+ */
+public Point getLocation (int offset, boolean trailing) {
+ checkLayout();
+ computeRuns(null);
+ int length = text.length();
+ if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ length = segmentsText.length();
+ offset = translateOffset(offset);
+ int line;
+ for (line=0; line<runs.length; line++) {
+ if (lineOffset[line + 1] > offset) break;
+ }
+ line = Math.min(line, runs.length - 1);
+ if (offset == length) {
+ return new Point(getLineIndent(line) + lineWidth[line], lineY[line]);
+ }
+ int low = -1;
+ int high = allRuns.length;
+ while (high - low > 1) {
+ int index = ((high + low) / 2);
+ StyleItem run = allRuns[index];
+ if (run.start > offset) {
+ high = index;
+ } else if (run.start + run.length <= offset) {
+ low = index;
+ } else {
+ int width;
+ if (run.style != null && run.style.metrics != null) {
+ GlyphMetrics metrics = run.style.metrics;
+ width = metrics.width * (offset - run.start + (trailing ? 1 : 0));
+ } else if (run.tab) {
+ width = (trailing || (offset == length)) ? run.width : 0;
+ } else {
+ int runOffset = offset - run.start;
+ int cChars = run.length;
+ int gGlyphs = run.glyphCount;
+ int[] piX = new int[1];
+ int /*long*/ advances = run.justify != 0 ? run.justify : run.advances;
+ OS.ScriptCPtoX(runOffset, trailing, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX);
+ width = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - piX[0] : piX[0];
+ }
+ return new Point(run.x + width, lineY[line]);
+ }
+ }
+ return new Point(0, 0);
+}
+
+/**
+ * Returns the next offset for the specified offset and movement
+ * type. The movement is one of <code>SWT.MOVEMENT_CHAR</code>,
+ * <code>SWT.MOVEMENT_CLUSTER</code>, <code>SWT.MOVEMENT_WORD</code>,
+ * <code>SWT.MOVEMENT_WORD_END</code> or <code>SWT.MOVEMENT_WORD_START</code>.
+ *
+ * @param offset the start offset
+ * @param movement the movement type
+ * @return the next offset
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the offset is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getPreviousOffset(int, int)
+ */
+public int getNextOffset (int offset, int movement) {
+ checkLayout();
+ return _getOffset (offset, movement, true);
+}
+
+int _getOffset(int offset, int movement, boolean forward) {
+ computeRuns(null);
+ int length = text.length();
+ if (!(0 <= offset && offset <= length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ if (forward && offset == length) return length;
+ if (!forward && offset == 0) return 0;
+ int step = forward ? 1 : -1;
+ if ((movement & SWT.MOVEMENT_CHAR) != 0) return offset + step;
+ length = segmentsText.length();
+ offset = translateOffset(offset);
+ SCRIPT_LOGATTR logAttr = new SCRIPT_LOGATTR();
+ SCRIPT_PROPERTIES properties = new SCRIPT_PROPERTIES();
+ int i = forward ? 0 : allRuns.length - 1;
+ offset = validadeOffset(offset, step);
+ do {
+ StyleItem run = allRuns[i];
+ if (run.start <= offset && offset < run.start + run.length) {
+ if (run.lineBreak && !run.softBreak) return untranslateOffset(run.start);
+ if (run.tab) return untranslateOffset(run.start);
+ OS.MoveMemory(properties, device.scripts[run.analysis.eScript], SCRIPT_PROPERTIES.sizeof);
+ boolean isComplex = properties.fNeedsCaretInfo || properties.fNeedsWordBreaking;
+ if (isComplex) breakRun(run);
+ while (run.start <= offset && offset < run.start + run.length) {
+ if (isComplex) {
+ OS.MoveMemory(logAttr, run.psla + ((offset - run.start) * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof);
+ }
+ switch (movement) {
+ case SWT.MOVEMENT_CLUSTER: {
+ if (properties.fNeedsCaretInfo) {
+ if (!logAttr.fInvalid && logAttr.fCharStop) return untranslateOffset(offset);
+ } else {
+ return untranslateOffset(offset);
+ }
+ break;
+ }
+ case SWT.MOVEMENT_WORD_START:
+ case SWT.MOVEMENT_WORD: {
+ if (properties.fNeedsWordBreaking) {
+ if (!logAttr.fInvalid && logAttr.fWordStop) return untranslateOffset(offset);
+ } else {
+ if (offset > 0) {
+ boolean letterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset));
+ boolean previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset - 1));
+ if (letterOrDigit != previousLetterOrDigit || !letterOrDigit) {
+ if (!Compatibility.isWhitespace(segmentsText.charAt(offset))) {
+ return untranslateOffset(offset);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case SWT.MOVEMENT_WORD_END: {
+ if (offset > 0) {
+ boolean isLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset));
+ boolean previousLetterOrDigit = Compatibility.isLetterOrDigit(segmentsText.charAt(offset - 1));
+ if (!isLetterOrDigit && previousLetterOrDigit) {
+ return untranslateOffset(offset);
+ }
+ }
+ break;
+ }
+ }
+ offset = validadeOffset(offset, step);
+ }
+ }
+ i += step;
+ } while (0 <= i && i < allRuns.length - 1 && 0 <= offset && offset < length);
+ return forward ? text.length() : 0;
+}
+
+/**
+ * Returns the character offset for the specified point.
+ * For a typical character, the trailing argument will be filled in to
+ * indicate whether the point is closer to the leading edge (0) or
+ * the trailing edge (1). When the point is over a cluster composed
+ * of multiple characters, the trailing argument will be filled with the
+ * position of the character in the cluster that is closest to
+ * the point.
+ *
+ * @param point the point
+ * @param trailing the trailing buffer
+ * @return the character offset
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the trailing length is less than <code>1</code></li>
+ * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getLocation(int, boolean)
+ */
+public int getOffset (Point point, int[] trailing) {
+ checkLayout();
+ if (point == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
+ return getOffset (point.x, point.y, trailing) ;
+}
+
+/**
+ * Returns the character offset for the specified point.
+ * For a typical character, the trailing argument will be filled in to
+ * indicate whether the point is closer to the leading edge (0) or
+ * the trailing edge (1). When the point is over a cluster composed
+ * of multiple characters, the trailing argument will be filled with the
+ * position of the character in the cluster that is closest to
+ * the point.
+ *
+ * @param x the x coordinate of the point
+ * @param y the y coordinate of the point
+ * @param trailing the trailing buffer
+ * @return the character offset
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the trailing length is less than <code>1</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getLocation(int, boolean)
+ */
+public int getOffset (int x, int y, int[] trailing) {
+ checkLayout();
+ computeRuns(null);
+ if (trailing != null && trailing.length < 1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ int line;
+ int lineCount = runs.length;
+ for (line=0; line<lineCount; line++) {
+ if (lineY[line + 1] > y) break;
+ }
+ line = Math.min(line, runs.length - 1);
+ StyleItem[] lineRuns = runs[line];
+ int lineIndent = getLineIndent(line);
+ if (x >= lineIndent + lineWidth[line]) x = lineIndent + lineWidth[line] - 1;
+ if (x < lineIndent) x = lineIndent;
+ int low = -1;
+ int high = lineRuns.length;
+ while (high - low > 1) {
+ int index = ((high + low) / 2);
+ StyleItem run = lineRuns[index];
+ if (run.x > x) {
+ high = index;
+ } else if (run.x + run.width <= x) {
+ low = index;
+ } else {
+ if (run.lineBreak && !run.softBreak) return untranslateOffset(run.start);
+ int xRun = x - run.x;
+ if (run.style != null && run.style.metrics != null) {
+ GlyphMetrics metrics = run.style.metrics;
+ if (metrics.width > 0) {
+ if (trailing != null) {
+ trailing[0] = (xRun % metrics.width < metrics.width / 2) ? 0 : 1;
+ }
+ return untranslateOffset(run.start + xRun / metrics.width);
+ }
+ }
+ if (run.tab) {
+ if (trailing != null) trailing[0] = x < (run.x + run.width / 2) ? 0 : 1;
+ return untranslateOffset(run.start);
+ }
+ int cChars = run.length;
+ int cGlyphs = run.glyphCount;
+ int[] piCP = new int[1];
+ int[] piTrailing = new int[1];
+ if ((orientation & SWT.RIGHT_TO_LEFT) != 0) {
+ xRun = run.width - xRun;
+ }
+ int /*long*/ advances = run.justify != 0 ? run.justify : run.advances;
+ OS.ScriptXtoCP(xRun, cChars, cGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piCP, piTrailing);
+ if (trailing != null) trailing[0] = piTrailing[0];
+ return untranslateOffset(run.start + piCP[0]);
+ }
+ }
+ if (trailing != null) trailing[0] = 0;
+ if (lineRuns.length == 1) {
+ StyleItem run = lineRuns[0];
+ if (run.lineBreak && !run.softBreak) return untranslateOffset(run.start);
+ }
+ return untranslateOffset(lineOffset[line + 1]);
+}
+
+/**
+ * Returns the orientation of the receiver.
+ *
+ * @return the orientation style
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getOrientation () {
+ checkLayout();
+ return orientation;
+}
+
+void getPartialSelection(StyleItem run, int selectionStart, int selectionEnd, RECT rect) {
+ int end = run.start + run.length - 1;
+ int selStart = Math.max(selectionStart, run.start) - run.start;
+ int selEnd = Math.min(selectionEnd, end) - run.start;
+ int cChars = run.length;
+ int gGlyphs = run.glyphCount;
+ int[] piX = new int[1];
+ int x = rect.left;
+ int /*long*/ advances = run.justify != 0 ? run.justify : run.advances;
+ OS.ScriptCPtoX(selStart, false, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX);
+ int runX = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - piX[0] : piX[0];
+ rect.left = x + runX;
+ OS.ScriptCPtoX(selEnd, true, cChars, gGlyphs, run.clusters, run.visAttrs, advances, run.analysis, piX);
+ runX = (orientation & SWT.RIGHT_TO_LEFT) != 0 ? run.width - piX[0] : piX[0];
+ rect.right = x + runX;
+}
+
+/**
+ * Returns the previous offset for the specified offset and movement
+ * type. The movement is one of <code>SWT.MOVEMENT_CHAR</code>,
+ * <code>SWT.MOVEMENT_CLUSTER</code> or <code>SWT.MOVEMENT_WORD</code>,
+ * <code>SWT.MOVEMENT_WORD_END</code> or <code>SWT.MOVEMENT_WORD_START</code>.
+ *
+ * @param offset the start offset
+ * @param movement the movement type
+ * @return the previous offset
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the offset is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getNextOffset(int, int)
+ */
+public int getPreviousOffset (int offset, int movement) {
+ checkLayout();
+ return _getOffset (offset, movement, false);
+}
+
+/**
+ * Gets the ranges of text that are associated with a <code>TextStyle</code>.
+ *
+ * @return the ranges, an array of offsets representing the start and end of each
+ * text style.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getStyles()
+ *
+ * @since 3.2
+ */
+public int[] getRanges () {
+ checkLayout();
+ int[] result = new int[stylesCount * 2];
+ int count = 0;
+ for (int i=0; i<stylesCount - 1; i++) {
+ if (styles[i].style != null) {
+ result[count++] = styles[i].start;
+ result[count++] = styles[i + 1].start - 1;
+ }
+ }
+ if (count != result.length) {
+ int[] newResult = new int[count];
+ System.arraycopy(result, 0, newResult, 0, count);
+ result = newResult;
+ }
+ return result;
+}
+
+/**
+ * Returns the text segments offsets of the receiver.
+ *
+ * @return the text segments offsets
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int[] getSegments () {
+ checkLayout();
+ return segments;
+}
+
+String getSegmentsText() {
+ if (segments == null) return text;
+ int nSegments = segments.length;
+ if (nSegments <= 1) return text;
+ int length = text.length();
+ if (length == 0) return text;
+ if (nSegments == 2) {
+ if (segments[0] == 0 && segments[1] == length) return text;
+ }
+ char[] oldChars = new char[length];
+ text.getChars(0, length, oldChars, 0);
+ char[] newChars = new char[length + nSegments];
+ int charCount = 0, segmentCount = 0;
+ char separator = orientation == SWT.RIGHT_TO_LEFT ? RTL_MARK : LTR_MARK;
+ while (charCount < length) {
+ if (segmentCount < nSegments && charCount == segments[segmentCount]) {
+ newChars[charCount + segmentCount++] = separator;
+ } else {
+ newChars[charCount + segmentCount] = oldChars[charCount++];
+ }
+ }
+ if (segmentCount < nSegments) {
+ segments[segmentCount] = charCount;
+ newChars[charCount + segmentCount++] = separator;
+ }
+ return new String(newChars, 0, Math.min(charCount + segmentCount, newChars.length));
+}
+
+/**
+ * Returns the line spacing of the receiver.
+ *
+ * @return the line spacing
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getSpacing () {
+ checkLayout();
+ return lineSpacing;
+}
+
+/**
+ * Gets the style of the receiver at the specified character offset.
+ *
+ * @param offset the text offset
+ * @return the style or <code>null</code> if not set
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the character offset is out of range</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public TextStyle getStyle (int offset) {
+ checkLayout();
+ int length = text.length();
+ if (!(0 <= offset && offset < length)) SWT.error(SWT.ERROR_INVALID_RANGE);
+ for (int i=1; i<stylesCount; i++) {
+ if (styles[i].start > offset) {
+ return styles[i - 1].style;
+ }
+ }
+ return null;
+}
+
+/**
+ * Gets all styles of the receiver.
+ *
+ * @return the styles
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #getRanges()
+ *
+ * @since 3.2
+ */
+public TextStyle[] getStyles () {
+ checkLayout();
+ TextStyle[] result = new TextStyle[stylesCount];
+ int count = 0;
+ for (int i=0; i<stylesCount; i++) {
+ if (styles[i].style != null) {
+ result[count++] = styles[i].style;
+ }
+ }
+ if (count != result.length) {
+ TextStyle[] newResult = new TextStyle[count];
+ System.arraycopy(result, 0, newResult, 0, count);
+ result = newResult;
+ }
+ return result;
+}
+
+/**
+ * Returns the tab list of the receiver.
+ *
+ * @return the tab list
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int[] getTabs () {
+ checkLayout();
+ return tabs;
+}
+
+/**
+ * Gets the receiver's text, which will be an empty
+ * string if it has never been set.
+ *
+ * @return the receiver's text
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public String getText () {
+ checkLayout();
+ return text;
+}
+
+/**
+ * Returns the width of the receiver.
+ *
+ * @return the width
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public int getWidth () {
+ checkLayout();
+ return wrapWidth;
+}
+
+/**
+ * Returns <code>true</code> if the text layout has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the text layout.
+ * When a text layout has been disposed, it is an error to
+ * invoke any other method using the text layout.
+ * </p>
+ *
+ * @return <code>true</code> when the text layout is disposed and <code>false</code> otherwise
+ */
+public boolean isDisposed () {
+ return device == null;
+}
+
+/*
+ * Itemize the receiver text
+ */
+StyleItem[] itemize () {
+ segmentsText = getSegmentsText();
+ int length = segmentsText.length();
+ SCRIPT_CONTROL scriptControl = new SCRIPT_CONTROL();
+ SCRIPT_STATE scriptState = new SCRIPT_STATE();
+ final int MAX_ITEM = length + 1;
+
+ if ((orientation & SWT.RIGHT_TO_LEFT) != 0) {
+ scriptState.uBidiLevel = 1;
+ scriptState.fArabicNumContext = true;
+ SCRIPT_DIGITSUBSTITUTE psds = new SCRIPT_DIGITSUBSTITUTE();
+ OS.ScriptRecordDigitSubstitution(OS.LOCALE_USER_DEFAULT, psds);
+ OS.ScriptApplyDigitSubstitution(psds, scriptControl, scriptState);
+ }
+
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ int /*long*/ pItems = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, MAX_ITEM * SCRIPT_ITEM.sizeof);
+ if (pItems == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ int[] pcItems = new int[1];
+ char[] chars = new char[length];
+ segmentsText.getChars(0, length, chars, 0);
+ OS.ScriptItemize(chars, length, MAX_ITEM, scriptControl, scriptState, pItems, pcItems);
+// if (hr == E_OUTOFMEMORY) //TODO handle it
+
+ StyleItem[] runs = merge(pItems, pcItems[0]);
+ OS.HeapFree(hHeap, 0, pItems);
+ return runs;
+}
+
+/*
+ * Merge styles ranges and script items
+ */
+StyleItem[] merge (int /*long*/ items, int itemCount) {
+ if (styles.length > stylesCount) {
+ StyleItem[] newStyles = new StyleItem[stylesCount];
+ System.arraycopy(styles, 0, newStyles, 0, stylesCount);
+ styles = newStyles;
+ }
+ int count = 0, start = 0, end = segmentsText.length(), itemIndex = 0, styleIndex = 0;
+ StyleItem[] runs = new StyleItem[itemCount + stylesCount];
+ SCRIPT_ITEM scriptItem = new SCRIPT_ITEM();
+ int itemLimit = -1;
+ int nextItemIndex = 0;
+ boolean linkBefore = false;
+ boolean merge = itemCount > TOO_MANY_RUNS;
+ SCRIPT_PROPERTIES sp = new SCRIPT_PROPERTIES();
+ while (start < end) {
+ StyleItem item = new StyleItem();
+ item.start = start;
+ item.style = styles[styleIndex].style;
+ runs[count++] = item;
+ OS.MoveMemory(scriptItem, items + itemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
+ item.analysis = scriptItem.a;
+ scriptItem.a = new SCRIPT_ANALYSIS();
+ if (linkBefore) {
+ item.analysis.fLinkBefore = true;
+ linkBefore = false;
+ }
+ char ch = segmentsText.charAt(start);
+ switch (ch) {
+ case '\r':
+ case '\n':
+ item.lineBreak = true;
+ break;
+ case '\t':
+ item.tab = true;
+ break;
+ }
+ if (itemLimit == -1) {
+ nextItemIndex = itemIndex + 1;
+ OS.MoveMemory(scriptItem, items + nextItemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
+ itemLimit = scriptItem.iCharPos;
+ if (nextItemIndex < itemCount && ch == '\r' && segmentsText.charAt(itemLimit) == '\n') {
+ nextItemIndex = itemIndex + 2;
+ OS.MoveMemory(scriptItem, items + nextItemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
+ itemLimit = scriptItem.iCharPos;
+ }
+ if (nextItemIndex < itemCount && merge) {
+ if (!item.lineBreak) {
+ OS.MoveMemory(sp, device.scripts[item.analysis.eScript], SCRIPT_PROPERTIES.sizeof);
+ if (!sp.fComplex || item.tab) {
+ for (int i = 0; i < MERGE_MAX; i++) {
+ if (nextItemIndex == itemCount) break;
+ char c = segmentsText.charAt(itemLimit);
+ if (c == '\n' || c == '\r') break;
+ if (c == '\t' != item.tab) break;
+ OS.MoveMemory(sp, device.scripts[scriptItem.a.eScript], SCRIPT_PROPERTIES.sizeof);
+ if (!item.tab && sp.fComplex) break;
+ nextItemIndex++;
+ OS.MoveMemory(scriptItem, items + nextItemIndex * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
+ itemLimit = scriptItem.iCharPos;
+ }
+ }
+ }
+ }
+ }
+
+ int styleLimit = translateOffset(styles[styleIndex + 1].start);
+ if (styleLimit <= itemLimit) {
+ styleIndex++;
+ start = styleLimit;
+ if (start < itemLimit && 0 < start && start < end) {
+ char pChar = segmentsText.charAt(start - 1);
+ char tChar = segmentsText.charAt(start);
+ if (Compatibility.isLetter(pChar) && Compatibility.isLetter(tChar)) {
+ item.analysis.fLinkAfter = true;
+ linkBefore = true;
+ }
+ }
+ }
+ if (itemLimit <= styleLimit) {
+ itemIndex = nextItemIndex;
+ start = itemLimit;
+ itemLimit = -1;
+ }
+ item.length = start - item.start;
+ }
+ StyleItem item = new StyleItem();
+ item.start = end;
+ OS.MoveMemory(scriptItem, items + itemCount * SCRIPT_ITEM.sizeof, SCRIPT_ITEM.sizeof);
+ item.analysis = scriptItem.a;
+ runs[count++] = item;
+ if (runs.length != count) {
+ StyleItem[] result = new StyleItem[count];
+ System.arraycopy(runs, 0, result, 0, count);
+ return result;
+ }
+ return runs;
+}
+
+/*
+ * Reorder the run
+ */
+StyleItem[] reorder (StyleItem[] runs, boolean terminate) {
+ int length = runs.length;
+ if (length <= 1) return runs;
+ byte[] bidiLevels = new byte[length];
+ for (int i=0; i<length; i++) {
+ bidiLevels[i] = (byte)(runs[i].analysis.s.uBidiLevel & 0x1F);
+ }
+ /*
+ * Feature in Windows. If the orientation is RTL Uniscribe will
+ * resolve the level of line breaks to 1, this can cause the line
+ * break to be reorder to the middle of the line. The fix is to set
+ * the level to zero to prevent it to be reordered.
+ */
+ StyleItem lastRun = runs[length - 1];
+ if (lastRun.lineBreak && !lastRun.softBreak) {
+ bidiLevels[length - 1] = 0;
+ }
+ int[] log2vis = new int[length];
+ OS.ScriptLayout(length, bidiLevels, null, log2vis);
+ StyleItem[] result = new StyleItem[length];
+ for (int i=0; i<length; i++) {
+ result[log2vis[i]] = runs[i];
+ }
+ if ((orientation & SWT.RIGHT_TO_LEFT) != 0) {
+ if (terminate) length--;
+ for (int i = 0; i < length / 2 ; i++) {
+ StyleItem tmp = result[i];
+ result[i] = result[length - i - 1];
+ result[length - i - 1] = tmp;
+ }
+ }
+ return result;
+}
+
+/**
+ * Sets the text alignment for the receiver. The alignment controls
+ * how a line of text is positioned horizontally. The argument should
+ * be one of <code>SWT.LEFT</code>, <code>SWT.RIGHT</code> or <code>SWT.CENTER</code>.
+ * <p>
+ * The default alignment is <code>SWT.LEFT</code>. Note that the receiver's
+ * width must be set in order to use <code>SWT.RIGHT</code> or <code>SWT.CENTER</code>
+ * alignment.
+ * </p>
+ *
+ * @param alignment the new alignment
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setWidth(int)
+ */
+public void setAlignment (int alignment) {
+ checkLayout();
+ int mask = SWT.LEFT | SWT.CENTER | SWT.RIGHT;
+ alignment &= mask;
+ if (alignment == 0) return;
+ if ((alignment & SWT.LEFT) != 0) alignment = SWT.LEFT;
+ if ((alignment & SWT.RIGHT) != 0) alignment = SWT.RIGHT;
+ if (this.alignment == alignment) return;
+ freeRuns();
+ this.alignment = alignment;
+}
+
+/**
+ * Sets the ascent of the receiver. The ascent is distance in pixels
+ * from the baseline to the top of the line and it is applied to all
+ * lines. The default value is <code>-1</code> which means that the
+ * ascent is calculated from the line fonts.
+ *
+ * @param ascent the new ascent
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the ascent is less than <code>-1</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setDescent(int)
+ * @see #getLineMetrics(int)
+ */
+public void setAscent(int ascent) {
+ checkLayout();
+ if (ascent < -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (this.ascent == ascent) return;
+ freeRuns();
+ this.ascent = ascent;
+}
+
+/**
+ * Sets the descent of the receiver. The descent is distance in pixels
+ * from the baseline to the bottom of the line and it is applied to all
+ * lines. The default value is <code>-1</code> which means that the
+ * descent is calculated from the line fonts.
+ *
+ * @param descent the new descent
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the descent is less than <code>-1</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setAscent(int)
+ * @see #getLineMetrics(int)
+ */
+public void setDescent(int descent) {
+ checkLayout();
+ if (descent < -1) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (this.descent == descent) return;
+ freeRuns();
+ this.descent = descent;
+}
+
+/**
+ * Sets the default font which will be used by the receiver
+ * to draw and measure text. If the
+ * argument is null, then a default font appropriate
+ * for the platform will be used instead. Note that a text
+ * style can override the default font.
+ *
+ * @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 SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setFont (Font font) {
+ checkLayout();
+ if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ Font oldFont = this.font;
+ if (oldFont == font) return;
+ this.font = font;
+ if (oldFont != null && oldFont.equals(font)) return;
+ freeRuns();
+}
+
+/**
+ * Sets the indent of the receiver. This indent it applied of the first line of
+ * each paragraph.
+ *
+ * @param indent new indent
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.2
+ */
+public void setIndent (int indent) {
+ checkLayout();
+ if (indent < 0) return;
+ if (this.indent == indent) return;
+ freeRuns();
+ this.indent = indent;
+}
+
+/**
+ * Sets the justification of the receiver. Note that the receiver's
+ * width must be set in order to use justification.
+ *
+ * @param justify new justify
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.2
+ */
+public void setJustify (boolean justify) {
+ checkLayout();
+ if (this.justify == justify) return;
+ freeRuns();
+ this.justify = justify;
+}
+
+/**
+ * Sets the orientation of the receiver, which must be one
+ * of <code>SWT.LEFT_TO_RIGHT</code> or <code>SWT.RIGHT_TO_LEFT</code>.
+ *
+ * @param orientation new orientation style
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setOrientation (int orientation) {
+ checkLayout();
+ int mask = SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
+ orientation &= mask;
+ if (orientation == 0) return;
+ if ((orientation & SWT.LEFT_TO_RIGHT) != 0) orientation = SWT.LEFT_TO_RIGHT;
+ if (this.orientation == orientation) return;
+ this.orientation = orientation;
+ freeRuns();
+}
+
+/**
+ * Sets the offsets of the receiver's text segments. Text segments are used to
+ * override the default behaviour of the bidirectional algorithm.
+ * Bidirectional reordering can happen within a text segment but not
+ * between two adjacent segments.
+ * <p>
+ * Each text segment is determined by two consecutive offsets in the
+ * <code>segments</code> arrays. The first element of the array should
+ * always be zero and the last one should always be equals to length of
+ * the text.
+ * </p>
+ *
+ * @param segments the text segments offset
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setSegments(int[] segments) {
+ checkLayout();
+ if (this.segments == null && segments == null) return;
+ if (this.segments != null && segments != null) {
+ if (this.segments.length == segments.length) {
+ int i;
+ for (i = 0; i <segments.length; i++) {
+ if (this.segments[i] != segments[i]) break;
+ }
+ if (i == segments.length) return;
+ }
+ }
+ freeRuns();
+ this.segments = segments;
+}
+
+/**
+ * Sets the line spacing of the receiver. The line spacing
+ * is the space left between lines.
+ *
+ * @param spacing the new line spacing
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the spacing is negative</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setSpacing (int spacing) {
+ checkLayout();
+ if (spacing < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (this.lineSpacing == spacing) return;
+ freeRuns();
+ this.lineSpacing = spacing;
+}
+
+/**
+ * Sets the style of the receiver for the specified range. Styles previously
+ * set for that range will be overwritten. The start and end offsets are
+ * inclusive and will be clamped if out of range.
+ *
+ * @param style the style
+ * @param start the start offset
+ * @param end the end offset
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setStyle (TextStyle style, int start, int end) {
+ checkLayout();
+ int length = text.length();
+ if (length == 0) return;
+ if (start > end) return;
+ start = Math.min(Math.max(0, start), length - 1);
+ end = Math.min(Math.max(0, end), length - 1);
+ int low = -1;
+ int high = stylesCount;
+ while (high - low > 1) {
+ int index = (high + low) / 2;
+ if (styles[index + 1].start > start) {
+ high = index;
+ } else {
+ low = index;
+ }
+ }
+ if (0 <= high && high < stylesCount) {
+ StyleItem item = styles[high];
+ if (item.start == start && styles[high + 1].start - 1 == end) {
+ if (style == null) {
+ if (item.style == null) return;
+ } else {
+ if (style.equals(item.style)) return;
+ }
+ }
+ }
+ freeRuns();
+ int modifyStart = high;
+ int modifyEnd = modifyStart;
+ while (modifyEnd < stylesCount) {
+ if (styles[modifyEnd + 1].start > end) break;
+ modifyEnd++;
+ }
+ if (modifyStart == modifyEnd) {
+ int styleStart = styles[modifyStart].start;
+ int styleEnd = styles[modifyEnd + 1].start - 1;
+ if (styleStart == start && styleEnd == end) {
+ styles[modifyStart].style = style;
+ return;
+ }
+ if (styleStart != start && styleEnd != end) {
+ int newLength = stylesCount + 2;
+ if (newLength > styles.length) {
+ int newSize = Math.min(newLength + 1024, Math.max(64, newLength * 2));
+ StyleItem[] newStyles = new StyleItem[newSize];
+ System.arraycopy(styles, 0, newStyles, 0, stylesCount);
+ styles = newStyles;
+ }
+ System.arraycopy(styles, modifyEnd + 1, styles, modifyEnd + 3, stylesCount - modifyEnd - 1);
+ StyleItem item = new StyleItem();
+ item.start = start;
+ item.style = style;
+ styles[modifyStart + 1] = item;
+ item = new StyleItem();
+ item.start = end + 1;
+ item.style = styles[modifyStart].style;
+ styles[modifyStart + 2] = item;
+ stylesCount = newLength;
+ return;
+ }
+ }
+ if (start == styles[modifyStart].start) modifyStart--;
+ if (end == styles[modifyEnd + 1].start - 1) modifyEnd++;
+ int newLength = stylesCount + 1 - (modifyEnd - modifyStart - 1);
+ if (newLength > styles.length) {
+ int newSize = Math.min(newLength + 1024, Math.max(64, newLength * 2));
+ StyleItem[] newStyles = new StyleItem[newSize];
+ System.arraycopy(styles, 0, newStyles, 0, stylesCount);
+ styles = newStyles;
+ }
+ System.arraycopy(styles, modifyEnd, styles, modifyStart + 2, stylesCount - modifyEnd);
+ StyleItem item = new StyleItem();
+ item.start = start;
+ item.style = style;
+ styles[modifyStart + 1] = item;
+ styles[modifyStart + 2].start = end + 1;
+ stylesCount = newLength;
+}
+
+/**
+ * Sets the receiver's tab list. Each value in the tab list specifies
+ * the space in pixels from the origin of the text layout to the respective
+ * tab stop. The last tab stop width is repeated continuously.
+ *
+ * @param tabs the new tab list
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setTabs (int[] tabs) {
+ checkLayout();
+ if (this.tabs == null && tabs == null) return;
+ if (this.tabs != null && tabs !=null) {
+ if (this.tabs.length == tabs.length) {
+ int i;
+ for (i = 0; i <tabs.length; i++) {
+ if (this.tabs[i] != tabs[i]) break;
+ }
+ if (i == tabs.length) return;
+ }
+ }
+ freeRuns();
+ this.tabs = tabs;
+}
+
+/**
+ * Sets the receiver's text.
+ *<p>
+ * Note: Setting the text also clears all the styles. This method
+ * returns without doing anything if the new text is the same as
+ * the current text.
+ * </p>
+ *
+ * @param text the new text
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the text is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setText (String text) {
+ checkLayout();
+ if (text == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (text.equals(this.text)) return;
+ freeRuns();
+ this.text = text;
+ styles = new StyleItem[2];
+ styles[0] = new StyleItem();
+ styles[1] = new StyleItem();
+ styles[1].start = text.length();
+ stylesCount = 2;
+}
+
+/**
+ * Sets the line width of the receiver, which determines how
+ * text should be wrapped and aligned. The default value is
+ * <code>-1</code> which means wrapping is disabled.
+ *
+ * @param width the new width
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_INVALID_ARGUMENT - if the width is <code>0</code> or less than <code>-1</code></li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @see #setAlignment(int)
+ */
+public void setWidth (int width) {
+ checkLayout();
+ if (width < -1 || width == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ if (this.wrapWidth == width) return;
+ freeRuns();
+ this.wrapWidth = width;
+}
+
+boolean shape (int /*long*/ hdc, StyleItem run, char[] chars, int[] glyphCount, int maxGlyphs, SCRIPT_PROPERTIES sp) {
+ boolean useCMAPcheck = !sp.fComplex && !run.analysis.fNoGlyphIndex;
+ if (useCMAPcheck) {
+ short[] glyphs = new short[chars.length];
+ if (OS.ScriptGetCMap(hdc, run.psc, chars, chars.length, 0, glyphs) != OS.S_OK) {
+ if (run.psc != 0) {
+ OS.ScriptFreeCache(run.psc);
+ glyphCount[0] = 0;
+ OS.MoveMemory(run.psc, new int /*long*/ [1], OS.PTR_SIZEOF);
+ }
+ return false;
+ }
+ }
+ int hr = OS.ScriptShape(hdc, run.psc, chars, chars.length, maxGlyphs, run.analysis, run.glyphs, run.clusters, run.visAttrs, glyphCount);
+ run.glyphCount = glyphCount[0];
+ if (useCMAPcheck) return true;
+
+ if (hr != OS.USP_E_SCRIPT_NOT_IN_FONT) {
+ if (run.analysis.fNoGlyphIndex) return true;
+ SCRIPT_FONTPROPERTIES fp = new SCRIPT_FONTPROPERTIES ();
+ fp.cBytes = SCRIPT_FONTPROPERTIES.sizeof;
+ OS.ScriptGetFontProperties(hdc, run.psc, fp);
+ short[] glyphs = new short[glyphCount[0]];
+ OS.MoveMemory(glyphs, run.glyphs, glyphs.length * 2);
+ int i;
+ for (i = 0; i < glyphs.length; i++) {
+ if (glyphs[i] == fp.wgDefault) break;
+ }
+ if (i == glyphs.length) return true;
+ }
+ if (run.psc != 0) {
+ OS.ScriptFreeCache(run.psc);
+ glyphCount[0] = 0;
+ OS.MoveMemory(run.psc, new int /*long*/ [1], OS.PTR_SIZEOF);
+ }
+ run.glyphCount = 0;
+ return false;
+}
+
+/*
+ * Generate glyphs for one Run.
+ */
+void shape (final int /*long*/ hdc, final StyleItem run) {
+ if (run.tab || run.lineBreak) return;
+ if (run.glyphs != 0) return;
+ final int[] buffer = new int[1];
+ final char[] chars = new char[run.length];
+ segmentsText.getChars(run.start, run.start + run.length, chars, 0);
+
+ final int maxGlyphs = (chars.length * 3 / 2) + 16;
+ int /*long*/ hHeap = OS.GetProcessHeap();
+ run.glyphs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2);
+ if (run.glyphs == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ run.clusters = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * 2);
+ if (run.clusters == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ run.visAttrs = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, maxGlyphs * SCRIPT_VISATTR_SIZEOF);
+ if (run.visAttrs == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ run.psc = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, OS.PTR_SIZEOF);
+ if (run.psc == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ final short script = run.analysis.eScript;
+ final SCRIPT_PROPERTIES sp = new SCRIPT_PROPERTIES();
+ OS.MoveMemory(sp, device.scripts[script], SCRIPT_PROPERTIES.sizeof);
+ boolean shapeSucceed = shape(hdc, run, chars, buffer, maxGlyphs, sp);
+ if (!shapeSucceed) {
+ int /*long*/ hFont = OS.GetCurrentObject(hdc, OS.OBJ_FONT);
+ int /*long*/ newFont = 0;
+ /*
+ * Bug in Uniscribe. In some version of Uniscribe, ScriptStringAnalyse crashes
+ * when the character array is too long. The fix is to limit the size of character
+ * array to two. Note, limiting the array to only one character would cause surrogate
+ * pairs to stop working.
+ */
+ char[] sampleChars = new char[Math.min(chars.length, 2)];
+ SCRIPT_LOGATTR logAttr = new SCRIPT_LOGATTR();
+ breakRun(run);
+ int count = 0;
+ for (int i = 0; i < chars.length; i++) {
+ OS.MoveMemory(logAttr, run.psla + (i * SCRIPT_LOGATTR.sizeof), SCRIPT_LOGATTR.sizeof);
+ if (!logAttr.fWhiteSpace) {
+ sampleChars[count++] = chars[i];
+ if (count == sampleChars.length) break;
+ }
+ }
+ if (count > 0) {
+ int /*long*/ ssa = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, OS.SCRIPT_STRING_ANALYSIS_sizeof());
+ int /*long*/ metaFileDc = OS.CreateEnhMetaFile(hdc, null, null, null);
+ int /*long*/ oldMetaFont = OS.SelectObject(metaFileDc, hFont);
+ int flags = OS.SSA_METAFILE | OS.SSA_FALLBACK | OS.SSA_GLYPHS | OS.SSA_LINK;
+ if (OS.ScriptStringAnalyse(metaFileDc, sampleChars, count, 0, -1, flags, 0, null, null, 0, 0, 0, ssa) == OS.S_OK) {
+ OS.ScriptStringOut(ssa, 0, 0, 0, null, 0, 0, false);
+ OS.ScriptStringFree(ssa);
+ }
+ OS.HeapFree(hHeap, 0, ssa);
+ OS.SelectObject(metaFileDc, oldMetaFont);
+ int /*long*/ metaFile = OS.CloseEnhMetaFile(metaFileDc);
+ final EMREXTCREATEFONTINDIRECTW emr = new EMREXTCREATEFONTINDIRECTW();
+ class MetaFileEnumProc {
+ int /*long*/ metaFileEnumProc (int /*long*/ hDC, int /*long*/ table, int /*long*/ record, int /*long*/ nObj, int /*long*/ lpData) {
+ OS.MoveMemory(emr.emr, record, EMR.sizeof);
+ switch (emr.emr.iType) {
+ case OS.EMR_EXTCREATEFONTINDIRECTW:
+ OS.MoveMemory(emr, record, EMREXTCREATEFONTINDIRECTW.sizeof);
+ break;
+ case OS.EMR_EXTTEXTOUTW:
+ return 0;
+ }
+ return 1;
+ }
+ };
+ MetaFileEnumProc object = new MetaFileEnumProc();
+ /* Avoid compiler warnings */
+ boolean compilerWarningWorkaround = false;
+ if (compilerWarningWorkaround) object.metaFileEnumProc(0, 0, 0, 0, 0);
+ Callback callback = new Callback(object, "metaFileEnumProc", 5);
+ int /*long*/ address = callback.getAddress();
+ if (address == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
+ OS.EnumEnhMetaFile(0, metaFile, address, 0, null);
+ OS.DeleteEnhMetaFile(metaFile);
+ callback.dispose();
+ newFont = OS.CreateFontIndirectW(emr.elfw.elfLogFont);
+ } else {
+ /*
+ * The run is composed only by white spaces, this happens when a run is split
+ * by a visual style. The font fallback for the script can not be determined
+ * using only white spaces. The solution is to use the font fallback of the
+ * previous or next run of the same script.
+ */
+ int index = 0;
+ while (index < allRuns.length - 1) {
+ if (allRuns[index] == run) {
+ if (index > 0) {
+ StyleItem pRun = allRuns[index - 1];
+ if (pRun.fallbackFont != 0 && pRun.analysis.eScript == run.analysis.eScript) {
+ LOGFONT logFont = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA();
+ OS.GetObject(pRun.fallbackFont, LOGFONT.sizeof, logFont);
+ newFont = OS.CreateFontIndirect(logFont);
+ }
+ }
+ if (newFont == 0) {
+ if (index + 1 < allRuns.length - 1) {
+ StyleItem nRun = allRuns[index + 1];
+ if (nRun.analysis.eScript == run.analysis.eScript) {
+ shape(hdc, nRun);
+ if (nRun.fallbackFont != 0) {
+ LOGFONT logFont = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA();
+ OS.GetObject(nRun.fallbackFont, LOGFONT.sizeof, logFont);
+ newFont = OS.CreateFontIndirect(logFont);
+ }
+ }
+ }
+ }
+ break;
+ }
+ index++;
+ }
+ }
+ if (newFont != 0) {
+ OS.SelectObject(hdc, newFont);
+ if (shapeSucceed = shape(hdc, run, chars, buffer, maxGlyphs, sp)) {
+ run.fallbackFont = newFont;
+ }
+ }
+ if (!shapeSucceed) {
+ if (!sp.fComplex) {
+ run.analysis.fNoGlyphIndex = true;
+ if (shapeSucceed = shape(hdc, run, chars, buffer, maxGlyphs, sp)) {
+ run.fallbackFont = newFont;
+ } else {
+ run.analysis.fNoGlyphIndex = false;
+ }
+ }
+ }
+ if (!shapeSucceed) {
+ if (mLangFontLink2 != 0) {
+ int /*long*/[] hNewFont = new int /*long*/[1];
+ int[] dwCodePages = new int[1], cchCodePages = new int[1];
+ /* GetStrCodePages() */
+ OS.VtblCall(4, mLangFontLink2, chars, chars.length, 0, dwCodePages, cchCodePages);
+ /* MapFont() */
+ if (OS.VtblCall(10, mLangFontLink2, hdc, dwCodePages[0], chars[0], hNewFont) == OS.S_OK) {
+ LOGFONT logFont = OS.IsUnicode ? (LOGFONT)new LOGFONTW () : new LOGFONTA ();
+ OS.GetObject(hNewFont[0], LOGFONT.sizeof, logFont);
+ /* ReleaseFont() */
+ OS.VtblCall(8, mLangFontLink2, hNewFont[0]);
+ int /*long*/ mLangFont = OS.CreateFontIndirect(logFont);
+ int /*long*/ oldFont = OS.SelectObject(hdc, mLangFont);
+ if (shapeSucceed = shape(hdc, run, chars, buffer, maxGlyphs, sp)) {
+ run.fallbackFont = mLangFont;
+ } else {
+ OS.SelectObject(hdc, oldFont);
+ OS.DeleteObject(mLangFont);
+ }
+ }
+ }
+ }
+ if (!shapeSucceed) OS.SelectObject(hdc, hFont);
+ if (newFont != 0 && newFont != run.fallbackFont) OS.DeleteObject(newFont);
+ }
+
+ if (!shapeSucceed) {
+ /*
+ * Shape Failed.
+ * Give up and shape the run with the default font.
+ * Missing glyphs typically will be represent as black boxes in the text.
+ */
+ OS.ScriptShape(hdc, run.psc, chars, chars.length, maxGlyphs, run.analysis, run.glyphs, run.clusters, run.visAttrs, buffer);
+ run.glyphCount = buffer[0];
+ }
+ int[] abc = new int[3];
+ run.advances = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, run.glyphCount * 4);
+ if (run.advances == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ run.goffsets = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, run.glyphCount * GOFFSET_SIZEOF);
+ if (run.goffsets == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ OS.ScriptPlace(hdc, run.psc, run.glyphs, run.glyphCount, run.visAttrs, run.analysis, run.advances, run.goffsets, abc);
+ run.width = abc[0] + abc[1] + abc[2];
+ TextStyle style = run.style;
+ if (style != null) {
+ OUTLINETEXTMETRIC lotm = null;
+ if (style.underline || style.strikeout) {
+ lotm = OS.IsUnicode ? (OUTLINETEXTMETRIC)new OUTLINETEXTMETRICW() : new OUTLINETEXTMETRICA();
+ if (OS.GetOutlineTextMetrics(hdc, OUTLINETEXTMETRIC.sizeof, lotm) == 0) {
+ lotm = null;
+ }
+ }
+ if (style.metrics != null) {
+ GlyphMetrics metrics = style.metrics;
+ /*
+ * Bug in Windows, on a Japanese machine, Uniscribe returns glyphcount
+ * equals zero for FFFC (possibly other unicode code points), the fix
+ * is to make sure the glyph is at least one pixel wide.
+ */
+ run.width = metrics.width * Math.max (1, run.glyphCount);
+ run.ascent = metrics.ascent;
+ run.descent = metrics.descent;
+ run.leading = 0;
+ } else {
+ TEXTMETRIC lptm = null;
+ if (lotm != null) {
+ lptm = OS.IsUnicode ? (TEXTMETRIC)((OUTLINETEXTMETRICW)lotm).otmTextMetrics : ((OUTLINETEXTMETRICA)lotm).otmTextMetrics;
+ } else {
+ lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
+ OS.GetTextMetrics(hdc, lptm);
+ }
+ run.ascent = lptm.tmAscent;
+ run.descent = lptm.tmDescent;
+ run.leading = lptm.tmInternalLeading;
+ }
+ if (lotm != null) {
+ run.underlinePos = lotm.otmsUnderscorePosition;
+ run.underlineThickness = Math.max(1, lotm.otmsUnderscoreSize);
+ run.strikeoutPos = lotm.otmsStrikeoutPosition;
+ run.strikeoutThickness = Math.max(1, lotm.otmsStrikeoutSize);
+ } else {
+ run.underlinePos = 1;
+ run.underlineThickness = 1;
+ run.strikeoutPos = run.ascent / 2;
+ run.strikeoutThickness = 1;
+ }
+ run.ascent += style.rise;
+ run.descent -= style.rise;
+ } else {
+ TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
+ OS.GetTextMetrics(hdc, lptm);
+ run.ascent = lptm.tmAscent;
+ run.descent = lptm.tmDescent;
+ run.leading = lptm.tmInternalLeading;
+ }
+}
+
+int validadeOffset(int offset, int step) {
+ offset += step;
+ if (segments != null && segments.length > 2) {
+ for (int i = 0; i < segments.length; i++) {
+ if (translateOffset(segments[i]) - 1 == offset) {
+ offset += step;
+ break;
+ }
+ }
+ }
+ return offset;
+}
+
+/**
+ * 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 "TextLayout {*DISPOSED*}";
+ return "TextLayout {}";
+}
+
+int translateOffset(int offset) {
+ if (segments == null) return offset;
+ int nSegments = segments.length;
+ if (nSegments <= 1) return offset;
+ int length = text.length();
+ if (length == 0) return offset;
+ if (nSegments == 2) {
+ if (segments[0] == 0 && segments[1] == length) return offset;
+ }
+ for (int i = 0; i < nSegments && offset - i >= segments[i]; i++) {
+ offset++;
+ }
+ return offset;
+}
+
+int untranslateOffset(int offset) {
+ if (segments == null) return offset;
+ int nSegments = segments.length;
+ if (nSegments <= 1) return offset;
+ int length = text.length();
+ if (length == 0) return offset;
+ if (nSegments == 2) {
+ if (segments[0] == 0 && segments[1] == length) return offset;
+ }
+ for (int i = 0; i < nSegments && offset > segments[i]; i++) {
+ offset--;
+ }
+ return offset;
+}
+}
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Transform.java b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Transform.java
new file mode 100644
index 0000000000..c4236ad294
--- /dev/null
+++ b/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/graphics/Transform.java
@@ -0,0 +1,369 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 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
+ *******************************************************************************/
+package org.eclipse.swt.graphics;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.internal.gdip.*;
+
+/**
+ * Instances of this class represent transformation matrices for
+ * points expressed as (x, y) pairs of floating point numbers.
+ * <p>
+ * Application code must explicitly invoke the <code>Transform.dispose()</code>
+ * method to release the operating system resources managed by each instance
+ * when those instances are no longer required.
+ * </p>
+ * <p>
+ * This class requires the operating system's advanced graphics subsystem
+ * which may not be available on some platforms.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: GraphicsExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ *
+ * @since 3.1
+ */
+public class Transform extends Resource {
+
+ /**
+ * the OS resource for the Transform
+ * (Warning: This field is platform dependent)
+ * <p>
+ * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
+ * public API. It is marked public only so that it can be shared
+ * within the packages provided by SWT. It is not available on all
+ * platforms and should never be accessed from application code.
+ * </p>
+ */
+ public int /*long*/ handle;
+
+/**
+ * Constructs a new identity Transform.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the Transform
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Transform (Device device) {
+ this(device, 1, 0, 0, 1, 0, 0);
+}
+
+/**
+ * Constructs a new Transform given an array of elements that represent the
+ * matrix that describes the transformation.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the Transform
+ * @param elements an array of floats that describe the transformation matrix
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device, or the elements array is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the elements array is too small to hold the matrix values</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Transform(Device device, float[] elements) {
+ this (device, checkTransform(elements)[0], elements[1], elements[2], elements[3], elements[4], elements[5]);
+}
+
+/**
+ * Constructs a new Transform given all of the elements that represent the
+ * matrix that describes the transformation.
+ * <p>
+ * This operation requires the operating system's advanced
+ * graphics subsystem which may not be available on some
+ * platforms.
+ * </p>
+ *
+ * @param device the device on which to allocate the Transform
+ * @param m11 the first element of the first row of the matrix
+ * @param m12 the second element of the first row of the matrix
+ * @param m21 the first element of the second row of the matrix
+ * @param m22 the second element of the second row of the matrix
+ * @param dx the third element of the first row of the matrix
+ * @param dy the third element of the second row of the matrix
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if device is null and there is no current device</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
+ * </ul>
+ * @exception SWTError <ul>
+ * <li>ERROR_NO_HANDLES if a handle for the Transform could not be obtained</li>
+ * </ul>
+ *
+ * @see #dispose()
+ */
+public Transform (Device device, float m11, float m12, float m21, float m22, float dx, float dy) {
+ super(device);
+ this.device.checkGDIP();
+ handle = Gdip.Matrix_new(m11, m12, m21, m22, dx, dy);
+ if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES);
+ init();
+}
+
+static float[] checkTransform(float[] elements) {
+ if (elements == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (elements.length < 6) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ return elements;
+}
+
+void destroy() {
+ Gdip.Matrix_delete(handle);
+ handle = 0;
+}
+
+/**
+ * Fills the parameter with the values of the transformation matrix
+ * that the receiver represents, in the order {m11, m12, m21, m22, dx, dy}.
+ *
+ * @param elements array to hold the matrix values
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
+ * <li>ERROR_INVALID_ARGUMENT - if the parameter is too small to hold the matrix values</li>
+ * </ul>
+ */
+public void getElements(float[] elements) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (elements == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (elements.length < 6) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ Gdip.Matrix_GetElements(handle, elements);
+}
+
+/**
+ * Modifies the receiver such that the matrix it represents becomes the
+ * identity matrix.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public void identity() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ Gdip.Matrix_SetElements(handle, 1, 0, 0, 1, 0, 0);
+}
+
+/**
+ * Modifies the receiver such that the matrix it represents becomes
+ * the mathematical inverse of the matrix it previously represented.
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * <li>ERROR_CANNOT_INVERT_MATRIX - if the matrix is not invertible</li>
+ * </ul>
+ */
+public void invert() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (Gdip.Matrix_Invert(handle) != 0) SWT.error(SWT.ERROR_CANNOT_INVERT_MATRIX);
+}
+
+/**
+ * Returns <code>true</code> if the Transform has been disposed,
+ * and <code>false</code> otherwise.
+ * <p>
+ * This method gets the dispose state for the Transform.
+ * When a Transform has been disposed, it is an error to
+ * invoke any other method using the Transform.
+ *
+ * @return <code>true</code> when the Transform is disposed, and <code>false</code> otherwise
+ */
+public boolean isDisposed() {
+ return handle == 0;
+}
+
+/**
+ * Returns <code>true</code> if the Transform represents the identity matrix
+ * and false otherwise.
+ *
+ * @return <code>true</code> if the receiver is an identity Transform, and <code>false</code> otherwise
+ */
+public boolean isIdentity() {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ return Gdip.Matrix_IsIdentity(handle);
+}
+
+/**
+ * Modifies the receiver such that the matrix it represents becomes the
+ * the result of multiplying the matrix it previously represented by the
+ * argument.
+ *
+ * @param matrix the matrix to multiply the receiver by
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ * @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>
+ */
+public void multiply(Transform matrix) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (matrix == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ if (matrix.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
+ Gdip.Matrix_Multiply(handle, matrix.handle, Gdip.MatrixOrderPrepend);
+}
+
+/**
+ * Modifies the receiver so that it represents a transformation that is
+ * equivalent to its previous transformation rotated by the specified angle.
+ * The angle is specified in degrees and for the identity transform 0 degrees
+ * is at the 3 o'clock position. A positive value indicates a clockwise rotation
+ * while a negative value indicates a counter-clockwise rotation.
+ *
+ * @param angle the angle to rotate the transformation by
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void rotate(float angle) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ Gdip.Matrix_Rotate(handle, angle, Gdip.MatrixOrderPrepend);
+}
+
+/**
+ * Modifies the receiver so that it represents a transformation that is
+ * equivalent to its previous transformation scaled by (scaleX, scaleY).
+ *
+ * @param scaleX the amount to scale in the X direction
+ * @param scaleY the amount to scale in the Y direction
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void scale(float scaleX, float scaleY) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ Gdip.Matrix_Scale(handle, scaleX, scaleY, Gdip.MatrixOrderPrepend);
+}
+
+/**
+ * Modifies the receiver to represent a new transformation given all of
+ * the elements that represent the matrix that describes that transformation.
+ *
+ * @param m11 the first element of the first row of the matrix
+ * @param m12 the second element of the first row of the matrix
+ * @param m21 the first element of the second row of the matrix
+ * @param m22 the second element of the second row of the matrix
+ * @param dx the third element of the first row of the matrix
+ * @param dy the third element of the second row of the matrix
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void setElements(float m11, float m12, float m21, float m22, float dx, float dy) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ Gdip.Matrix_SetElements(handle, m11, m12, m21, m22, dx, dy);
+}
+
+/**
+ * Modifies the receiver so that it represents a transformation that is
+ * equivalent to its previous transformation sheared by (shearX, shearY).
+ *
+ * @param shearX the shear factor in the X direction
+ * @param shearY the shear factor in the Y direction
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ *
+ * @since 3.4
+ */
+public void shear(float shearX, float shearY) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ Gdip.Matrix_Shear(handle, shearX, shearY, Gdip.MatrixOrderPrepend);
+}
+
+/**
+ * Given an array containing points described by alternating x and y values,
+ * modify that array such that each point has been replaced with the result of
+ * applying the transformation represented by the receiver to that point.
+ *
+ * @param pointArray an array of alternating x and y values to be transformed
+ *
+ * @exception IllegalArgumentException <ul>
+ * <li>ERROR_NULL_ARGUMENT - if the point array is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void transform(float[] pointArray) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
+ Gdip.Matrix_TransformPoints(handle, pointArray, pointArray.length / 2);
+}
+
+/**
+ * Modifies the receiver so that it represents a transformation that is
+ * equivalent to its previous transformation translated by (offsetX, offsetY).
+ *
+ * @param offsetX the distance to translate in the X direction
+ * @param offsetY the distance to translate in the Y direction
+ *
+ * @exception SWTException <ul>
+ * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
+ * </ul>
+ */
+public void translate(float offsetX, float offsetY) {
+ if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
+ Gdip.Matrix_Translate(handle, offsetX, offsetY, Gdip.MatrixOrderPrepend);
+}
+
+/**
+ * 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 "Transform {*DISPOSED*}";
+ float[] elements = new float[6];
+ getElements(elements);
+ return "Transform {" + elements [0] + "," + elements [1] + "," +elements [2] + "," +elements [3] + "," +elements [4] + "," +elements [5] + "}";
+}
+
+}