KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > graphics > GC


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.swt.graphics;
12
13
14 import org.eclipse.swt.internal.*;
15 import org.eclipse.swt.internal.gdip.*;
16 import org.eclipse.swt.internal.win32.*;
17 import org.eclipse.swt.*;
18
19 /**
20  * Class <code>GC</code> is where all of the drawing capabilities that are
21  * supported by SWT are located. Instances are used to draw on either an
22  * <code>Image</code>, a <code>Control</code>, or directly on a <code>Display</code>.
23  * <dl>
24  * <dt><b>Styles:</b></dt>
25  * <dd>LEFT_TO_RIGHT, RIGHT_TO_LEFT</dd>
26  * </dl>
27  *
28  * <p>
29  * The SWT drawing coordinate system is the two-dimensional space with the origin
30  * (0,0) at the top left corner of the drawing area and with (x,y) values increasing
31  * to the right and downward respectively.
32  * </p>
33  *
34  * <p>
35  * Application code must explicitly invoke the <code>GC.dispose()</code>
36  * method to release the operating system resources managed by each instance
37  * when those instances are no longer required. This is <em>particularly</em>
38  * important on Windows95 and Windows98 where the operating system has a limited
39  * number of device contexts available.
40  * </p>
41  *
42  * <p>
43  * Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified.
44  * </p>
45  *
46  * @see org.eclipse.swt.events.PaintEvent
47  */

48
49 public final class GC extends Resource {
50     
51     /**
52      * the handle to the OS device context
53      * (Warning: This field is platform dependent)
54      * <p>
55      * <b>IMPORTANT:</b> This field is <em>not</em> part of the SWT
56      * public API. It is marked public only so that it can be shared
57      * within the packages provided by SWT. It is not available on all
58      * platforms and should never be accessed from application code.
59      * </p>
60      */

61     public int handle;
62
63     Drawable drawable;
64     GCData data;
65
66     static final int FOREGROUND = 1 << 0;
67     static final int BACKGROUND = 1 << 1;
68     static final int FONT = 1 << 2;
69     static final int LINE_STYLE = 1 << 3;
70     static final int LINE_WIDTH = 1 << 4;
71     static final int LINE_CAP = 1 << 5;
72     static final int LINE_JOIN = 1 << 6;
73     static final int LINE_MITERLIMIT = 1 << 7;
74     static final int FOREGROUND_TEXT = 1 << 8;
75     static final int BACKGROUND_TEXT = 1 << 9;
76     static final int BRUSH = 1 << 10;
77     static final int PEN = 1 << 11;
78     static final int NULL_BRUSH = 1 << 12;
79     static final int NULL_PEN = 1 << 13;
80     static final int DRAW_OFFSET = 1 << 14;
81
82     static final int DRAW = FOREGROUND | LINE_STYLE | LINE_WIDTH | LINE_CAP | LINE_JOIN | LINE_MITERLIMIT | PEN | NULL_BRUSH | DRAW_OFFSET;
83     static final int FILL = BACKGROUND | BRUSH | NULL_PEN;
84
85     static final float[] LINE_DOT_ZERO = new float[]{3, 3};
86     static final float[] LINE_DASH_ZERO = new float[]{18, 6};
87     static final float[] LINE_DASHDOT_ZERO = new float[]{9, 6, 3, 6};
88     static final float[] LINE_DASHDOTDOT_ZERO = new float[]{9, 3, 3, 3, 3, 3};
89
90 /**
91  * Prevents uninitialized instances from being created outside the package.
92  */

93 GC() {
94 }
95
96 /**
97  * Constructs a new instance of this class which has been
98  * configured to draw on the specified drawable. Sets the
99  * foreground color, background color and font in the GC
100  * to match those in the drawable.
101  * <p>
102  * You must dispose the graphics context when it is no longer required.
103  * </p>
104  * @param drawable the drawable to draw on
105  * @exception IllegalArgumentException <ul>
106  * <li>ERROR_NULL_ARGUMENT - if the drawable is null</li>
107  * <li>ERROR_NULL_ARGUMENT - if there is no current device</li>
108  * <li>ERROR_INVALID_ARGUMENT
109  * - if the drawable is an image that is not a bitmap or an icon
110  * - if the drawable is an image or printer that is already selected
111  * into another graphics context</li>
112  * </ul>
113  * @exception SWTError <ul>
114  * <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li>
115  * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
116  * </ul>
117  */

118 public GC(Drawable drawable) {
119     this(drawable, SWT.NONE);
120 }
121
122 /**
123  * Constructs a new instance of this class which has been
124  * configured to draw on the specified drawable. Sets the
125  * foreground color, background color and font in the GC
126  * to match those in the drawable.
127  * <p>
128  * You must dispose the graphics context when it is no longer required.
129  * </p>
130  *
131  * @param drawable the drawable to draw on
132  * @param style the style of GC to construct
133  *
134  * @exception IllegalArgumentException <ul>
135  * <li>ERROR_NULL_ARGUMENT - if the drawable is null</li>
136  * <li>ERROR_NULL_ARGUMENT - if there is no current device</li>
137  * <li>ERROR_INVALID_ARGUMENT
138  * - if the drawable is an image that is not a bitmap or an icon
139  * - if the drawable is an image or printer that is already selected
140  * into another graphics context</li>
141  * </ul>
142  * @exception SWTError <ul>
143  * <li>ERROR_NO_HANDLES if a handle could not be obtained for GC creation</li>
144  * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
145  * </ul>
146  *
147  * @since 2.1.2
148  */

149 public GC(Drawable drawable, int style) {
150     if (drawable == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
151     GCData data = new GCData ();
152     data.style = checkStyle(style);
153     int hDC = drawable.internal_new_GC(data);
154     Device device = data.device;
155     if (device == null) device = Device.getDevice();
156     if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
157     this.device = data.device = device;
158     init (drawable, data, hDC);
159     if (device.tracking) device.new_Object(this);
160 }
161
162 static int checkStyle(int style) {
163     if ((style & SWT.LEFT_TO_RIGHT) != 0) style &= ~SWT.RIGHT_TO_LEFT;
164     return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT);
165 }
166
167 void checkGC(int mask) {
168     int state = data.state;
169     if ((state & mask) == mask) return;
170     state = (state ^ mask) & mask;
171     data.state |= mask;
172     int gdipGraphics = data.gdipGraphics;
173     if (gdipGraphics != 0) {
174         int pen = data.gdipPen;
175         float width = data.lineWidth;
176         if ((state & FOREGROUND) != 0 || (pen == 0 && (state & (LINE_WIDTH | LINE_STYLE | LINE_MITERLIMIT | LINE_JOIN | LINE_CAP)) != 0)) {
177             if (data.gdipFgBrush != 0) Gdip.SolidBrush_delete(data.gdipFgBrush);
178             data.gdipFgBrush = 0;
179             int brush;
180             Pattern pattern = data.foregroundPattern;
181             if (pattern != null) {
182                 brush = pattern.handle;
183                 if ((data.style & SWT.MIRRORED) != 0) {
184                     switch (Gdip.Brush_GetType(brush)) {
185                         case Gdip.BrushTypeTextureFill:
186                             brush = Gdip.Brush_Clone(brush);
187                             if (brush == 0) SWT.error(SWT.ERROR_NO_HANDLES);
188                             Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
189                             data.gdipFgBrush = brush;
190                     }
191                 }
192             } else {
193                 int foreground = data.foreground;
194                 int rgb = ((foreground >> 16) & 0xFF) | (foreground & 0xFF00) | ((foreground & 0xFF) << 16);
195                 int color = Gdip.Color_new(data.alpha << 24 | rgb);
196                 if (color == 0) SWT.error(SWT.ERROR_NO_HANDLES);
197                 brush = Gdip.SolidBrush_new(color);
198                 if (brush == 0) SWT.error(SWT.ERROR_NO_HANDLES);
199                 Gdip.Color_delete(color);
200                 data.gdipFgBrush = brush;
201             }
202             if (pen != 0) {
203                 Gdip.Pen_SetBrush(pen, brush);
204             } else {
205                 pen = data.gdipPen = Gdip.Pen_new(brush, width);
206             }
207         }
208         if ((state & LINE_WIDTH) != 0) {
209             Gdip.Pen_SetWidth(pen, width);
210             switch (data.lineStyle) {
211                 case SWT.LINE_CUSTOM:
212                     state |= LINE_STYLE;
213             }
214         }
215         if ((state & LINE_STYLE) != 0) {
216             float[] dashes = null;
217             float dashOffset = 0;
218             int dashStyle = Gdip.DashStyleSolid;
219             switch (data.lineStyle) {
220                 case SWT.LINE_SOLID: break;
221                 case SWT.LINE_DOT: dashStyle = Gdip.DashStyleDot; if (width == 0) dashes = LINE_DOT_ZERO; break;
222                 case SWT.LINE_DASH: dashStyle = Gdip.DashStyleDash; if (width == 0) dashes = LINE_DASH_ZERO; break;
223                 case SWT.LINE_DASHDOT: dashStyle = Gdip.DashStyleDashDot; if (width == 0) dashes = LINE_DASHDOT_ZERO; break;
224                 case SWT.LINE_DASHDOTDOT: dashStyle = Gdip.DashStyleDashDotDot; if (width == 0) dashes = LINE_DASHDOTDOT_ZERO; break;
225                 case SWT.LINE_CUSTOM: {
226                     if (data.lineDashes != null) {
227                         dashOffset = data.lineDashesOffset / Math.max (1, width);
228                         dashes = new float[data.lineDashes.length * 2];
229                         for (int i = 0; i < data.lineDashes.length; i++) {
230                             float dash = data.lineDashes[i] / Math.max (1, width);
231                             dashes[i] = dash;
232                             dashes[i + data.lineDashes.length] = dash;
233                         }
234                     }
235                 }
236             }
237             if (dashes != null) {
238                 Gdip.Pen_SetDashPattern(pen, dashes, dashes.length);
239                 Gdip.Pen_SetDashStyle(pen, Gdip.DashStyleCustom);
240                 Gdip.Pen_SetDashOffset(pen, dashOffset);
241             } else {
242                 Gdip.Pen_SetDashStyle(pen, dashStyle);
243             }
244         }
245         if ((state & LINE_MITERLIMIT) != 0) {
246             Gdip.Pen_SetMiterLimit(pen, data.lineMiterLimit);
247         }
248         if ((state & LINE_JOIN) != 0) {
249             int joinStyle = 0;
250             switch (data.lineJoin) {
251                 case SWT.JOIN_MITER: joinStyle = Gdip.LineJoinMiter; break;
252                 case SWT.JOIN_BEVEL: joinStyle = Gdip.LineJoinBevel; break;
253                 case SWT.JOIN_ROUND: joinStyle = Gdip.LineJoinRound; break;
254             }
255             Gdip.Pen_SetLineJoin(pen, joinStyle);
256         }
257         if ((state & LINE_CAP) != 0) {
258             int dashCap = Gdip.DashCapFlat, capStyle = 0;
259             switch (data.lineCap) {
260                 case SWT.CAP_FLAT: capStyle = Gdip.LineCapFlat; break;
261                 case SWT.CAP_ROUND: capStyle = Gdip.LineCapRound; dashCap = Gdip.DashCapRound; break;
262                 case SWT.CAP_SQUARE: capStyle = Gdip.LineCapSquare; break;
263             }
264             Gdip.Pen_SetLineCap(pen, capStyle, capStyle, dashCap);
265         }
266         if ((state & BACKGROUND) != 0) {
267             if (data.gdipBgBrush != 0) Gdip.SolidBrush_delete(data.gdipBgBrush);
268             data.gdipBgBrush = 0;
269             Pattern pattern = data.backgroundPattern;
270             if (pattern != null) {
271                 data.gdipBrush = pattern.handle;
272                 if ((data.style & SWT.MIRRORED) != 0) {
273                     switch (Gdip.Brush_GetType(data.gdipBrush)) {
274                         case Gdip.BrushTypeTextureFill:
275                             int brush = Gdip.Brush_Clone(data.gdipBrush);
276                             if (brush == 0) SWT.error(SWT.ERROR_NO_HANDLES);
277                             Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
278                             data.gdipBrush = data.gdipBgBrush = brush;
279                     }
280                 }
281             } else {
282                 int background = data.background;
283                 int rgb = ((background >> 16) & 0xFF) | (background & 0xFF00) | ((background & 0xFF) << 16);
284                 int color = Gdip.Color_new(data.alpha << 24 | rgb);
285                 if (color == 0) SWT.error(SWT.ERROR_NO_HANDLES);
286                 int brush = Gdip.SolidBrush_new(color);
287                 if (brush == 0) SWT.error(SWT.ERROR_NO_HANDLES);
288                 Gdip.Color_delete(color);
289                 data.gdipBrush = data.gdipBgBrush = brush;
290             }
291         }
292         if ((state & FONT) != 0) {
293             OS.SelectObject(handle, data.hFont);
294             int font = createGdipFont(handle, data.hFont);
295             if (data.gdipFont != 0) Gdip.Font_delete(data.gdipFont);
296             data.gdipFont = font;
297         }
298         if ((state & DRAW_OFFSET) != 0) {
299             data.gdipXOffset = data.gdipYOffset = 0;
300             int matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
301             float[] elements = new float[6];
302             Gdip.Graphics_GetTransform(gdipGraphics, matrix);
303             Gdip.Matrix_GetElements(matrix, elements);
304             Gdip.Matrix_delete(matrix);
305             float scaling = elements[0];
306             if (scaling < 0) scaling = -scaling;
307             float penWidth = data.lineWidth * scaling;
308             if (penWidth == 0 || ((int)penWidth % 2) == 1) {
309                 data.gdipXOffset = 0.5f / scaling;
310             }
311             scaling = elements[3];
312             if (scaling < 0) scaling = -scaling;
313             penWidth = data.lineWidth * scaling;
314             if (penWidth == 0 || ((int)penWidth % 2) == 1) {
315                 data.gdipYOffset = 0.5f / scaling;
316             }
317         }
318         return;
319     }
320     if ((state & (FOREGROUND | LINE_CAP | LINE_JOIN | LINE_STYLE | LINE_WIDTH)) != 0) {
321         int color = data.foreground;
322         int width = (int)data.lineWidth;
323         int[] dashes = null;
324         int lineStyle = OS.PS_SOLID;
325         switch (data.lineStyle) {
326             case SWT.LINE_SOLID: break;
327             case SWT.LINE_DASH: lineStyle = OS.PS_DASH; break;
328             case SWT.LINE_DOT: lineStyle = OS.PS_DOT; break;
329             case SWT.LINE_DASHDOT: lineStyle = OS.PS_DASHDOT; break;
330             case SWT.LINE_DASHDOTDOT: lineStyle = OS.PS_DASHDOTDOT; break;
331             case SWT.LINE_CUSTOM: {
332                 if (data.lineDashes != null) {
333                     lineStyle = OS.PS_USERSTYLE;
334                     dashes = new int[data.lineDashes.length];
335                     for (int i = 0; i < dashes.length; i++) {
336                         dashes[i] = (int)data.lineDashes[i];
337                     }
338                 }
339                 break;
340             }
341         }
342         if ((state & LINE_STYLE) != 0) {
343             OS.SetBkMode(handle, data.lineStyle == SWT.LINE_SOLID ? OS.OPAQUE : OS.TRANSPARENT);
344         }
345         int joinStyle = 0;
346         switch (data.lineJoin) {
347             case SWT.JOIN_MITER: joinStyle = OS.PS_JOIN_MITER; break;
348             case SWT.JOIN_ROUND: joinStyle = OS.PS_JOIN_ROUND; break;
349             case SWT.JOIN_BEVEL: joinStyle = OS.PS_JOIN_BEVEL; break;
350         }
351         int capStyle = 0;
352         switch (data.lineCap) {
353             case SWT.CAP_ROUND: capStyle = OS.PS_ENDCAP_ROUND; break;
354             case SWT.CAP_FLAT: capStyle = OS.PS_ENDCAP_FLAT; break;
355             case SWT.CAP_SQUARE: capStyle = OS.PS_ENDCAP_SQUARE;break;
356         }
357         int style = lineStyle | joinStyle | capStyle;
358         /*
359         * Feature in Windows. Windows does not honour line styles other then
360         * PS_SOLID for pens wider than 1 pixel created with CreatePen(). The fix
361         * is to use ExtCreatePen() instead.
362         */

363         int newPen;
364         if (OS.IsWinCE || (width == 0 && lineStyle != OS.PS_USERSTYLE) || style == 0) {
365             newPen = OS.CreatePen(style & OS.PS_STYLE_MASK, width, color);
366         } else {
367             LOGBRUSH logBrush = new LOGBRUSH();
368             logBrush.lbStyle = OS.BS_SOLID;
369             logBrush.lbColor = color;
370             /* Feature in Windows. PS_GEOMETRIC pens cannot have zero width. */
371             newPen = OS.ExtCreatePen (style | OS.PS_GEOMETRIC, Math.max(1, width), logBrush, dashes != null ? dashes.length : 0, dashes);
372         }
373         OS.SelectObject(handle, newPen);
374         data.state |= PEN;
375         data.state &= ~NULL_PEN;
376         if (data.hPen != 0) OS.DeleteObject(data.hPen);
377         data.hPen = data.hOldPen = newPen;
378     } else if ((state & PEN) != 0) {
379         OS.SelectObject(handle, data.hOldPen);
380         data.state &= ~NULL_PEN;
381     } else if ((state & NULL_PEN) != 0) {
382         data.hOldPen = OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN));
383         data.state &= ~PEN;
384     }
385     if ((state & BACKGROUND) != 0) {
386         int newBrush = OS.CreateSolidBrush(data.background);
387         OS.SelectObject(handle, newBrush);
388         data.state |= BRUSH;
389         data.state &= ~NULL_BRUSH;
390         if (data.hBrush != 0) OS.DeleteObject(data.hBrush);
391         data.hOldBrush = data.hBrush = newBrush;
392     } else if ((state & BRUSH) != 0) {
393         OS.SelectObject(handle, data.hOldBrush);
394         data.state &= ~NULL_BRUSH;
395     } else if ((state & NULL_BRUSH) != 0) {
396         data.hOldBrush = OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH));
397         data.state &= ~BRUSH;
398     }
399     if ((state & BACKGROUND_TEXT) != 0) {
400         OS.SetBkColor(handle, data.background);
401     }
402     if ((state & FOREGROUND_TEXT) != 0) {
403         OS.SetTextColor(handle, data.foreground);
404     }
405     if ((state & FONT) != 0) {
406         OS.SelectObject(handle, data.hFont);
407     }
408 }
409
410 /**
411  * Copies a rectangular area of the receiver at the specified
412  * position into the image, which must be of type <code>SWT.BITMAP</code>.
413  *
414  * @param image the image to copy into
415  * @param x the x coordinate in the receiver of the area to be copied
416  * @param y the y coordinate in the receiver of the area to be copied
417  *
418  * @exception IllegalArgumentException <ul>
419  * <li>ERROR_NULL_ARGUMENT - if the image is null</li>
420  * <li>ERROR_INVALID_ARGUMENT - if the image is not a bitmap or has been disposed</li>
421  * </ul>
422  * @exception SWTException <ul>
423  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
424  * </ul>
425  */

426 public void copyArea(Image image, int x, int y) {
427     if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
428     if (image == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
429     if (image.type != SWT.BITMAP || image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
430
431     /* Copy the bitmap area */
432     Rectangle rect = image.getBounds();
433     int memHdc = OS.CreateCompatibleDC(handle);
434     int hOldBitmap = OS.SelectObject(memHdc, image.handle);
435     OS.BitBlt(memHdc, 0, 0, rect.width, rect.height, handle, x, y, OS.SRCCOPY);
436     OS.SelectObject(memHdc, hOldBitmap);
437     OS.DeleteDC(memHdc);
438 }
439
440 /**
441  * Copies a rectangular area of the receiver at the source
442  * position onto the receiver at the destination position.
443  *
444  * @param srcX the x coordinate in the receiver of the area to be copied
445  * @param srcY the y coordinate in the receiver of the area to be copied
446  * @param width the width of the area to copy
447  * @param height the height of the area to copy
448  * @param destX the x coordinate in the receiver of the area to copy to
449  * @param destY the y coordinate in the receiver of the area to copy to
450  *
451  * @exception SWTException <ul>
452  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
453  * </ul>
454  */

455 public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY) {
456     copyArea(srcX, srcY, width, height, destX, destY, true);
457 }
458
459 /**
460  * Copies a rectangular area of the receiver at the source
461  * position onto the receiver at the destination position.
462  *
463  * @param srcX the x coordinate in the receiver of the area to be copied
464  * @param srcY the y coordinate in the receiver of the area to be copied
465  * @param width the width of the area to copy
466  * @param height the height of the area to copy
467  * @param destX the x coordinate in the receiver of the area to copy to
468  * @param destY the y coordinate in the receiver of the area to copy to
469  * @param paint if <code>true</code> paint events will be generated for old and obscured areas
470  *
471  * @exception SWTException <ul>
472  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
473  * </ul>
474  *
475  * @since 3.1
476  */

477 public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY, boolean paint) {
478     if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
479
480     /*
481     * Feature in WinCE. The function WindowFromDC is not part of the
482     * WinCE SDK. The fix is to remember the HWND.
483     */

484     int hwnd = data.hwnd;
485     if (hwnd == 0) {
486         OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY);
487     } else {
488         RECT lprcClip = null;
489         int hrgn = OS.CreateRectRgn(0, 0, 0, 0);
490         if (OS.GetClipRgn(handle, hrgn) == 1) {
491             lprcClip = new RECT();
492             OS.GetRgnBox(hrgn, lprcClip);
493         }
494         OS.DeleteObject(hrgn);
495         RECT lprcScroll = new RECT();
496         OS.SetRect(lprcScroll, srcX, srcY, srcX + width, srcY + height);
497         int flags = paint ? OS.SW_INVALIDATE | OS.SW_ERASE : 0;
498         int res = OS.ScrollWindowEx(hwnd, destX - srcX, destY - srcY, lprcScroll, lprcClip, 0, null, flags);
499
500         /*
501         * Feature in WinCE. ScrollWindowEx does not accept combined
502         * vertical and horizontal scrolling. The fix is to do a
503         * BitBlt and invalidate the appropriate source area.
504         */

505         if (res == 0 && OS.IsWinCE) {
506             OS.BitBlt(handle, destX, destY, width, height, handle, srcX, srcY, OS.SRCCOPY);
507             if (paint) {
508                 int deltaX = destX - srcX, deltaY = destY - srcY;
509                 boolean disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY);
510                 if (disjoint) {
511                     OS.InvalidateRect(hwnd, lprcScroll, true);
512                 } else {
513                     if (deltaX != 0) {
514                         int newX = destX - deltaX;
515                         if (deltaX < 0) newX = destX + width;
516                         OS.SetRect(lprcScroll, newX, srcY, newX + Math.abs(deltaX), srcY + height);
517                         OS.InvalidateRect(hwnd, lprcScroll, true);
518                     }
519                     if (deltaY != 0) {
520                         int newY = destY - deltaY;
521                         if (deltaY < 0) newY = destY + height;
522                         OS.SetRect(lprcScroll, srcX, newY, srcX + width, newY + Math.abs(deltaY));
523                         OS.InvalidateRect(hwnd, lprcScroll, true);
524                     }
525                 }
526             }
527         }
528     }
529 }
530
531 static int createGdipFont(int hDC, int hFont) {
532     int font = Gdip.Font_new(hDC, hFont);
533     if (font == 0) SWT.error(SWT.ERROR_NO_HANDLES);
534     if (!Gdip.Font_IsAvailable(font)) {
535         Gdip.Font_delete(font);
536         LOGFONT logFont = OS.IsUnicode ? (LOGFONT)new LOGFONTW() : new LOGFONTA();
537         OS.GetObject(hFont, LOGFONT.sizeof, logFont);
538         int size = Math.abs(logFont.lfHeight);
539         int style = Gdip.FontStyleRegular;
540         if (logFont.lfWeight == 700) style |= Gdip.FontStyleBold;
541         if (logFont.lfItalic != 0) style |= Gdip.FontStyleItalic;
542         char[] chars;
543         if (OS.IsUnicode) {
544             chars = ((LOGFONTW)logFont).lfFaceName;
545         } else {
546             chars = new char[OS.LF_FACESIZE];
547             byte[] bytes = ((LOGFONTA)logFont).lfFaceName;
548             OS.MultiByteToWideChar (OS.CP_ACP, OS.MB_PRECOMPOSED, bytes, bytes.length, chars, chars.length);
549         }
550         int index = 0;
551         while (index < chars.length) {
552             if (chars [index] == 0) break;
553             index++;
554         }
555         String JavaDoc name = new String JavaDoc (chars, 0, index);
556         if (Compatibility.equalsIgnoreCase(name, "Courier")) { //$NON-NLS-1$
557
name = "Courier New"; //$NON-NLS-1$
558
}
559         char[] buffer = new char[name.length() + 1];
560         name.getChars(0, name.length(), buffer, 0);
561         font = Gdip.Font_new(buffer, size, style, Gdip.UnitPixel, 0);
562     }
563     if (font == 0) SWT.error(SWT.ERROR_NO_HANDLES);
564     return font;
565 }
566
567 static void destroyGdipBrush(int brush) {
568     int type = Gdip.Brush_GetType(brush);
569     switch (type) {
570         case Gdip.BrushTypeSolidColor:
571             Gdip.SolidBrush_delete(brush);
572             break;
573         case Gdip.BrushTypeHatchFill:
574             Gdip.HatchBrush_delete(brush);
575             break;
576         case Gdip.BrushTypeLinearGradient:
577             Gdip.LinearGradientBrush_delete(brush);
578             break;
579         case Gdip.BrushTypeTextureFill:
580             Gdip.TextureBrush_delete(brush);
581             break;
582     }
583 }
584
585 /**
586  * Disposes of the operating system resources associated with
587  * the graphics context. Applications must dispose of all GCs
588  * which they allocate.
589  *
590  * @exception SWTError <ul>
591  * <li>ERROR_THREAD_INVALID_ACCESS if not called from the thread that created the drawable</li>
592  * </ul>
593  */

594 public void dispose() {
595     if (handle == 0) return;
596     if (data.device.isDisposed()) return;
597     
598     disposeGdip();
599
600     /* Select stock pen and brush objects and free resources */
601     if (data.hPen != 0) {
602         OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN));
603         OS.DeleteObject(data.hPen);
604         data.hPen = 0;
605     }
606     if (data.hBrush != 0) {
607         OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH));
608         OS.DeleteObject(data.hBrush);
609         data.hBrush = 0;
610     }
611     
612     /*
613     * Put back the original bitmap into the device context.
614     * This will ensure that we have not left a bitmap
615     * selected in it when we delete the HDC.
616     */

617     int hNullBitmap = data.hNullBitmap;
618     if (hNullBitmap != 0) {
619         OS.SelectObject(handle, hNullBitmap);
620         data.hNullBitmap = 0;
621     }
622     Image image = data.image;
623     if (image != null) image.memGC = null;
624     
625     /*
626     * Dispose the HDC.
627     */

628     Device device = data.device;
629     if (drawable != null) drawable.internal_dispose_GC(handle, data);
630     drawable = null;
631     handle = 0;
632     data.image = null;
633     data.ps = null;
634     if (device.tracking) device.dispose_Object(this);
635     data.device = null;
636     data = null;
637 }
638
639 void disposeGdip() {
640     if (data.gdipPen != 0) Gdip.Pen_delete(data.gdipPen);
641     if (data.gdipBgBrush != 0) destroyGdipBrush(data.gdipBgBrush);
642     if (data.gdipFgBrush != 0) destroyGdipBrush(data.gdipFgBrush);
643     if (data.gdipFont != 0) Gdip.Font_delete(data.gdipFont);
644     if (data.gdipGraphics != 0) Gdip.Graphics_delete(data.gdipGraphics);
645     data.gdipGraphics = data.gdipBrush = data.gdipBgBrush = data.gdipFgBrush =
646         data.gdipFont = data.gdipPen = 0;
647 }
648
649 /**
650  * Draws the outline of a circular or elliptical arc
651  * within the specified rectangular area.
652  * <p>
653  * The resulting arc begins at <code>startAngle</code> and extends
654  * for <code>arcAngle</code> degrees, using the current color.
655  * Angles are interpreted such that 0 degrees is at the 3 o'clock
656  * position. A positive value indicates a counter-clockwise rotation
657  * while a negative value indicates a clockwise rotation.
658  * </p><p>
659  * The center of the arc is the center of the rectangle whose origin
660  * is (<code>x</code>, <code>y</code>) and whose size is specified by the
661  * <code>width</code> and <code>height</code> arguments.
662  * </p><p>
663  * The resulting arc covers an area <code>width + 1</code> pixels wide
664  * by <code>height + 1</code> pixels tall.
665  * </p>
666  *
667  * @param x the x coordinate of the upper-left corner of the arc to be drawn
668  * @param y the y coordinate of the upper-left corner of the arc to be drawn
669  * @param width the width of the arc to be drawn
670  * @param height the height of the arc to be drawn
671  * @param startAngle the beginning angle
672  * @param arcAngle the angular extent of the arc, relative to the start angle
673  *
674  * @exception SWTException <ul>
675  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
676  * </ul>
677  */

678 public void drawArc (int x, int y, int width, int height, int startAngle, int arcAngle) {
679     if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
680     checkGC(DRAW);
681     if (width < 0) {
682         x = x + width;
683         width = -width;
684     }
685     if (height < 0) {
686         y = y + height;
687         height = -height;
688     }
689     if (width == 0 || height == 0 || arcAngle == 0) return;
690     int gdipGraphics = data.gdipGraphics;
691     if (gdipGraphics != 0) {
692         Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
693         if (width == height) {
694             Gdip.Graphics_DrawArc(gdipGraphics, data.gdipPen, x, y, width, height, -startAngle, -arcAngle);
695         } else {
696             int path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
697             if (path == 0) SWT.error(SWT.ERROR_NO_HANDLES);
698             int matrix = Gdip.Matrix_new(width, 0, 0, height, x, y);
699             if (matrix == 0) SWT.error(SWT.ERROR_NO_HANDLES);
700             Gdip.GraphicsPath_AddArc(path, 0, 0, 1, 1, -startAngle, -arcAngle);
701             Gdip.GraphicsPath_Transform(path, matrix);
702             Gdip.Graphics_DrawPath(gdipGraphics, data.gdipPen, path);
703             Gdip.Matrix_delete(matrix);
704             Gdip.GraphicsPath_delete(path);
705         }
706         Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
707         return;
708     }
709     if ((data.style & SWT.MIRRORED) != 0) {
710         if (data.lineWidth != 0 && data.lineWidth % 2 == 0) x--;
711     }
712     /*
713     * Feature in WinCE. The function Arc is not present in the
714     * WinCE SDK. The fix is to emulate arc drawing by using
715     * Polyline.
716     */

717     if (OS.IsWinCE) {
718         /* compute arc with a simple linear interpolation */
719         if (arcAngle < 0) {
720             startAngle += arcAngle;
721             arcAngle = -arcAngle;
722         }
723         if (arcAngle > 360) arcAngle = 360;
724         int[] points = new int[(arcAngle + 1) * 2];
725         int cteX = 2 * x + width;
726         int cteY = 2 * y + height;
727         int index = 0;
728         for (int i = 0; i <= arcAngle; i++) {
729             points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1;
730             points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1;
731         }
732         OS.Polyline(handle, points, points.length / 2);
733     } else {
734         int x1, y1, x2, y2,tmp;
735         boolean isNegative;
736         if (arcAngle >= 360 || arcAngle <= -360) {
737             x1 = x2 = x + width;
738             y1 = y2 = y + height / 2;
739         } else {
740             isNegative = arcAngle < 0;
741     
742             arcAngle = arcAngle + startAngle;
743             if (isNegative) {
744                 // swap angles
745
tmp = startAngle;
746                 startAngle = arcAngle;
747                 arcAngle = tmp;
748             }
749             x1 = Compatibility.cos(startAngle, width) + x + width/2;
750             y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2;
751             
752             x2 = Compatibility.cos(arcAngle, width) + x + width/2;
753             y2 = -1 * Compatibility.sin(arcAngle, height) + y + height/2;
754         }
755         OS.Arc(handle, x, y, x + width + 1, y + height + 1, x1, y1, x2, y2);
756     }
757 }
758
759 /**
760  * Draws a rectangle, based on the specified arguments, which has
761  * the appearance of the platform's <em>focus rectangle</em> if the
762  * platform supports such a notion, and otherwise draws a simple
763  * rectangle in the receiver's foreground color.
764  *
765  * @param x the x coordinate of the rectangle
766  * @param y the y coordinate of the rectangle
767  * @param width the width of the rectangle
768  * @param height the height of the rectangle
769  *
770  * @exception SWTException <ul>
771  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
772  * </ul>
773  *
774  * @see #drawRectangle(int, int, int, int)
775  */

776 public void drawFocus (int x, int y, int width, int height) {
777     if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
778     if ((data.uiState & OS.UISF_HIDEFOCUS) != 0) return;
779     int hdc = handle, state = 0;
780     int gdipGraphics = data.gdipGraphics;
781     if (gdipGraphics != 0) {
782         int clipRgn = 0;
783         Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone);
784         int rgn = Gdip.Region_new();
785         if (rgn == 0) SWT.error(SWT.ERROR_NO_HANDLES);
786         Gdip.Graphics_GetClip(gdipGraphics, rgn);
787         if (!Gdip.Region_IsInfinite(rgn, gdipGraphics)) {
788             clipRgn = Gdip.Region_GetHRGN(rgn, gdipGraphics);
789         }
790         Gdip.Region_delete(rgn);
791         Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf);
792         float[] lpXform = null;
793         int matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
794         if (matrix == 0) SWT.error(SWT.ERROR_NO_HANDLES);
795         Gdip.Graphics_GetTransform(gdipGraphics, matrix);
796         if (!Gdip.Matrix_IsIdentity(matrix)) {
797             lpXform = new float[6];
798             Gdip.Matrix_GetElements(matrix, lpXform);
799         }
800         Gdip.Matrix_delete(matrix);
801         hdc = Gdip.Graphics_GetHDC(gdipGraphics);
802         state = OS.SaveDC(hdc);
803         OS.SetBkColor(hdc, data.background);
804         OS.SetTextColor(hdc, data.foreground);
805         if (lpXform != null) {
806             OS.SetGraphicsMode(hdc, OS.GM_ADVANCED);
807             OS.SetWorldTransform(hdc, lpXform);
808         }
809         if (clipRgn != 0) {
810             OS.SelectClipRgn(hdc, clipRgn);
811             OS.DeleteObject(clipRgn);
812         }
813     }
814     RECT rect = new RECT();
815     OS.SetRect(rect, x, y, x + width, y + height);
816     OS.DrawFocusRect(hdc, rect);
817     if (gdipGraphics != 0) {
818         OS.RestoreDC(hdc, state);
819         Gdip.Graphics_ReleaseHDC(gdipGraphics, hdc);
820     }
821 }
822
823 /**
824  * Draws the given image in the receiver at the specified
825  * coordinates.
826  *
827  * @param image the image to draw
828  * @param x the x coordinate of where to draw
829  * @param y the y coordinate of where to draw
830  *
831  * @exception IllegalArgumentException <ul>
832  * <li>ERROR_NULL_ARGUMENT - if the image is null</li>
833  * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
834  * <li>ERROR_INVALID_ARGUMENT - if the given coordinates are outside the bounds of the image</li>
835  * @exception SWTException <ul>
836  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
837  * </ul>
838  * @exception SWTError <ul>
839  * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li>
840  * </ul>
841  */

842 public void drawImage(Image image, int x, int y) {
843     if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
844     if (image == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
845     if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
846     drawImage(image, 0, 0, -1, -1, x, y, -1, -1, true);
847 }
848
849 /**
850  * Copies a rectangular area from the source image into a (potentially
851  * different sized) rectangular area in the receiver. If the source
852  * and destination areas are of differing sizes, then the source
853  * area will be stretched or shrunk to fit the destination area
854  * as it is copied. The copy fails if any part of the source rectangle
855  * lies outside the bounds of the source image, or if any of the width
856  * or height arguments are negative.
857  *
858  * @param image the source image
859  * @param srcX the x coordinate in the source image to copy from
860  * @param srcY the y coordinate in the source image to copy from
861  * @param srcWidth the width in pixels to copy from the source
862  * @param srcHeight the height in pixels to copy from the source
863  * @param destX the x coordinate in the destination to copy to
864  * @param destY the y coordinate in the destination to copy to
865  * @param destWidth the width in pixels of the destination rectangle
866  * @param destHeight the height in pixels of the destination rectangle
867  *
868  * @exception IllegalArgumentException <ul>
869  * <li>ERROR_NULL_ARGUMENT - if the image is null</li>
870  * <li>ERROR_INVALID_ARGUMENT - if the image has been disposed</li>
871  * <li>ERROR_INVALID_ARGUMENT - if any of the width or height arguments are negative.
872  * <li>ERROR_INVALID_ARGUMENT - if the source rectangle is not contained within the bounds of the source image</li>
873  * </ul>
874  * @exception SWTException <ul>
875  * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
876  * </ul>
877  * @exception SWTError <ul>
878  * <li>ERROR_NO_HANDLES - if no handles are available to perform the operation</li>
879  * </ul>
880  */

881 public void drawImage(Image image, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) {
882     if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
883     if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) return;
884     if (srcX < 0 || srcY < 0 || srcWidth < 0 || srcHeight < 0 || destWidth < 0 || destHeight < 0) {
885         SWT.error (SWT.ERROR_INVALID_ARGUMENT);
886     }
887     if (image == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
888     if (image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
889     drawImage(image, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, false);
890 }
891
892 void drawImage(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
893     if (data.gdipGraphics != 0) {
894         //TODO - cache bitmap
895
int[] gdipImage = srcImage.createGdipImage();
896         int img = gdipImage[0];
897         int imgWidth = Gdip.Image_GetWidth(img);
898         int imgHeight = Gdip.Image_GetHeight(img);
899         if (simple) {
900             srcWidth = destWidth = imgWidth;
901             srcHeight = destHeight = imgHeight;
902         } else {
903             if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) {
904                 SWT.error (SWT.ERROR_INVALID_ARGUMENT);
905             }
906             simple = srcX == 0 && srcY == 0 &&
907                 srcWidth == destWidth && destWidth == imgWidth &&
908                 srcHeight == destHeight && destHeight == imgHeight;
909         }
910         Rect rect = new Rect();
911         rect.X = destX;
912         rect.Y = destY;
913         rect.Width = destWidth;
914         rect.Height = destHeight;
915         /*
916         * Note that if the wrap mode is not WrapModeTileFlipXY, the scaled image
917         * is translucent around the borders.
918         */

919         int attrib = Gdip.ImageAttributes_new();
920         Gdip.ImageAttributes_SetWrapMode(attrib, Gdip.WrapModeTileFlipXY);
921         if (data.alpha != 0xFF) {
922             float[] matrix = new float[]{
923                 1,0,0,0,0,
924                 0,1,0,0,0,
925                 0,0,1,0,0,
926                 0,0,0,data.alpha / (float)0xFF,0,
927                 0,0,0,0,1,
928             };
929             Gdip.ImageAttributes_SetColorMatrix(attrib, matrix, Gdip.ColorMatrixFlagsDefault, Gdip.ColorAdjustTypeBitmap);
930         }
931         int gstate = 0;
932         if ((data.style & SWT.MIRRORED) != 0) {
933             gstate = Gdip.Graphics_Save(data.gdipGraphics);
934             Gdip.Graphics_ScaleTransform(data.gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend);
935             Gdip.Graphics_TranslateTransform(data.gdipGraphics, - 2 * destX - destWidth, 0, Gdip.MatrixOrderPrepend);
936         }
937         Gdip.Graphics_DrawImage(data.gdipGraphics, img, rect, srcX, srcY, srcWidth, srcHeight, Gdip.UnitPixel, attrib, 0, 0);
938         if ((data.style & SWT.MIRRORED) != 0) {
939             Gdip.Graphics_Restore(data.gdipGraphics, gstate);
940         }
941         Gdip.ImageAttributes_delete(attrib);
942         Gdip.Bitmap_delete(img);
943         if (gdipImage[1] != 0) {
944             int hHeap = OS.GetProcessHeap ();
945             OS.HeapFree(hHeap, 0, gdipImage[1]);
946         }
947         return;
948     }
949     switch (srcImage.type) {
950         case SWT.BITMAP:
951             drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
952             break;
953         case SWT.ICON:
954             drawIcon(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple);
955             break;
956     }
957 }
958
959 void drawIcon(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
960     int technology = OS.GetDeviceCaps(handle, OS.TECHNOLOGY);
961
962     boolean drawIcon = true;
963     int flags = OS.DI_NORMAL;
964     int offsetX = 0, offsetY = 0;
965     if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(5, 1)) {
966         if ((OS.GetLayout(handle) & OS.LAYOUT_RTL) != 0) {
967             flags |= OS.DI_NOMIRROR;
968             /*
969             * Bug in Windows. For some reason, DrawIconEx() does not take
970             * into account the window origin when the DI_NOMIRROR and
971             * LAYOUT_RTL are set. The fix is to set the window origin to
972             * (0, 0) and offset the drawing ourselves.
973             */

974             POINT pt = new POINT();
975             OS.GetWindowOrgEx(handle, pt);
976             offsetX = pt.x;
977             offsetY = pt.y;
978         }
979     } else {
980         if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
981             drawIcon = (OS.GetLayout(handle) & OS.LAYOUT_RTL) == 0;
982         }
983     }
984
985     /* Simple case: no stretching, entire icon */
986     if (simple && technology != OS.DT_RASPRINTER && drawIcon) {
987         if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, 0, 0, null);
988         OS.DrawIconEx(handle, destX - offsetX, destY - offsetY, srcImage.handle, 0, 0, 0, 0, flags);
989         if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, offsetX, offsetY, null);
990         return;
991     }
992
993     /* Get the icon info */
994     ICONINFO srcIconInfo = new ICONINFO();
995     if (OS.IsWinCE) {
996         Image.GetIconInfo(srcImage, srcIconInfo);
997     } else {
998         OS.GetIconInfo(srcImage.handle, srcIconInfo);
999     }
1000
1001    /* Get the icon width and height */
1002    int hBitmap = srcIconInfo.hbmColor;
1003    if (hBitmap == 0) hBitmap = srcIconInfo.hbmMask;
1004    BITMAP bm = new BITMAP();
1005    OS.GetObject(hBitmap, BITMAP.sizeof, bm);
1006    int iconWidth = bm.bmWidth, iconHeight = bm.bmHeight;
1007    if (hBitmap == srcIconInfo.hbmMask) iconHeight /= 2;
1008    
1009    if (simple) {
1010        srcWidth = destWidth = iconWidth;
1011        srcHeight = destHeight = iconHeight;
1012    }
1013
1014    /* Draw the icon */
1015    boolean failed = srcX + srcWidth > iconWidth || srcY + srcHeight > iconHeight;
1016    if (!failed) {
1017        simple = srcX == 0 && srcY == 0 &&
1018            srcWidth == destWidth && srcHeight == destHeight &&
1019            srcWidth == iconWidth && srcHeight == iconHeight;
1020        if (!drawIcon) {
1021            drawBitmapMask(srcImage, srcIconInfo.hbmColor, srcIconInfo.hbmMask, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, iconWidth, iconHeight, false);
1022        } else if (simple && technology != OS.DT_RASPRINTER) {
1023            /* Simple case: no stretching, entire icon */
1024            if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, 0, 0, null);
1025            OS.DrawIconEx(handle, destX - offsetX, destY - offsetY, srcImage.handle, 0, 0, 0, 0, flags);
1026            if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, offsetX, offsetY, null);
1027        } else {
1028            /* Create the icon info and HDC's */
1029            ICONINFO newIconInfo = new ICONINFO();
1030            newIconInfo.fIcon = true;
1031            int srcHdc = OS.CreateCompatibleDC(handle);
1032            int dstHdc = OS.CreateCompatibleDC(handle);
1033                        
1034            /* Blt the color bitmap */
1035            int srcColorY = srcY;
1036            int srcColor = srcIconInfo.hbmColor;
1037            if (srcColor == 0) {
1038                srcColor = srcIconInfo.hbmMask;
1039                srcColorY += iconHeight;
1040            }
1041            int oldSrcBitmap = OS.SelectObject(srcHdc, srcColor);
1042            newIconInfo.hbmColor = OS.CreateCompatibleBitmap(srcHdc, destWidth, destHeight);
1043            if (newIconInfo.hbmColor == 0) SWT.error(SWT.ERROR_NO_HANDLES);
1044            int oldDestBitmap = OS.SelectObject(dstHdc, newIconInfo.hbmColor);
1045            boolean stretch = !simple && (srcWidth != destWidth || srcHeight != destHeight);
1046            if (stretch) {
1047                if (!OS.IsWinCE) OS.SetStretchBltMode(dstHdc, OS.COLORONCOLOR);
1048                OS.StretchBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCCOPY);
1049            } else {
1050                OS.BitBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcColorY, OS.SRCCOPY);
1051            }
1052            
1053            /* Blt the mask bitmap */
1054            OS.SelectObject(srcHdc, srcIconInfo.hbmMask);
1055            newIconInfo.hbmMask = OS.CreateBitmap(destWidth, destHeight, 1, 1, null);
1056            if (newIconInfo.hbmMask == 0) SWT.error(SWT.ERROR_NO_HANDLES);
1057            OS.SelectObject(dstHdc, newIconInfo.hbmMask);
1058            if (stretch) {
1059                OS.StretchBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCCOPY);
1060            } else {
1061                OS.BitBlt(dstHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCCOPY);
1062            }
1063            
1064            if (technology == OS.DT_RASPRINTER) {
1065                OS.SelectObject(srcHdc, newIconInfo.hbmColor);
1066                OS.SelectObject(dstHdc, newIconInfo.hbmMask);
1067                drawBitmapTransparentByClipping(srcHdc, dstHdc, 0, 0, destWidth, destHeight, destX, destY, destWidth, destHeight, true, destWidth, destHeight);
1068                OS.SelectObject(srcHdc, oldSrcBitmap);
1069                OS.SelectObject(dstHdc, oldDestBitmap);
1070            } else {
1071                OS.SelectObject(srcHdc, oldSrcBitmap);
1072                OS.SelectObject(dstHdc, oldDestBitmap);
1073                int hIcon = OS.CreateIconIndirect(newIconInfo);
1074                if (hIcon == 0) SWT.error(SWT.ERROR_NO_HANDLES);
1075                if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, 0, 0, null);
1076                OS.DrawIconEx(handle, destX - offsetX, destY - offsetY, hIcon, destWidth, destHeight, 0, 0, flags);
1077                if (offsetX != 0 || offsetY != 0) OS.SetWindowOrgEx(handle, offsetX, offsetY, null);
1078                OS.DestroyIcon(hIcon);
1079            }
1080            
1081            /* Destroy the new icon src and mask and hdc's*/
1082            OS.DeleteObject(newIconInfo.hbmMask);
1083            OS.DeleteObject(newIconInfo.hbmColor);
1084            OS.DeleteDC(dstHdc);
1085            OS.DeleteDC(srcHdc);
1086        }
1087    }
1088
1089    /* Free icon info */
1090    OS.DeleteObject(srcIconInfo.hbmMask);
1091    if (srcIconInfo.hbmColor != 0) {
1092        OS.DeleteObject(srcIconInfo.hbmColor);
1093    }
1094    
1095    if (failed) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1096}
1097
1098void drawBitmap(Image srcImage, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple) {
1099    BITMAP bm = new BITMAP();
1100    OS.GetObject(srcImage.handle, BITMAP.sizeof, bm);
1101    int imgWidth = bm.bmWidth;
1102    int imgHeight = bm.bmHeight;
1103    if (simple) {
1104        srcWidth = destWidth = imgWidth;
1105        srcHeight = destHeight = imgHeight;
1106    } else {
1107        if (srcX + srcWidth > imgWidth || srcY + srcHeight > imgHeight) {
1108            SWT.error (SWT.ERROR_INVALID_ARGUMENT);
1109        }
1110        simple = srcX == 0 && srcY == 0 &&
1111            srcWidth == destWidth && destWidth == imgWidth &&
1112            srcHeight == destHeight && destHeight == imgHeight;
1113    }
1114    boolean mustRestore = false;
1115    GC memGC = srcImage.memGC;
1116    if (memGC != null && !memGC.isDisposed()) {
1117        memGC.flush();
1118        mustRestore = true;
1119        GCData data = memGC.data;
1120        if (data.hNullBitmap != 0) {
1121            OS.SelectObject(memGC.handle, data.hNullBitmap);
1122            data.hNullBitmap = 0;
1123        }
1124    }
1125    if (srcImage.alpha != -1 || srcImage.alphaData != null) {
1126        drawBitmapAlpha(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
1127    } else if (srcImage.transparentPixel != -1) {
1128        drawBitmapTransparent(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
1129    } else {
1130        drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
1131    }
1132    if (mustRestore) {
1133        int hOldBitmap = OS.SelectObject(memGC.handle, srcImage.handle);
1134        memGC.data.hNullBitmap = hOldBitmap;
1135    }
1136}
1137
1138void 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) {
1139    /* Simple cases */
1140    if (srcImage.alpha == 0) return;
1141    if (srcImage.alpha == 255) {
1142        drawBitmap(srcImage, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, bm, imgWidth, imgHeight);
1143        return;
1144    }
1145
1146    if (OS.IsWinNT && OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
1147        BLENDFUNCTION blend = new BLENDFUNCTION();
1148        blend.BlendOp = OS.AC_SRC_OVER;
1149        int srcHdc = OS.CreateCompatibleDC(handle);
1150        int oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
1151        if (srcImage.alpha != -1) {
1152            blend.SourceConstantAlpha = (byte)srcImage.alpha;
1153            OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, blend);
1154        } else {
1155            int memDib = Image.createDIB(srcWidth, srcHeight, 32);
1156            if (memDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
1157            int memHdc = OS.CreateCompatibleDC(handle);
1158            int oldMemBitmap = OS.SelectObject(memHdc, memDib);
1159            BITMAP dibBM = new BITMAP();
1160            OS.GetObject(memDib, BITMAP.sizeof, dibBM);
1161            OS.BitBlt(memHdc, 0, 0, srcWidth, srcHeight, srcHdc, srcX, srcY, OS.SRCCOPY);
1162            byte[] srcData = new byte[dibBM.bmWidthBytes * dibBM.bmHeight];
1163            OS.MoveMemory(srcData, dibBM.bmBits, srcData.length);
1164            final int apinc = imgWidth - srcWidth;
1165            int ap = srcY * imgWidth + srcX, sp = 0;
1166            byte[] alphaData = srcImage.alphaData;
1167            for (int y = 0; y < srcHeight; ++y) {
1168                for (int x = 0; x < srcWidth; ++x) {
1169                    int alpha = alphaData[ap++] & 0xff;
1170                    int r = ((srcData[sp + 0] & 0xFF) * alpha) + 128;
1171                    r = (r + (r >> 8)) >> 8;
1172                    int g = ((srcData[sp + 1] & 0xFF) * alpha) + 128;
1173                    g = (g + (g >> 8)) >> 8;
1174                    int b = ((srcData[sp + 2] & 0xFF) * alpha) + 128;
1175                    b = (b + (b >> 8)) >> 8;
1176                    srcData[sp+0] = (byte)r;
1177                    srcData[sp+1] = (byte)g;
1178                    srcData[sp+2] = (byte)b;
1179                    srcData[sp+3] = (byte)alpha;
1180                    sp += 4;
1181                }
1182                ap += apinc;
1183            }
1184            OS.MoveMemory(dibBM.bmBits, srcData, srcData.length);
1185            blend.SourceConstantAlpha = (byte)0xff;
1186            blend.AlphaFormat = OS.AC_SRC_ALPHA;
1187            OS.AlphaBlend(handle, destX, destY, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, blend);
1188            OS.SelectObject(memHdc, oldMemBitmap);
1189            OS.DeleteDC(memHdc);
1190            OS.DeleteObject(memDib);
1191        }
1192        OS.SelectObject(srcHdc, oldSrcBitmap);
1193        OS.DeleteDC(srcHdc);
1194        return;
1195    }
1196
1197    /* Check clipping */
1198    Rectangle rect = getClipping();
1199    rect = rect.intersection(new Rectangle(destX, destY, destWidth, destHeight));
1200    if (rect.isEmpty()) return;
1201
1202    /*
1203    * Optimization. Recalculate src and dest rectangles so that
1204    * only the clipping area is drawn.
1205    */

1206    int sx1 = srcX + (((rect.x - destX) * srcWidth) / destWidth);
1207    int sx2 = srcX + ((((rect.x + rect.width) - destX) * srcWidth) / destWidth);
1208    int sy1 = srcY + (((rect.y - destY) * srcHeight) / destHeight);
1209    int sy2 = srcY + ((((rect.y + rect.height) - destY) * srcHeight) / destHeight);
1210    destX = rect.x;
1211    destY = rect.y;
1212    destWidth = rect.width;
1213    destHeight = rect.height;
1214    srcX = sx1;
1215    srcY = sy1;
1216    srcWidth = Math.max(1, sx2 - sx1);
1217    srcHeight = Math.max(1, sy2 - sy1);
1218    
1219    /* Create resources */
1220    int srcHdc = OS.CreateCompatibleDC(handle);
1221    int oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
1222    int memHdc = OS.CreateCompatibleDC(handle);
1223    int memDib = Image.createDIB(Math.max(srcWidth, destWidth), Math.max(srcHeight, destHeight), 32);
1224    if (memDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
1225    int oldMemBitmap = OS.SelectObject(memHdc, memDib);
1226
1227    BITMAP dibBM = new BITMAP();
1228    OS.GetObject(memDib, BITMAP.sizeof, dibBM);
1229    int sizeInBytes = dibBM.bmWidthBytes * dibBM.bmHeight;
1230
1231    /* Get the background pixels */
1232    OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY);
1233    byte[] destData = new byte[sizeInBytes];
1234    OS.MoveMemory(destData, dibBM.bmBits, sizeInBytes);
1235
1236    /* Get the foreground pixels */
1237    OS.BitBlt(memHdc, 0, 0, srcWidth, srcHeight, srcHdc, srcX, srcY, OS.SRCCOPY);
1238    byte[] srcData = new byte[sizeInBytes];
1239    OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
1240    
1241    /* Merge the alpha channel in place */
1242    int alpha = srcImage.alpha;
1243    final boolean hasAlphaChannel = (srcImage.alpha == -1);
1244    if (hasAlphaChannel) {
1245        final int apinc = imgWidth - srcWidth;
1246        final int spinc = dibBM.bmWidthBytes - srcWidth * 4;
1247        int ap = srcY * imgWidth + srcX, sp = 3;
1248        byte[] alphaData = srcImage.alphaData;
1249        for (int y = 0; y < srcHeight; ++y) {
1250            for (int x = 0; x < srcWidth; ++x) {
1251                srcData[sp] = alphaData[ap++];
1252                sp += 4;
1253            }
1254            ap += apinc;
1255            sp += spinc;
1256        }
1257    }
1258    
1259    /* Scale the foreground pixels with alpha */
1260    OS.MoveMemory(dibBM.bmBits, srcData, sizeInBytes);
1261    /*
1262    * Bug in WinCE and Win98. StretchBlt does not correctly stretch when
1263    * the source and destination HDCs are the same. The workaround is to
1264    * stretch to a temporary HDC and blit back into the original HDC.
1265    * Note that on WinCE StretchBlt correctly compresses the image when the
1266    * source and destination HDCs are the same.
1267    */

1268    if ((OS.IsWinCE && (destWidth > srcWidth || destHeight > srcHeight)) || (!OS.IsWinNT && !OS.IsWinCE)) {
1269        int tempHdc = OS.CreateCompatibleDC(handle);
1270        int tempDib = Image.createDIB(destWidth, destHeight, 32);
1271        if (tempDib == 0) SWT.error(SWT.ERROR_NO_HANDLES);
1272        int oldTempBitmap = OS.SelectObject(tempHdc, tempDib);
1273        if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
1274            if (!OS.IsWinCE) OS.SetStretchBltMode(memHdc, OS.COLORONCOLOR);
1275            OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY);
1276        } else {
1277            OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY);
1278        }
1279        OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY);
1280        OS.SelectObject(tempHdc, oldTempBitmap);
1281        OS.DeleteObject(tempDib);
1282        OS.DeleteDC(tempHdc);
1283    } else {
1284        if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
1285            if (!OS.IsWinCE) OS.SetStretchBltMode(memHdc, OS.COLORONCOLOR);
1286            OS.StretchBlt(memHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, srcWidth, srcHeight, OS.SRCCOPY);
1287        } else {
1288            OS.BitBlt(memHdc, 0, 0, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY);
1289        }
1290    }
1291    OS.MoveMemory(srcData, dibBM.bmBits, sizeInBytes);
1292    
1293    /* Compose the pixels */
1294    final int dpinc = dibBM.bmWidthBytes - destWidth * 4;
1295    int dp = 0;
1296    for (int y = 0; y < destHeight; ++y) {
1297        for (int x = 0; x < destWidth; ++x) {
1298            if (hasAlphaChannel) alpha = srcData[dp + 3] & 0xff;
1299            destData[dp] += ((srcData[dp] & 0xff) - (destData[dp] & 0xff)) * alpha / 255;
1300            destData[dp + 1] += ((srcData[dp + 1] & 0xff) - (destData[dp + 1] & 0xff)) * alpha / 255;
1301            destData[dp + 2] += ((srcData[dp + 2] & 0xff) - (destData[dp + 2] & 0xff)) * alpha / 255;
1302            dp += 4;
1303        }
1304        dp += dpinc;
1305    }
1306
1307    /* Draw the composed pixels */
1308    OS.MoveMemory(dibBM.bmBits, destData, sizeInBytes);
1309    OS.BitBlt(handle, destX, destY, destWidth, destHeight, memHdc, 0, 0, OS.SRCCOPY);
1310
1311    /* Free resources */
1312    OS.SelectObject(memHdc, oldMemBitmap);
1313    OS.DeleteDC(memHdc);
1314    OS.DeleteObject(memDib);
1315    OS.SelectObject(srcHdc, oldSrcBitmap);
1316    OS.DeleteDC(srcHdc);
1317}
1318
1319void drawBitmapTransparentByClipping(int srcHdc, int maskHdc, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight, boolean simple, int imgWidth, int imgHeight) {
1320    /* Create a clipping region from the mask */
1321    int rgn = OS.CreateRectRgn(0, 0, 0, 0);
1322    for (int y=0; y<imgHeight; y++) {
1323        for (int x=0; x<imgWidth; x++) {
1324            if (OS.GetPixel(maskHdc, x, y) == 0) {
1325                int tempRgn = OS.CreateRectRgn(x, y, x+1, y+1);
1326                OS.CombineRgn(rgn, rgn, tempRgn, OS.RGN_OR);
1327                OS.DeleteObject(tempRgn);
1328            }
1329        }
1330    }
1331    /* Stretch the clipping mask if needed */
1332    if (destWidth != srcWidth || destHeight != srcHeight) {
1333        int nBytes = OS.GetRegionData (rgn, 0, null);
1334        int[] lpRgnData = new int[nBytes / 4];
1335        OS.GetRegionData (rgn, nBytes, lpRgnData);
1336        float[] lpXform = new float[] {(float)destWidth/srcWidth, 0, 0, (float)destHeight/srcHeight, 0, 0};
1337        int tmpRgn = OS.ExtCreateRegion(lpXform, nBytes, lpRgnData);
1338        OS.DeleteObject(rgn);
1339        rgn = tmpRgn;
1340    }
1341    OS.OffsetRgn(rgn, destX, destY);
1342    int clip = OS.CreateRectRgn(0, 0, 0, 0);
1343    int result = OS.GetClipRgn(handle, clip);
1344    if (result == 1) OS.CombineRgn(rgn, rgn, clip, OS.RGN_AND);
1345    OS.SelectClipRgn(handle, rgn);
1346    int rop2 = 0;
1347    if (!OS.IsWinCE) {
1348        rop2 = OS.GetROP2(handle);
1349    } else {
1350        rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN);
1351        OS.SetROP2 (handle, rop2);
1352    }
1353    int dwRop = rop2 == OS.R2_XORPEN ? OS.SRCINVERT : OS.SRCCOPY;
1354    if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
1355        int mode = 0;
1356        if (!OS.IsWinCE) mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR);
1357        OS.StretchBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, dwRop);
1358        if (!OS.IsWinCE) OS.SetStretchBltMode(handle, mode);
1359    } else {
1360        OS.BitBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, dwRop);
1361    }
1362    OS.SelectClipRgn(handle, result == 1 ? clip : 0);
1363    OS.DeleteObject(clip);
1364    OS.DeleteObject(rgn);
1365}
1366
1367void drawBitmapMask(Image srcImage, int srcColor, int 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) {
1368    int srcColorY = srcY;
1369    if (srcColor == 0) {
1370        srcColor = srcMask;
1371        srcColorY += imgHeight;
1372    }
1373    int srcHdc = OS.CreateCompatibleDC(handle);
1374    int oldSrcBitmap = OS.SelectObject(srcHdc, srcColor);
1375    int destHdc = handle, x = destX, y = destY;
1376    int tempHdc = 0, tempBitmap = 0, oldTempBitmap = 0;
1377    int oldBkColor = 0, oldTextColor = 0;
1378    if (offscreen) {
1379        tempHdc = OS.CreateCompatibleDC(handle);
1380        tempBitmap = OS.CreateCompatibleBitmap(handle, destWidth, destHeight);
1381        oldTempBitmap = OS.SelectObject(tempHdc, tempBitmap);
1382        OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY);
1383        destHdc = tempHdc;
1384        x = y = 0;
1385    } else {
1386        oldBkColor = OS.SetBkColor(handle, 0xFFFFFF);
1387        oldTextColor = OS.SetTextColor(handle, 0);
1388    }
1389    if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
1390        int mode = 0;
1391        if (!OS.IsWinCE) mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR);
1392        OS.StretchBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCINVERT);
1393        OS.SelectObject(srcHdc, srcMask);
1394        OS.StretchBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCAND);
1395        OS.SelectObject(srcHdc, srcColor);
1396        OS.StretchBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, srcWidth, srcHeight, OS.SRCINVERT);
1397        if (!OS.IsWinCE) OS.SetStretchBltMode(handle, mode);
1398    } else {
1399        OS.BitBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, OS.SRCINVERT);
1400        OS.SetTextColor(destHdc, 0);
1401        OS.SelectObject(srcHdc, srcMask);
1402        OS.BitBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCAND);
1403        OS.SelectObject(srcHdc, srcColor);
1404        OS.BitBlt(destHdc, x, y, destWidth, destHeight, srcHdc, srcX, srcColorY, OS.SRCINVERT);
1405    }
1406    if (offscreen) {
1407        OS.BitBlt(handle, destX, destY, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY);
1408        OS.SelectObject(tempHdc, oldTempBitmap);
1409        OS.DeleteDC(tempHdc);
1410        OS.DeleteObject(tempBitmap);
1411    } else {
1412        OS.SetBkColor(handle, oldBkColor);
1413        OS.SetTextColor(handle, oldTextColor);
1414    }
1415    OS.SelectObject(srcHdc, oldSrcBitmap);
1416    OS.DeleteDC(srcHdc);
1417}
1418
1419void 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) {
1420        
1421    /* Find the RGB values for the transparent pixel. */
1422    int transBlue = 0, transGreen = 0, transRed = 0;
1423    boolean isDib = bm.bmBits != 0;
1424    int hBitmap = srcImage.handle;
1425    int srcHdc = OS.CreateCompatibleDC(handle);
1426    int oldSrcBitmap = OS.SelectObject(srcHdc, hBitmap);
1427    byte[] originalColors = null;
1428    if (bm.bmBitsPixel <= 8) {
1429        if (isDib) {
1430            /* Palette-based DIBSECTION */
1431            if (OS.IsWinCE) {
1432                byte[] pBits = new byte[1];
1433                OS.MoveMemory(pBits, bm.bmBits, 1);
1434                byte oldValue = pBits[0];
1435                int mask = (0xFF << (8 - bm.bmBitsPixel)) & 0x00FF;
1436                pBits[0] = (byte)((srcImage.transparentPixel << (8 - bm.bmBitsPixel)) | (pBits[0] & ~mask));
1437                OS.MoveMemory(bm.bmBits, pBits, 1);
1438                int color = OS.GetPixel(srcHdc, 0, 0);
1439                pBits[0] = oldValue;
1440                OS.MoveMemory(bm.bmBits, pBits, 1);
1441                transBlue = (color & 0xFF0000) >> 16;
1442                transGreen = (color & 0xFF00) >> 8;
1443                transRed = color & 0xFF;
1444            } else {
1445                int maxColors = 1 << bm.bmBitsPixel;
1446                byte[] oldColors = new byte[maxColors * 4];
1447                OS.GetDIBColorTable(srcHdc, 0, maxColors, oldColors);
1448                int offset = srcImage.transparentPixel * 4;
1449                boolean fixPalette = false;
1450                for (int i = 0; i < oldColors.length; i += 4) {
1451                    if (i != offset) {
1452                        if (oldColors[offset] == oldColors[i] && oldColors[offset+1] == oldColors[i+1] && oldColors[offset+2] == oldColors[i+2]) {
1453                            fixPalette = true;
1454                            break;
1455                        }
1456                    }
1457                }
1458                if (fixPalette) {
1459                    byte[] newColors = new byte[oldColors.length];
1460                    transRed = transGreen = transBlue = 0xff;
1461                    newColors[offset] = (byte)transBlue;
1462                    newColors[offset+1] = (byte)transGreen;
1463                    newColors[offset+2] = (byte)transRed;
1464                    OS.SetDIBColorTable(srcHdc, 0, maxColors, newColors);
1465                    originalColors = oldColors;
1466                } else {
1467                    transBlue = oldColors[offset] & 0xFF;
1468                    transGreen = oldColors[offset+1] & 0xFF;
1469                    transRed = oldColors[offset+2] & 0xFF;
1470                }
1471            }
1472        } else {
1473            /* Palette-based bitmap */
1474            int numColors = 1 << bm.bmBitsPixel;
1475            /* Set the few fields necessary to get the RGB data out */
1476            BITMAPINFOHEADER bmiHeader = new BITMAPINFOHEADER();
1477            bmiHeader.biSize = BITMAPINFOHEADER.sizeof;
1478            bmiHeader.biPlanes = bm.bmPlanes;
1479            bmiHeader.biBitCount = bm.bmBitsPixel;
1480            byte[] bmi = new byte[BITMAPINFOHEADER.sizeof + numColors * 4];
1481            OS.MoveMemory(bmi, bmiHeader, BITMAPINFOHEADER.sizeof);
1482            if (OS.IsWinCE) SWT.error(SWT.ERROR_NOT_IMPLEMENTED);
1483            OS.GetDIBits(srcHdc, srcImage.handle, 0, 0, 0, bmi, OS.DIB_RGB_COLORS);
1484            int offset = BITMAPINFOHEADER.sizeof + 4 * srcImage.transparentPixel;
1485            transRed = bmi[offset + 2] & 0xFF;
1486            transGreen = bmi[offset + 1] & 0xFF;
1487            transBlue = bmi[offset] & 0xFF;
1488        }
1489    } else {
1490        /* Direct color image */
1491        int pixel = srcImage.transparentPixel;
1492        switch (bm.bmBitsPixel) {
1493            case 16:
1494                transBlue = (pixel & 0x1F) << 3;
1495                transGreen = (pixel & 0x3E0) >> 2;
1496                transRed = (pixel & 0x7C00) >> 7;
1497                break;
1498            case 24:
1499                transBlue = (pixel & 0xFF0000) >> 16;
1500                transGreen = (pixel & 0xFF00) >> 8;
1501                transRed = pixel & 0xFF;
1502                break;
1503            case 32:
1504                transBlue = (pixel & 0xFF000000) >>> 24;
1505                transGreen = (pixel & 0xFF0000) >> 16;
1506                transRed = (pixel & 0xFF00) >> 8;
1507                break;
1508        }
1509    }
1510
1511    int transparentColor = transBlue << 16 | transGreen << 8 | transRed;
1512    if (OS.IsWinCE) {
1513        /*
1514        * Note in WinCE. TransparentImage uses the first entry of a palette
1515        * based image when there are multiple entries that have the same
1516        * transparent color.
1517        */

1518        OS.TransparentImage(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, transparentColor);
1519    } else if (originalColors == null && OS.IsWinNT && OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
1520        int mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR);
1521        OS.TransparentBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, transparentColor);
1522        OS.SetStretchBltMode(handle, mode);
1523    } else {
1524        /* Create the mask for the source image */
1525        int maskHdc = OS.CreateCompatibleDC(handle);
1526        int maskBitmap = OS.CreateBitmap(imgWidth, imgHeight, 1, 1, null);
1527        int oldMaskBitmap = OS.SelectObject(maskHdc, maskBitmap);
1528        OS.SetBkColor(srcHdc, transparentColor);
1529        OS.BitBlt(maskHdc, 0, 0, imgWidth, imgHeight, srcHdc, 0, 0, OS.SRCCOPY);
1530        if (originalColors != null) OS.SetDIBColorTable(srcHdc, 0, 1 << bm.bmBitsPixel, originalColors);
1531    
1532        if (OS.GetDeviceCaps(handle, OS.TECHNOLOGY) == OS.DT_RASPRINTER) {
1533            /* Most printers do not support BitBlt(), draw the source bitmap transparently using clipping */
1534            drawBitmapTransparentByClipping(srcHdc, maskHdc, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight, simple, imgWidth, imgHeight);
1535        } else {
1536            /* Draw the source bitmap transparently using invert/and mask/invert */
1537            int tempHdc = OS.CreateCompatibleDC(handle);
1538            int tempBitmap = OS.CreateCompatibleBitmap(handle, destWidth, destHeight);
1539            int oldTempBitmap = OS.SelectObject(tempHdc, tempBitmap);
1540            OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, handle, destX, destY, OS.SRCCOPY);
1541            if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
1542                if (!OS.IsWinCE) OS.SetStretchBltMode(tempHdc, OS.COLORONCOLOR);
1543                OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCINVERT);
1544                OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, maskHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCAND);
1545                OS.StretchBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, OS.SRCINVERT);
1546            } else {
1547                OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCINVERT);
1548                OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, maskHdc, srcX, srcY, OS.SRCAND);
1549                OS.BitBlt(tempHdc, 0, 0, destWidth, destHeight, srcHdc, srcX, srcY, OS.SRCINVERT);
1550            }
1551            OS.BitBlt(handle, destX, destY, destWidth, destHeight, tempHdc, 0, 0, OS.SRCCOPY);
1552            OS.SelectObject(tempHdc, oldTempBitmap);
1553            OS.DeleteDC(tempHdc);
1554            OS.DeleteObject(tempBitmap);
1555        }
1556        OS.SelectObject(maskHdc, oldMaskBitmap);
1557        OS.DeleteDC(maskHdc);
1558        OS.DeleteObject(maskBitmap);
1559    }
1560    OS.SelectObject(srcHdc, oldSrcBitmap);
1561    if (hBitmap != srcImage.handle) OS.DeleteObject(hBitmap);
1562    OS.DeleteDC(srcHdc);
1563}
1564
1565void 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) {
1566    int srcHdc = OS.CreateCompatibleDC(handle);
1567    int oldSrcBitmap = OS.SelectObject(srcHdc, srcImage.handle);
1568    int rop2 = 0;
1569    if (!OS.IsWinCE) {
1570        rop2 = OS.GetROP2(handle);
1571    } else {
1572        rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN);
1573        OS.SetROP2 (handle, rop2);
1574    }
1575    int dwRop = rop2 == OS.R2_XORPEN ? OS.SRCINVERT : OS.SRCCOPY;
1576    if (!simple && (srcWidth != destWidth || srcHeight != destHeight)) {
1577        int mode = 0;
1578        if (!OS.IsWinCE) mode = OS.SetStretchBltMode(handle, OS.COLORONCOLOR);
1579        OS.StretchBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, srcWidth, srcHeight, dwRop);
1580        if (!OS.IsWinCE) OS.SetStretchBltMode(handle, mode);
1581    } else {
1582        OS.BitBlt(handle, destX, destY, destWidth, destHeight, srcHdc, srcX, srcY, dwRop);
1583    }
1584    OS.SelectObject(srcHdc, oldSrcBitmap);
1585    OS.DeleteDC(srcHdc);
1586}
1587
1588/**
1589 * Draws a line, using the foreground color, between the points
1590 * (<code>x1</code>, <code>y1</code>) and (<code>x2</code>, <code>y2</code>).
1591 *
1592 * @param x1 the first point's x coordinate
1593 * @param y1 the first point's y coordinate
1594 * @param x2 the second point's x coordinate
1595 * @param y2 the second point's y coordinate
1596 *
1597 * @exception SWTException <ul>
1598 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1599 * </ul>
1600 */

1601public void drawLine (int x1, int y1, int x2, int y2) {
1602    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1603    checkGC(DRAW);
1604    int gdipGraphics = data.gdipGraphics;
1605    if (gdipGraphics != 0) {
1606        Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
1607        Gdip.Graphics_DrawLine(gdipGraphics, data.gdipPen, x1, y1, x2, y2);
1608        Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
1609        return;
1610    }
1611    if ((data.style & SWT.MIRRORED) != 0) {
1612        if (data.lineWidth != 0 && data.lineWidth % 2 == 0) {
1613            x1--;
1614            x2--;
1615        }
1616    }
1617    if (OS.IsWinCE) {
1618        int [] points = new int [] {x1, y1, x2, y2};
1619        OS.Polyline (handle, points, points.length / 2);
1620    } else {
1621        OS.MoveToEx (handle, x1, y1, 0);
1622        OS.LineTo (handle, x2, y2);
1623    }
1624    if (data.lineWidth <= 1) {
1625        OS.SetPixel (handle, x2, y2, data.foreground);
1626    }
1627}
1628
1629/**
1630 * Draws the outline of an oval, using the foreground color,
1631 * within the specified rectangular area.
1632 * <p>
1633 * The result is a circle or ellipse that fits within the
1634 * rectangle specified by the <code>x</code>, <code>y</code>,
1635 * <code>width</code>, and <code>height</code> arguments.
1636 * </p><p>
1637 * The oval covers an area that is <code>width + 1</code>
1638 * pixels wide and <code>height + 1</code> pixels tall.
1639 * </p>
1640 *
1641 * @param x the x coordinate of the upper left corner of the oval to be drawn
1642 * @param y the y coordinate of the upper left corner of the oval to be drawn
1643 * @param width the width of the oval to be drawn
1644 * @param height the height of the oval to be drawn
1645 *
1646 * @exception SWTException <ul>
1647 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1648 * </ul>
1649 */

1650public void drawOval (int x, int y, int width, int height) {
1651    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1652    checkGC(DRAW);
1653    int gdipGraphics = data.gdipGraphics;
1654    if (gdipGraphics != 0) {
1655        Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
1656        Gdip.Graphics_DrawEllipse(gdipGraphics, data.gdipPen, x, y, width, height);
1657        Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
1658        return;
1659    }
1660    if ((data.style & SWT.MIRRORED) != 0) {
1661        if (data.lineWidth != 0 && data.lineWidth % 2 == 0) x--;
1662    }
1663    OS.Ellipse(handle, x, y, x + width + 1, y + height + 1);
1664}
1665
1666/**
1667 * Draws the path described by the parameter.
1668 * <p>
1669 * This operation requires the operating system's advanced
1670 * graphics subsystem which may not be available on some
1671 * platforms.
1672 * </p>
1673 *
1674 * @param path the path to draw
1675 *
1676 * @exception IllegalArgumentException <ul>
1677 * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
1678 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
1679 * </ul>
1680 * @exception SWTException <ul>
1681 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1682 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
1683 * </ul>
1684 *
1685 * @see Path
1686 *
1687 * @since 3.1
1688 */

1689public void drawPath (Path path) {
1690    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1691    if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1692    if (path.handle == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
1693    initGdip();
1694    checkGC(DRAW);
1695    int gdipGraphics = data.gdipGraphics;
1696    Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
1697    Gdip.Graphics_DrawPath(gdipGraphics, data.gdipPen, path.handle);
1698    Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
1699}
1700
1701/**
1702 * Draws a pixel, using the foreground color, at the specified
1703 * point (<code>x</code>, <code>y</code>).
1704 * <p>
1705 * Note that the receiver's line attributes do not affect this
1706 * operation.
1707 * </p>
1708 *
1709 * @param x the point's x coordinate
1710 * @param y the point's y coordinate
1711 *
1712 * @exception SWTException <ul>
1713 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1714 * </ul>
1715 *
1716 * @since 3.0
1717 */

1718public void drawPoint (int x, int y) {
1719    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1720    if (data.gdipGraphics != 0) {
1721        checkGC(DRAW);
1722        Gdip.Graphics_FillRectangle(data.gdipGraphics, getFgBrush(), x, y, 1, 1);
1723        return;
1724    }
1725    OS.SetPixel (handle, x, y, data.foreground);
1726}
1727
1728/**
1729 * Draws the closed polygon which is defined by the specified array
1730 * of integer coordinates, using the receiver's foreground color. The array
1731 * contains alternating x and y values which are considered to represent
1732 * points which are the vertices of the polygon. Lines are drawn between
1733 * each consecutive pair, and between the first pair and last pair in the
1734 * array.
1735 *
1736 * @param pointArray an array of alternating x and y values which are the vertices of the polygon
1737 *
1738 * @exception IllegalArgumentException <ul>
1739 * <li>ERROR_NULL_ARGUMENT if pointArray is null</li>
1740 * </ul>
1741 * @exception SWTException <ul>
1742 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1743 * </ul>
1744 */

1745public void drawPolygon(int[] pointArray) {
1746    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1747    if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1748    checkGC(DRAW);
1749    int gdipGraphics = data.gdipGraphics;
1750    if (gdipGraphics != 0) {
1751        Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
1752        Gdip.Graphics_DrawPolygon(gdipGraphics, data.gdipPen, pointArray, pointArray.length / 2);
1753        Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
1754        return;
1755    }
1756    if ((data.style & SWT.MIRRORED) != 0) {
1757        if (data.lineWidth != 0 && data.lineWidth % 2 == 0) {
1758            for (int i = 0; i < pointArray.length; i+=2) {
1759                pointArray[i]--;
1760            }
1761        }
1762    }
1763    OS.Polygon(handle, pointArray, pointArray.length / 2);
1764    if ((data.style & SWT.MIRRORED) != 0) {
1765        if (data.lineWidth != 0 && data.lineWidth % 2 == 0) {
1766            for (int i = 0; i < pointArray.length; i+=2) {
1767                pointArray[i]++;
1768            }
1769        }
1770    }
1771}
1772
1773/**
1774 * Draws the polyline which is defined by the specified array
1775 * of integer coordinates, using the receiver's foreground color. The array
1776 * contains alternating x and y values which are considered to represent
1777 * points which are the corners of the polyline. Lines are drawn between
1778 * each consecutive pair, but not between the first pair and last pair in
1779 * the array.
1780 *
1781 * @param pointArray an array of alternating x and y values which are the corners of the polyline
1782 *
1783 * @exception IllegalArgumentException <ul>
1784 * <li>ERROR_NULL_ARGUMENT - if the point array is null</li>
1785 * </ul>
1786 * @exception SWTException <ul>
1787 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1788 * </ul>
1789 */

1790public void drawPolyline(int[] pointArray) {
1791    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1792    if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1793    checkGC(DRAW);
1794    int gdipGraphics = data.gdipGraphics;
1795    if (gdipGraphics != 0) {
1796        Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
1797        Gdip.Graphics_DrawLines(gdipGraphics, data.gdipPen, pointArray, pointArray.length / 2);
1798        Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
1799        return;
1800    }
1801    if ((data.style & SWT.MIRRORED) != 0) {
1802        if (data.lineWidth != 0 && data.lineWidth % 2 == 0) {
1803            for (int i = 0; i < pointArray.length; i+=2) {
1804                pointArray[i]--;
1805            }
1806        }
1807    }
1808    OS.Polyline(handle, pointArray, pointArray.length / 2);
1809    int length = pointArray.length;
1810    if (length >= 2) {
1811        if (data.lineWidth <= 1) {
1812            OS.SetPixel (handle, pointArray[length - 2], pointArray[length - 1], data.foreground);
1813        }
1814    }
1815    if ((data.style & SWT.MIRRORED) != 0) {
1816        if (data.lineWidth != 0 && data.lineWidth % 2 == 0) {
1817            for (int i = 0; i < pointArray.length; i+=2) {
1818                pointArray[i]++;
1819            }
1820        }
1821    }
1822}
1823
1824/**
1825 * Draws the outline of the rectangle specified by the arguments,
1826 * using the receiver's foreground color. The left and right edges
1827 * of the rectangle are at <code>x</code> and <code>x + width</code>.
1828 * The top and bottom edges are at <code>y</code> and <code>y + height</code>.
1829 *
1830 * @param x the x coordinate of the rectangle to be drawn
1831 * @param y the y coordinate of the rectangle to be drawn
1832 * @param width the width of the rectangle to be drawn
1833 * @param height the height of the rectangle to be drawn
1834 *
1835 * @exception SWTException <ul>
1836 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1837 * </ul>
1838 */

1839public void drawRectangle (int x, int y, int width, int height) {
1840    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1841    checkGC(DRAW);
1842    int gdipGraphics = data.gdipGraphics;
1843    if (gdipGraphics != 0) {
1844        Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
1845        Gdip.Graphics_DrawRectangle(gdipGraphics, data.gdipPen, x, y, width, height);
1846        Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
1847        return;
1848    }
1849    if ((data.style & SWT.MIRRORED) != 0) {
1850        /*
1851        * Note that Rectangle() subtracts one pixel in MIRRORED mode when
1852        * the pen was created with CreatePen() and its width is 0 or 1.
1853        */

1854        if (data.lineWidth > 1) {
1855            if ((data.lineWidth % 2) == 1) x++;
1856        } else {
1857            if (data.hPen != 0 && OS.GetObject(data.hPen, 0, 0) != LOGPEN.sizeof) {
1858                x++;
1859            }
1860        }
1861    }
1862    OS.Rectangle (handle, x, y, x + width + 1, y + height + 1);
1863}
1864
1865/**
1866 * Draws the outline of the specified rectangle, using the receiver's
1867 * foreground color. The left and right edges of the rectangle are at
1868 * <code>rect.x</code> and <code>rect.x + rect.width</code>. The top
1869 * and bottom edges are at <code>rect.y</code> and
1870 * <code>rect.y + rect.height</code>.
1871 *
1872 * @param rect the rectangle to draw
1873 *
1874 * @exception IllegalArgumentException <ul>
1875 * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
1876 * </ul>
1877 * @exception SWTException <ul>
1878 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1879 * </ul>
1880 */

1881public void drawRectangle (Rectangle rect) {
1882    if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
1883    drawRectangle (rect.x, rect.y, rect.width, rect.height);
1884}
1885
1886/**
1887 * Draws the outline of the round-cornered rectangle specified by
1888 * the arguments, using the receiver's foreground color. The left and
1889 * right edges of the rectangle are at <code>x</code> and <code>x + width</code>.
1890 * The top and bottom edges are at <code>y</code> and <code>y + height</code>.
1891 * The <em>roundness</em> of the corners is specified by the
1892 * <code>arcWidth</code> and <code>arcHeight</code> arguments, which
1893 * are respectively the width and height of the ellipse used to draw
1894 * the corners.
1895 *
1896 * @param x the x coordinate of the rectangle to be drawn
1897 * @param y the y coordinate of the rectangle to be drawn
1898 * @param width the width of the rectangle to be drawn
1899 * @param height the height of the rectangle to be drawn
1900 * @param arcWidth the width of the arc
1901 * @param arcHeight the height of the arc
1902 *
1903 * @exception SWTException <ul>
1904 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
1905 * </ul>
1906 */

1907public void drawRoundRectangle (int x, int y, int width, int height, int arcWidth, int arcHeight) {
1908    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
1909    checkGC(DRAW);
1910    if (data.gdipGraphics != 0) {
1911        drawRoundRectangleGdip(data.gdipGraphics, data.gdipPen, x, y, width, height, arcWidth, arcHeight);
1912        return;
1913    }
1914    if ((data.style & SWT.MIRRORED) != 0) {
1915        if (data.lineWidth != 0 && data.lineWidth % 2 == 0) x--;
1916    }
1917    if (OS.IsWinCE) {
1918        /*
1919        * Bug in WinCE PPC. On certain devices, RoundRect does not draw
1920        * all the pixels. The workaround is to draw a round rectangle
1921        * using lines and arcs.
1922        */

1923        if (width == 0 || height == 0) return;
1924        if (arcWidth == 0 || arcHeight == 0) {
1925            drawRectangle(x, y, width, height);
1926            return;
1927        }
1928        if (width < 0) {
1929            x += width;
1930            width = -width;
1931        }
1932        if (height < 0) {
1933            y += height;
1934            height = -height;
1935        }
1936        if (arcWidth < 0) arcWidth = -arcWidth;
1937        if (arcHeight < 0) arcHeight = -arcHeight;
1938        if (arcWidth > width) arcWidth = width;
1939        if (arcHeight > height) arcHeight = height;
1940                
1941        if (arcWidth < width) {
1942            drawLine(x+arcWidth/2, y, x+width-arcWidth/2, y);
1943            drawLine(x+arcWidth/2, y+height, x+width-arcWidth/2, y+height);
1944        }
1945        if (arcHeight < height) {
1946            drawLine(x, y+arcHeight/2, x, y+height-arcHeight/2);
1947            drawLine(x+width, y+arcHeight/2, x+width, y+height-arcHeight/2);
1948        }
1949        if (arcWidth != 0 && arcHeight != 0) {
1950            drawArc(x, y, arcWidth, arcHeight, 90, 90);
1951            drawArc(x+width-arcWidth, y, arcWidth, arcHeight, 0, 90);
1952            drawArc(x+width-arcWidth, y+height-arcHeight, arcWidth, arcHeight, 0, -90);
1953            drawArc(x, y+height-arcHeight, arcWidth, arcHeight, 180, 90);
1954        }
1955    } else {
1956        OS.RoundRect(handle, x,y,x+width+1,y+height+1, arcWidth, arcHeight);
1957    }
1958}
1959
1960void drawRoundRectangleGdip (int gdipGraphics, int pen, int x, int y, int width, int height, int arcWidth, int arcHeight) {
1961    int nx = x;
1962    int ny = y;
1963    int nw = width;
1964    int nh = height;
1965    int naw = arcWidth;
1966    int nah = arcHeight;
1967    
1968    if (nw < 0) {
1969        nw = 0 - nw;
1970        nx = nx - nw;
1971    }
1972    if (nh < 0) {
1973        nh = 0 - nh;
1974        ny = ny - nh;
1975    }
1976    if (naw < 0)
1977        naw = 0 - naw;
1978    if (nah < 0)
1979        nah = 0 - nah;
1980    
1981    Gdip.Graphics_TranslateTransform(gdipGraphics, data.gdipXOffset, data.gdipYOffset, Gdip.MatrixOrderPrepend);
1982    int path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
1983    if (path == 0) SWT.error(SWT.ERROR_NO_HANDLES);
1984    if (nw > naw) {
1985        if (nh > nah) {
1986            Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nah, 0, -90);
1987            Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nah, -90, -90);
1988            Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, naw, nah, -180, -90);
1989            Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny + nh - nah, naw, nah, -270, -90);
1990        } else {
1991            Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nh, -270, -180);
1992            Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nh, -90, -180);
1993        }
1994    } else {
1995        if (nh > nah) {
1996            Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nah, 0, -180);
1997            Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, nw, nah, -180, -180);
1998        } else {
1999            Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nh, 0, 360);
2000        }
2001    }
2002    Gdip.GraphicsPath_CloseFigure(path);
2003    Gdip.Graphics_DrawPath(gdipGraphics, pen, path);
2004    Gdip.GraphicsPath_delete(path);
2005    Gdip.Graphics_TranslateTransform(gdipGraphics, -data.gdipXOffset, -data.gdipYOffset, Gdip.MatrixOrderPrepend);
2006}
2007
2008/**
2009 * Draws the given string, using the receiver's current font and
2010 * foreground color. No tab expansion or carriage return processing
2011 * will be performed. The background of the rectangular area where
2012 * the string is being drawn will be filled with the receiver's
2013 * background color.
2014 *
2015 * @param string the string to be drawn
2016 * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn
2017 * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn
2018 *
2019 * @exception IllegalArgumentException <ul>
2020 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
2021 * </ul>
2022 * @exception SWTException <ul>
2023 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2024 * </ul>
2025 */

2026public void drawString (String JavaDoc string, int x, int y) {
2027    drawString(string, x, y, false);
2028}
2029
2030/**
2031 * Draws the given string, using the receiver's current font and
2032 * foreground color. No tab expansion or carriage return processing
2033 * will be performed. If <code>isTransparent</code> is <code>true</code>,
2034 * then the background of the rectangular area where the string is being
2035 * drawn will not be modified, otherwise it will be filled with the
2036 * receiver's background color.
2037 *
2038 * @param string the string to be drawn
2039 * @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn
2040 * @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn
2041 * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque
2042 *
2043 * @exception IllegalArgumentException <ul>
2044 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
2045 * </ul>
2046 * @exception SWTException <ul>
2047 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2048 * </ul>
2049 */

2050public void drawString (String JavaDoc string, int x, int y, boolean isTransparent) {
2051    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2052    if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
2053// TCHAR buffer = new TCHAR (getCodePage(), string, false);
2054
int length = string.length();
2055    if (length == 0) return;
2056    char[] buffer = new char [length];
2057    string.getChars(0, length, buffer, 0);
2058    int gdipGraphics = data.gdipGraphics;
2059    if (gdipGraphics != 0) {
2060        checkGC(FONT | FOREGROUND | (isTransparent ? 0 : BACKGROUND));
2061        PointF pt = new PointF();
2062        int format = Gdip.StringFormat_Clone(Gdip.StringFormat_GenericTypographic());
2063        int formatFlags = Gdip.StringFormat_GetFormatFlags(format) | Gdip.StringFormatFlagsMeasureTrailingSpaces;
2064        if ((data.style & SWT.MIRRORED) != 0) formatFlags |= Gdip.StringFormatFlagsDirectionRightToLeft;
2065        Gdip.StringFormat_SetFormatFlags(format, formatFlags);
2066        if (!isTransparent) {
2067            RectF bounds = new RectF();
2068            Gdip.Graphics_MeasureString(gdipGraphics, buffer, length, data.gdipFont, pt, format, bounds);
2069            Gdip.Graphics_FillRectangle(gdipGraphics, data.gdipBrush, x, y, Math.round(bounds.Width), Math.round(bounds.Height));
2070        }
2071        int gstate = 0, brush = getFgBrush();
2072        if ((data.style & SWT.MIRRORED) != 0) {
2073            switch (Gdip.Brush_GetType(brush)) {
2074                case Gdip.BrushTypeLinearGradient:
2075                    Gdip.LinearGradientBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
2076                    Gdip.LinearGradientBrush_TranslateTransform(brush, - 2 * x, 0, Gdip.MatrixOrderPrepend);
2077                    break;
2078                case Gdip.BrushTypeTextureFill:
2079                    Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
2080                    Gdip.TextureBrush_TranslateTransform(brush, - 2 * x, 0, Gdip.MatrixOrderPrepend);
2081                    break;
2082            }
2083            gstate = Gdip.Graphics_Save(gdipGraphics);
2084            Gdip.Graphics_ScaleTransform(gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend);
2085            Gdip.Graphics_TranslateTransform(gdipGraphics, - 2 * x, 0, Gdip.MatrixOrderPrepend);
2086        }
2087        pt.X = x;
2088        pt.Y = y;
2089        Gdip.Graphics_DrawString(gdipGraphics, buffer, length, data.gdipFont, pt, format, brush);
2090        if ((data.style & SWT.MIRRORED) != 0) {
2091            switch (Gdip.Brush_GetType(brush)) {
2092                case Gdip.BrushTypeLinearGradient:
2093                    Gdip.LinearGradientBrush_ResetTransform(brush);
2094                    break;
2095                case Gdip.BrushTypeTextureFill:
2096                    Gdip.TextureBrush_ResetTransform(brush);
2097                    break;
2098            }
2099            Gdip.Graphics_Restore(gdipGraphics, gstate);
2100        }
2101        Gdip.StringFormat_delete(format);
2102        return;
2103    }
2104    int rop2 = 0;
2105    if (OS.IsWinCE) {
2106        rop2 = OS.SetROP2(handle, OS.R2_COPYPEN);
2107        OS.SetROP2(handle, rop2);
2108    } else {
2109        rop2 = OS.GetROP2(handle);
2110    }
2111    checkGC(FONT | FOREGROUND_TEXT | BACKGROUND_TEXT);
2112    int oldBkMode = OS.SetBkMode(handle, isTransparent ? OS.TRANSPARENT : OS.OPAQUE);
2113    RECT rect = null;
2114    SIZE size = null;
2115    int flags = 0;
2116    if ((data.style & SWT.MIRRORED) != 0) {
2117        if (!isTransparent) {
2118            size = new SIZE();
2119            OS.GetTextExtentPoint32W(handle, buffer, length, size);
2120            rect = new RECT ();
2121            rect.left = x;
2122            rect.right = x + size.cx;
2123            rect.top = y;
2124            rect.bottom = y + size.cy;
2125            flags = OS.ETO_CLIPPED;
2126        }
2127        x--;
2128    }
2129    if (rop2 != OS.R2_XORPEN) {
2130        OS.ExtTextOutW(handle, x, y, flags, rect, buffer, length, null);
2131    } else {
2132        int foreground = OS.GetTextColor(handle);
2133        if (isTransparent) {
2134            if (size == null) {
2135                size = new SIZE();
2136                OS.GetTextExtentPoint32W(handle, buffer, length, size);
2137            }
2138            int width = size.cx, height = size.cy;
2139            int hBitmap = OS.CreateCompatibleBitmap(handle, width, height);
2140            if (hBitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
2141            int memDC = OS.CreateCompatibleDC(handle);
2142            int hOldBitmap = OS.SelectObject(memDC, hBitmap);
2143            OS.PatBlt(memDC, 0, 0, width, height, OS.BLACKNESS);
2144            OS.SetBkMode(memDC, OS.TRANSPARENT);
2145            OS.SetTextColor(memDC, foreground);
2146            OS.SelectObject(memDC, OS.GetCurrentObject(handle, OS.OBJ_FONT));
2147            OS.ExtTextOutW(memDC, 0, 0, 0, null, buffer, length, null);
2148            OS.BitBlt(handle, x, y, width, height, memDC, 0, 0, OS.SRCINVERT);
2149            OS.SelectObject(memDC, hOldBitmap);
2150            OS.DeleteDC(memDC);
2151            OS.DeleteObject(hBitmap);
2152        } else {
2153            int background = OS.GetBkColor(handle);
2154            OS.SetTextColor(handle, foreground ^ background);
2155            OS.ExtTextOutW(handle, x, y, flags, rect, buffer, length, null);
2156            OS.SetTextColor(handle, foreground);
2157        }
2158    }
2159    OS.SetBkMode(handle, oldBkMode);
2160}
2161
2162/**
2163 * Draws the given string, using the receiver's current font and
2164 * foreground color. Tab expansion and carriage return processing
2165 * are performed. The background of the rectangular area where
2166 * the text is being drawn will be filled with the receiver's
2167 * background color.
2168 *
2169 * @param string the string to be drawn
2170 * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
2171 * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
2172 *
2173 * @exception IllegalArgumentException <ul>
2174 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
2175 * </ul>
2176 * @exception SWTException <ul>
2177 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2178 * </ul>
2179 */

2180public void drawText (String JavaDoc string, int x, int y) {
2181    drawText(string, x, y, SWT.DRAW_DELIMITER | SWT.DRAW_TAB);
2182}
2183
2184/**
2185 * Draws the given string, using the receiver's current font and
2186 * foreground color. Tab expansion and carriage return processing
2187 * are performed. If <code>isTransparent</code> is <code>true</code>,
2188 * then the background of the rectangular area where the text is being
2189 * drawn will not be modified, otherwise it will be filled with the
2190 * receiver's background color.
2191 *
2192 * @param string the string to be drawn
2193 * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
2194 * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
2195 * @param isTransparent if <code>true</code> the background will be transparent, otherwise it will be opaque
2196 *
2197 * @exception IllegalArgumentException <ul>
2198 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
2199 * </ul>
2200 * @exception SWTException <ul>
2201 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2202 * </ul>
2203 */

2204public void drawText (String JavaDoc string, int x, int y, boolean isTransparent) {
2205    int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB;
2206    if (isTransparent) flags |= SWT.DRAW_TRANSPARENT;
2207    drawText(string, x, y, flags);
2208}
2209
2210/**
2211 * Draws the given string, using the receiver's current font and
2212 * foreground color. Tab expansion, line delimiter and mnemonic
2213 * processing are performed according to the specified flags. If
2214 * <code>flags</code> includes <code>DRAW_TRANSPARENT</code>,
2215 * then the background of the rectangular area where the text is being
2216 * drawn will not be modified, otherwise it will be filled with the
2217 * receiver's background color.
2218 * <p>
2219 * The parameter <code>flags</code> may be a combination of:
2220 * <dl>
2221 * <dt><b>DRAW_DELIMITER</b></dt>
2222 * <dd>draw multiple lines</dd>
2223 * <dt><b>DRAW_TAB</b></dt>
2224 * <dd>expand tabs</dd>
2225 * <dt><b>DRAW_MNEMONIC</b></dt>
2226 * <dd>underline the mnemonic character</dd>
2227 * <dt><b>DRAW_TRANSPARENT</b></dt>
2228 * <dd>transparent background</dd>
2229 * </dl>
2230 * </p>
2231 *
2232 * @param string the string to be drawn
2233 * @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
2234 * @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
2235 * @param flags the flags specifying how to process the text
2236 *
2237 * @exception IllegalArgumentException <ul>
2238 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
2239 * </ul>
2240 * @exception SWTException <ul>
2241 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2242 * </ul>
2243 */

2244public void drawText (String JavaDoc string, int x, int y, int flags) {
2245    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2246    if (string == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
2247    if (string.length() == 0) return;
2248    int gdipGraphics = data.gdipGraphics;
2249    if (gdipGraphics != 0) {
2250        checkGC(FONT | FOREGROUND | ((flags & SWT.DRAW_TRANSPARENT) != 0 ? 0 : BACKGROUND));
2251        int length = string.length();
2252        char[] buffer = new char [length];
2253        string.getChars(0, length, buffer, 0);
2254        PointF pt = new PointF();
2255        int format = Gdip.StringFormat_Clone(Gdip.StringFormat_GenericTypographic());
2256        int formatFlags = Gdip.StringFormat_GetFormatFlags(format) | Gdip.StringFormatFlagsMeasureTrailingSpaces;
2257        if ((data.style & SWT.MIRRORED) != 0) formatFlags |= Gdip.StringFormatFlagsDirectionRightToLeft;
2258        Gdip.StringFormat_SetFormatFlags(format, formatFlags);
2259        float[] tabs = (flags & SWT.DRAW_TAB) != 0 ? new float[]{measureSpace(data.gdipFont, format) * 8} : new float[1];
2260        Gdip.StringFormat_SetTabStops(format, 0, tabs.length, tabs);
2261        int hotkeyPrefix = (flags & SWT.DRAW_MNEMONIC) != 0 ? Gdip.HotkeyPrefixShow : Gdip.HotkeyPrefixNone;
2262        if ((flags & SWT.DRAW_MNEMONIC) != 0 && (data.uiState & OS.UISF_HIDEACCEL) != 0) hotkeyPrefix = Gdip.HotkeyPrefixHide;
2263        Gdip.StringFormat_SetHotkeyPrefix(format, hotkeyPrefix);
2264        if ((flags & SWT.DRAW_TRANSPARENT) == 0) {
2265            RectF bounds = new RectF();
2266            Gdip.Graphics_MeasureString(gdipGraphics, buffer, length, data.gdipFont, pt, format, bounds);
2267            Gdip.Graphics_FillRectangle(gdipGraphics, data.gdipBrush, x, y, Math.round(bounds.Width), Math.round(bounds.Height));
2268        }
2269        int gstate = 0, brush = getFgBrush();
2270        if ((data.style & SWT.MIRRORED) != 0) {
2271            switch (Gdip.Brush_GetType(brush)) {
2272                case Gdip.BrushTypeLinearGradient:
2273                    Gdip.LinearGradientBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
2274                    Gdip.LinearGradientBrush_TranslateTransform(brush, - 2 * x, 0, Gdip.MatrixOrderPrepend);
2275                    break;
2276                case Gdip.BrushTypeTextureFill:
2277                    Gdip.TextureBrush_ScaleTransform(brush, -1, 1, Gdip.MatrixOrderPrepend);
2278                    Gdip.TextureBrush_TranslateTransform(brush, - 2 * x, 0, Gdip.MatrixOrderPrepend);
2279                    break;
2280            }
2281            gstate = Gdip.Graphics_Save(gdipGraphics);
2282            Gdip.Graphics_ScaleTransform(gdipGraphics, -1, 1, Gdip.MatrixOrderPrepend);
2283            Gdip.Graphics_TranslateTransform(gdipGraphics, - 2 * x, 0, Gdip.MatrixOrderPrepend);
2284        }
2285        pt.X = x;
2286        pt.Y = y;
2287        Gdip.Graphics_DrawString(gdipGraphics, buffer, length, data.gdipFont, pt, format, brush);
2288        if ((data.style & SWT.MIRRORED) != 0) {
2289            switch (Gdip.Brush_GetType(brush)) {
2290                case Gdip.BrushTypeLinearGradient:
2291                    Gdip.LinearGradientBrush_ResetTransform(brush);
2292                    break;
2293                case Gdip.BrushTypeTextureFill:
2294                    Gdip.TextureBrush_ResetTransform(brush);
2295                    break;
2296            }
2297            Gdip.Graphics_Restore(gdipGraphics, gstate);
2298        }
2299        Gdip.StringFormat_delete(format);
2300        return;
2301    }
2302    TCHAR buffer = new TCHAR(getCodePage(), string, false);
2303    int length = buffer.length();
2304    if (length == 0) return;
2305    RECT rect = new RECT();
2306    /*
2307    * Feature in Windows. For some reason DrawText(), the maximum
2308    * value for the bottom and right coordinates for the RECT that
2309    * is used to position the text is different on between Windows
2310    * versions. If this value is larger than the maximum, nothing
2311    * is drawn. On Windows 98, the limit is 0x7FFF. On Windows CE,
2312    * NT, and 2000 it is 0x6FFFFFF. And on XP, it is 0x7FFFFFFF.
2313    * The fix is to use the the smaller limit for Windows 98 and the
2314    * larger limit on the other Windows platforms.
2315    */

2316    int limit = OS.IsWin95 ? 0x7FFF : 0x6FFFFFF;
2317    OS.SetRect(rect, x, y, limit, limit);
2318    int uFormat = OS.DT_LEFT;
2319    if ((flags & SWT.DRAW_DELIMITER) == 0) uFormat |= OS.DT_SINGLELINE;
2320    if ((flags & SWT.DRAW_TAB) != 0) uFormat |= OS.DT_EXPANDTABS;
2321    if ((flags & SWT.DRAW_MNEMONIC) == 0) uFormat |= OS.DT_NOPREFIX;
2322    if ((flags & SWT.DRAW_MNEMONIC) != 0 && (data.uiState & OS.UISF_HIDEACCEL) != 0) {
2323        uFormat |= OS.DT_HIDEPREFIX;
2324    }
2325    int rop2 = 0;
2326    if (OS.IsWinCE) {
2327        rop2 = OS.SetROP2(handle, OS.R2_COPYPEN);
2328        OS.SetROP2(handle, rop2);
2329    } else {
2330        rop2 = OS.GetROP2(handle);
2331    }
2332    checkGC(FONT | FOREGROUND_TEXT | BACKGROUND_TEXT);
2333    int oldBkMode = OS.SetBkMode(handle, (flags & SWT.DRAW_TRANSPARENT) != 0 ? OS.TRANSPARENT : OS.OPAQUE);
2334    if (rop2 != OS.R2_XORPEN) {
2335        OS.DrawText(handle, buffer, length, rect, uFormat);
2336    } else {
2337        int foreground = OS.GetTextColor(handle);
2338        if ((flags & SWT.DRAW_TRANSPARENT) != 0) {
2339            OS.DrawText(handle, buffer, buffer.length(), rect, uFormat | OS.DT_CALCRECT);
2340            int width = rect.right - rect.left;
2341            int height = rect.bottom - rect.top;
2342            int hBitmap = OS.CreateCompatibleBitmap(handle, width, height);
2343            if (hBitmap == 0) SWT.error(SWT.ERROR_NO_HANDLES);
2344            int memDC = OS.CreateCompatibleDC(handle);
2345            int hOldBitmap = OS.SelectObject(memDC, hBitmap);
2346            OS.PatBlt(memDC, 0, 0, width, height, OS.BLACKNESS);
2347            OS.SetBkMode(memDC, OS.TRANSPARENT);
2348            OS.SetTextColor(memDC, foreground);
2349            OS.SelectObject(memDC, OS.GetCurrentObject(handle, OS.OBJ_FONT));
2350            OS.SetRect(rect, 0, 0, 0x7FFF, 0x7FFF);
2351            OS.DrawText(memDC, buffer, length, rect, uFormat);
2352            OS.BitBlt(handle, x, y, width, height, memDC, 0, 0, OS.SRCINVERT);
2353            OS.SelectObject(memDC, hOldBitmap);
2354            OS.DeleteDC(memDC);
2355            OS.DeleteObject(hBitmap);
2356        } else {
2357            int background = OS.GetBkColor(handle);
2358            OS.SetTextColor(handle, foreground ^ background);
2359            OS.DrawText(handle, buffer, length, rect, uFormat);
2360            OS.SetTextColor(handle, foreground);
2361        }
2362    }
2363    OS.SetBkMode(handle, oldBkMode);
2364}
2365
2366/**
2367 * Compares the argument to the receiver, and returns true
2368 * if they represent the <em>same</em> object using a class
2369 * specific comparison.
2370 *
2371 * @param object the object to compare with this object
2372 * @return <code>true</code> if the object is the same as this object and <code>false</code> otherwise
2373 *
2374 * @see #hashCode
2375 */

2376public boolean equals (Object JavaDoc object) {
2377    return (object == this) || ((object instanceof GC) && (handle == ((GC)object).handle));
2378}
2379
2380/**
2381 * Fills the interior of a circular or elliptical arc within
2382 * the specified rectangular area, with the receiver's background
2383 * color.
2384 * <p>
2385 * The resulting arc begins at <code>startAngle</code> and extends
2386 * for <code>arcAngle</code> degrees, using the current color.
2387 * Angles are interpreted such that 0 degrees is at the 3 o'clock
2388 * position. A positive value indicates a counter-clockwise rotation
2389 * while a negative value indicates a clockwise rotation.
2390 * </p><p>
2391 * The center of the arc is the center of the rectangle whose origin
2392 * is (<code>x</code>, <code>y</code>) and whose size is specified by the
2393 * <code>width</code> and <code>height</code> arguments.
2394 * </p><p>
2395 * The resulting arc covers an area <code>width + 1</code> pixels wide
2396 * by <code>height + 1</code> pixels tall.
2397 * </p>
2398 *
2399 * @param x the x coordinate of the upper-left corner of the arc to be filled
2400 * @param y the y coordinate of the upper-left corner of the arc to be filled
2401 * @param width the width of the arc to be filled
2402 * @param height the height of the arc to be filled
2403 * @param startAngle the beginning angle
2404 * @param arcAngle the angular extent of the arc, relative to the start angle
2405 *
2406 * @exception SWTException <ul>
2407 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2408 * </ul>
2409 *
2410 * @see #drawArc
2411 */

2412public void fillArc (int x, int y, int width, int height, int startAngle, int arcAngle) {
2413    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2414    checkGC(FILL);
2415    if (width < 0) {
2416        x = x + width;
2417        width = -width;
2418    }
2419    if (height < 0) {
2420        y = y + height;
2421        height = -height;
2422    }
2423    if (width == 0 || height == 0 || arcAngle == 0) return;
2424    int gdipGraphics = data.gdipGraphics;
2425    if (gdipGraphics != 0) {
2426        if (width == height) {
2427            Gdip.Graphics_FillPie(gdipGraphics, data.gdipBrush, x, y, width, height, -startAngle, -arcAngle);
2428        } else {
2429            int state = Gdip.Graphics_Save(gdipGraphics);
2430            Gdip.Graphics_TranslateTransform(gdipGraphics, x, y, Gdip.MatrixOrderPrepend);
2431            Gdip.Graphics_ScaleTransform(gdipGraphics, width, height, Gdip.MatrixOrderPrepend);
2432            Gdip.Graphics_FillPie(gdipGraphics, data.gdipBrush, 0, 0, 1, 1, -startAngle, -arcAngle);
2433            Gdip.Graphics_Restore(gdipGraphics, state);
2434        }
2435        return;
2436    }
2437    
2438    if ((data.style & SWT.MIRRORED) != 0) x--;
2439    /*
2440    * Feature in WinCE. The function Pie is not present in the
2441    * WinCE SDK. The fix is to emulate it by using Polygon.
2442    */

2443    if (OS.IsWinCE) {
2444        /* compute arc with a simple linear interpolation */
2445        if (arcAngle < 0) {
2446            startAngle += arcAngle;
2447            arcAngle = -arcAngle;
2448        }
2449        boolean drawSegments = true;
2450        if (arcAngle >= 360) {
2451            arcAngle = 360;
2452            drawSegments = false;
2453        }
2454        int[] points = new int[(arcAngle + 1) * 2 + (drawSegments ? 4 : 0)];
2455        int cteX = 2 * x + width;
2456        int cteY = 2 * y + height;
2457        int index = (drawSegments ? 2 : 0);
2458        for (int i = 0; i <= arcAngle; i++) {
2459            points[index++] = (Compatibility.cos(startAngle + i, width) + cteX) >> 1;
2460            points[index++] = (cteY - Compatibility.sin(startAngle + i, height)) >> 1;
2461        }
2462        if (drawSegments) {
2463            points[0] = points[points.length - 2] = cteX >> 1;
2464            points[1] = points[points.length - 1] = cteY >> 1;
2465        }
2466        OS.Polygon(handle, points, points.length / 2);
2467    } else {
2468        int x1, y1, x2, y2,tmp;
2469        boolean isNegative;
2470        if (arcAngle >= 360 || arcAngle <= -360) {
2471            x1 = x2 = x + width;
2472            y1 = y2 = y + height / 2;
2473        } else {
2474            isNegative = arcAngle < 0;
2475    
2476            arcAngle = arcAngle + startAngle;
2477            if (isNegative) {
2478                // swap angles
2479
tmp = startAngle;
2480                startAngle = arcAngle;
2481                arcAngle = tmp;
2482            }
2483            x1 = Compatibility.cos(startAngle, width) + x + width/2;
2484            y1 = -1 * Compatibility.sin(startAngle, height) + y + height/2;
2485            
2486            x2 = Compatibility.cos(arcAngle, width) + x + width/2;
2487            y2 = -1 * Compatibility.sin(arcAngle, height) + y + height/2;
2488        }
2489        OS.Pie(handle, x, y, x + width + 1, y + height + 1, x1, y1, x2, y2);
2490    }
2491}
2492
2493/**
2494 * Fills the interior of the specified rectangle with a gradient
2495 * sweeping from left to right or top to bottom progressing
2496 * from the receiver's foreground color to its background color.
2497 *
2498 * @param x the x coordinate of the rectangle to be filled
2499 * @param y the y coordinate of the rectangle to be filled
2500 * @param width the width of the rectangle to be filled, may be negative
2501 * (inverts direction of gradient if horizontal)
2502 * @param height the height of the rectangle to be filled, may be negative
2503 * (inverts direction of gradient if vertical)
2504 * @param vertical if true sweeps from top to bottom, else
2505 * sweeps from left to right
2506 *
2507 * @exception SWTException <ul>
2508 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2509 * </ul>
2510 *
2511 * @see #drawRectangle(int, int, int, int)
2512 */

2513public void fillGradientRectangle(int x, int y, int width, int height, boolean vertical) {
2514    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2515    if (width == 0 || height == 0) return;
2516
2517    RGB backgroundRGB, foregroundRGB;
2518    backgroundRGB = getBackground().getRGB();
2519    foregroundRGB = getForeground().getRGB();
2520
2521    RGB fromRGB, toRGB;
2522    fromRGB = foregroundRGB;
2523    toRGB = backgroundRGB;
2524
2525    boolean swapColors = false;
2526    if (width < 0) {
2527        x += width; width = -width;
2528        if (! vertical) swapColors = true;
2529    }
2530    if (height < 0) {
2531        y += height; height = -height;
2532        if (vertical) swapColors = true;
2533    }
2534    if (swapColors) {
2535        fromRGB = backgroundRGB;
2536        toRGB = foregroundRGB;
2537    }
2538    if (fromRGB.equals(toRGB)) {
2539        fillRectangle(x, y, width, height);
2540        return;
2541    }
2542    if (data.gdipGraphics != 0) {
2543        initGdip();
2544        PointF p1= new PointF(), p2 = new PointF();
2545        p1.X = x;
2546        p1.Y = y;
2547        if (vertical) {
2548            p2.X = p1.X;
2549            p2.Y = p1.Y + height;
2550        } else {
2551            p2.X = p1.X + width;
2552            p2.Y = p1.Y;
2553        }
2554        int rgb = ((fromRGB.red & 0xFF) << 16) | ((fromRGB.green & 0xFF) << 8) | (fromRGB.blue & 0xFF);
2555        int fromGpColor = Gdip.Color_new(data.alpha << 24 | rgb);
2556        if (fromGpColor == 0) SWT.error(SWT.ERROR_NO_HANDLES);
2557        rgb = ((toRGB.red & 0xFF) << 16) | ((toRGB.green & 0xFF) << 8) | (toRGB.blue & 0xFF);
2558        int toGpColor = Gdip.Color_new(data.alpha << 24 | rgb);
2559        if (toGpColor == 0) SWT.error(SWT.ERROR_NO_HANDLES);
2560        int brush = Gdip.LinearGradientBrush_new(p1, p2, fromGpColor, toGpColor);
2561        Gdip.Graphics_FillRectangle(data.gdipGraphics, brush, x, y, width, height);
2562        Gdip.LinearGradientBrush_delete(brush);
2563        Gdip.Color_delete(fromGpColor);
2564        Gdip.Color_delete(toGpColor);
2565        return;
2566    }
2567    /* Use GradientFill if supported, only on Windows 98, 2000 and newer. */
2568    /*
2569    * Bug in Windows: On Windows 2000 when the device is a printer,
2570    * GradientFill swaps red and blue color components, causing the
2571    * gradient to be printed in the wrong color. On Windows 98 when
2572    * the device is a printer, GradientFill does not fill completely
2573    * to the right edge of the rectangle. The fix is not to use
2574    * GradientFill for printer devices.
2575    */

2576    int rop2 = 0;
2577    if (OS.IsWinCE) {
2578        rop2 = OS.SetROP2(handle, OS.R2_COPYPEN);
2579        OS.SetROP2(handle, rop2);
2580    } else {
2581        rop2 = OS.GetROP2(handle);
2582    }
2583    if (OS.IsWinNT && rop2 != OS.R2_XORPEN && OS.GetDeviceCaps(handle, OS.TECHNOLOGY) != OS.DT_RASPRINTER) {
2584        final int hHeap = OS.GetProcessHeap();
2585        final int pMesh = OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, GRADIENT_RECT.sizeof + TRIVERTEX.sizeof * 2);
2586        if (pMesh == 0) SWT.error(SWT.ERROR_NO_HANDLES);
2587        final int pVertex = pMesh + GRADIENT_RECT.sizeof;
2588    
2589        GRADIENT_RECT gradientRect = new GRADIENT_RECT();
2590        gradientRect.UpperLeft = 0;
2591        gradientRect.LowerRight = 1;
2592        OS.MoveMemory(pMesh, gradientRect, GRADIENT_RECT.sizeof);
2593    
2594        TRIVERTEX trivertex = new TRIVERTEX();
2595        trivertex.x = x;
2596        trivertex.y = y;
2597        trivertex.Red = (short)((fromRGB.red << 8) | fromRGB.red);
2598        trivertex.Green = (short)((fromRGB.green << 8) | fromRGB.green);
2599        trivertex.Blue = (short)((fromRGB.blue << 8) | fromRGB.blue);
2600        trivertex.Alpha = -1;
2601        OS.MoveMemory(pVertex, trivertex, TRIVERTEX.sizeof);
2602        
2603        trivertex.x = x + width;
2604        trivertex.y = y + height;
2605        trivertex.Red = (short)((toRGB.red << 8) | toRGB.red);
2606        trivertex.Green = (short)((toRGB.green << 8) | toRGB.green);
2607        trivertex.Blue = (short)((toRGB.blue << 8) | toRGB.blue);
2608        trivertex.Alpha = -1;
2609        OS.MoveMemory(pVertex + TRIVERTEX.sizeof, trivertex, TRIVERTEX.sizeof);
2610    
2611        boolean success = OS.GradientFill(handle, pVertex, 2, pMesh, 1, vertical ? OS.GRADIENT_FILL_RECT_V : OS.GRADIENT_FILL_RECT_H);
2612        OS.HeapFree(hHeap, 0, pMesh);
2613        if (success) return;
2614    }
2615    
2616    final int depth = OS.GetDeviceCaps(handle, OS.BITSPIXEL);
2617    final int bitResolution = (depth >= 24) ? 8 : (depth >= 15) ? 5 : 0;
2618    ImageData.fillGradientRectangle(this, data.device,
2619        x, y, width, height, vertical, fromRGB, toRGB,
2620        bitResolution, bitResolution, bitResolution);
2621}
2622
2623/**
2624 * Fills the interior of an oval, within the specified
2625 * rectangular area, with the receiver's background
2626 * color.
2627 *
2628 * @param x the x coordinate of the upper left corner of the oval to be filled
2629 * @param y the y coordinate of the upper left corner of the oval to be filled
2630 * @param width the width of the oval to be filled
2631 * @param height the height of the oval to be filled
2632 *
2633 * @exception SWTException <ul>
2634 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2635 * </ul>
2636 *
2637 * @see #drawOval
2638 */

2639public void fillOval (int x, int y, int width, int height) {
2640    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2641    checkGC(FILL);
2642    if (data.gdipGraphics != 0) {
2643        Gdip.Graphics_FillEllipse(data.gdipGraphics, data.gdipBrush, x, y, width, height);
2644        return;
2645    }
2646    if ((data.style & SWT.MIRRORED) != 0) x--;
2647    OS.Ellipse(handle, x, y, x + width + 1, y + height + 1);
2648}
2649
2650/**
2651 * Fills the path described by the parameter.
2652 * <p>
2653 * This operation requires the operating system's advanced
2654 * graphics subsystem which may not be available on some
2655 * platforms.
2656 * </p>
2657 *
2658 * @param path the path to fill
2659 *
2660 * @exception IllegalArgumentException <ul>
2661 * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
2662 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
2663 * </ul>
2664 * @exception SWTException <ul>
2665 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2666 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
2667 * </ul>
2668 *
2669 * @see Path
2670 *
2671 * @since 3.1
2672 */

2673public void fillPath (Path path) {
2674    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2675    if (path == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
2676    if (path.handle == 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
2677    initGdip();
2678    checkGC(FILL);
2679    int mode = OS.GetPolyFillMode(handle) == OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate;
2680    Gdip.GraphicsPath_SetFillMode(path.handle, mode);
2681    Gdip.Graphics_FillPath(data.gdipGraphics, data.gdipBrush, path.handle);
2682}
2683
2684/**
2685 * Fills the interior of the closed polygon which is defined by the
2686 * specified array of integer coordinates, using the receiver's
2687 * background color. The array contains alternating x and y values
2688 * which are considered to represent points which are the vertices of
2689 * the polygon. Lines are drawn between each consecutive pair, and
2690 * between the first pair and last pair in the array.
2691 *
2692 * @param pointArray an array of alternating x and y values which are the vertices of the polygon
2693 *
2694 * @exception IllegalArgumentException <ul>
2695 * <li>ERROR_NULL_ARGUMENT if pointArray is null</li>
2696 * </ul>
2697 * @exception SWTException <ul>
2698 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2699 * </ul>
2700 *
2701 * @see #drawPolygon
2702 */

2703public void fillPolygon(int[] pointArray) {
2704    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2705    if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
2706    checkGC(FILL);
2707    if (data.gdipGraphics != 0) {
2708        int mode = OS.GetPolyFillMode(handle) == OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate;
2709        Gdip.Graphics_FillPolygon(data.gdipGraphics, data.gdipBrush, pointArray, pointArray.length / 2, mode);
2710        return;
2711    }
2712    if ((data.style & SWT.MIRRORED) != 0) {
2713        for (int i = 0; i < pointArray.length; i+=2) {
2714            pointArray[i]--;
2715        }
2716    }
2717    OS.Polygon(handle, pointArray, pointArray.length / 2);
2718    if ((data.style & SWT.MIRRORED) != 0) {
2719        for (int i = 0; i < pointArray.length; i+=2) {
2720            pointArray[i]++;
2721        }
2722    }
2723}
2724
2725/**
2726 * Fills the interior of the rectangle specified by the arguments,
2727 * using the receiver's background color.
2728 *
2729 * @param x the x coordinate of the rectangle to be filled
2730 * @param y the y coordinate of the rectangle to be filled
2731 * @param width the width of the rectangle to be filled
2732 * @param height the height of the rectangle to be filled
2733 *
2734 * @exception SWTException <ul>
2735 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2736 * </ul>
2737 *
2738 * @see #drawRectangle(int, int, int, int)
2739 */

2740public void fillRectangle (int x, int y, int width, int height) {
2741    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2742    checkGC(FILL);
2743    if (data.gdipGraphics != 0) {
2744        Gdip.Graphics_FillRectangle(data.gdipGraphics, data.gdipBrush, x, y, width, height);
2745        return;
2746    }
2747    int rop2 = 0;
2748    if (OS.IsWinCE) {
2749        rop2 = OS.SetROP2(handle, OS.R2_COPYPEN);
2750        OS.SetROP2(handle, rop2);
2751    } else {
2752        rop2 = OS.GetROP2(handle);
2753    }
2754    int dwRop = rop2 == OS.R2_XORPEN ? OS.PATINVERT : OS.PATCOPY;
2755    OS.PatBlt(handle, x, y, width, height, dwRop);
2756}
2757
2758/**
2759 * Fills the interior of the specified rectangle, using the receiver's
2760 * background color.
2761 *
2762 * @param rect the rectangle to be filled
2763 *
2764 * @exception IllegalArgumentException <ul>
2765 * <li>ERROR_NULL_ARGUMENT - if the rectangle is null</li>
2766 * </ul>
2767 * @exception SWTException <ul>
2768 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2769 * </ul>
2770 *
2771 * @see #drawRectangle(int, int, int, int)
2772 */

2773public void fillRectangle (Rectangle rect) {
2774    if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
2775    fillRectangle (rect.x, rect.y, rect.width, rect.height);
2776}
2777
2778/**
2779 * Fills the interior of the round-cornered rectangle specified by
2780 * the arguments, using the receiver's background color.
2781 *
2782 * @param x the x coordinate of the rectangle to be filled
2783 * @param y the y coordinate of the rectangle to be filled
2784 * @param width the width of the rectangle to be filled
2785 * @param height the height of the rectangle to be filled
2786 * @param arcWidth the width of the arc
2787 * @param arcHeight the height of the arc
2788 *
2789 * @exception SWTException <ul>
2790 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2791 * </ul>
2792 *
2793 * @see #drawRoundRectangle
2794 */

2795public void fillRoundRectangle (int x, int y, int width, int height, int arcWidth, int arcHeight) {
2796    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2797    checkGC(FILL);
2798    if (data.gdipGraphics != 0) {
2799        fillRoundRectangleGdip(data.gdipGraphics, data.gdipBrush, x, y, width, height, arcWidth, arcHeight);
2800        return;
2801    }
2802    if ((data.style & SWT.MIRRORED) != 0) x--;
2803    OS.RoundRect(handle, x,y,x+width+1,y+height+1,arcWidth, arcHeight);
2804}
2805
2806void fillRoundRectangleGdip (int gdipGraphics, int brush, int x, int y, int width, int height, int arcWidth, int arcHeight) {
2807    int nx = x;
2808    int ny = y;
2809    int nw = width;
2810    int nh = height;
2811    int naw = arcWidth;
2812    int nah = arcHeight;
2813    
2814    if (nw < 0) {
2815        nw = 0 - nw;
2816        nx = nx - nw;
2817    }
2818    if (nh < 0) {
2819        nh = 0 - nh;
2820        ny = ny -nh;
2821    }
2822    if (naw < 0)
2823        naw = 0 - naw;
2824    if (nah < 0)
2825        nah = 0 - nah;
2826
2827    int path = Gdip.GraphicsPath_new(Gdip.FillModeAlternate);
2828    if (path == 0) SWT.error(SWT.ERROR_NO_HANDLES);
2829    if (nw > naw) {
2830        if (nh > nah) {
2831            Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nah, 0, -90);
2832            Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nah, -90, -90);
2833            Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, naw, nah, -180, -90);
2834            Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny + nh - nah, naw, nah, -270, -90);
2835        } else {
2836            Gdip.GraphicsPath_AddArc(path, nx + nw - naw, ny, naw, nh, -270, -180);
2837            Gdip.GraphicsPath_AddArc(path, nx, ny, naw, nh, -90, -180);
2838        }
2839    } else {
2840        if (nh > nah) {
2841            Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nah, 0, -180);
2842            Gdip.GraphicsPath_AddArc(path, nx, ny + nh - nah, nw, nah, -180, -180);
2843        } else {
2844            Gdip.GraphicsPath_AddArc(path, nx, ny, nw, nh, 0, 360);
2845        }
2846    }
2847    Gdip.GraphicsPath_CloseFigure(path);
2848    Gdip.Graphics_FillPath(gdipGraphics, brush, path);
2849    Gdip.GraphicsPath_delete(path);
2850}
2851
2852void flush () {
2853    if (data.gdipGraphics != 0) {
2854        Gdip.Graphics_Flush(data.gdipGraphics, 0);
2855        /*
2856        * Note Flush() does not flush the output to the
2857        * underline HDC. This is done by calling GetHDC()
2858        * followed by ReleaseHDC().
2859        */

2860        int hdc = Gdip.Graphics_GetHDC(data.gdipGraphics);
2861        Gdip.Graphics_ReleaseHDC(data.gdipGraphics, hdc);
2862    }
2863}
2864
2865/**
2866 * Returns the <em>advance width</em> of the specified character in
2867 * the font which is currently selected into the receiver.
2868 * <p>
2869 * The advance width is defined as the horizontal distance the cursor
2870 * should move after printing the character in the selected font.
2871 * </p>
2872 *
2873 * @param ch the character to measure
2874 * @return the distance in the x direction to move past the character before painting the next
2875 *
2876 * @exception SWTException <ul>
2877 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2878 * </ul>
2879 */

2880public int getAdvanceWidth(char ch) {
2881    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2882    checkGC(FONT);
2883    if (OS.IsWinCE) {
2884        SIZE size = new SIZE();
2885        OS.GetTextExtentPoint32W(handle, new char[]{ch}, 1, size);
2886        return size.cx;
2887    }
2888    int tch = ch;
2889    if (ch > 0x7F) {
2890        TCHAR buffer = new TCHAR(getCodePage(), ch, false);
2891        tch = buffer.tcharAt(0);
2892    }
2893    int[] width = new int[1];
2894    OS.GetCharWidth(handle, tch, tch, width);
2895    return width[0];
2896}
2897
2898/**
2899 * Returns <code>true</code> if receiver is using the operating system's
2900 * advanced graphics subsystem. Otherwise, <code>false</code> is returned
2901 * to indicate that normal graphics are in use.
2902 * <p>
2903 * Advanced graphics may not be installed for the operating system. In this
2904 * case, <code>false</code> is always returned. Some operating system have
2905 * only one graphics subsystem. If this subsystem supports advanced graphics,
2906 * then <code>true</code> is always returned. If any graphics operation such
2907 * as alpha, antialias, patterns, interpolation, paths, clipping or transformation
2908 * has caused the receiver to switch from regular to advanced graphics mode,
2909 * <code>true</code> is returned. If the receiver has been explicitly switched
2910 * to advanced mode and this mode is supported, <code>true</code> is returned.
2911 * </p>
2912 *
2913 * @return the advanced value
2914 *
2915 * @exception SWTException <ul>
2916 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2917 * </ul>
2918 *
2919 * @see #setAdvanced
2920 *
2921 * @since 3.1
2922 */

2923public boolean getAdvanced() {
2924    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2925    return data.gdipGraphics != 0;
2926}
2927
2928/**
2929 * Returns the receiver's alpha value.
2930 *
2931 * @return the alpha value
2932 *
2933 * @exception SWTException <ul>
2934 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2935 * </ul>
2936 *
2937 * @since 3.1
2938 */

2939public int getAlpha() {
2940    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2941    return data.alpha;
2942}
2943
2944/**
2945 * Returns the receiver's anti-aliasing setting value, which will be
2946 * one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or
2947 * <code>SWT.ON</code>. Note that this controls anti-aliasing for all
2948 * <em>non-text drawing</em> operations.
2949 *
2950 * @return the anti-aliasing setting
2951 *
2952 * @exception SWTException <ul>
2953 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2954 * </ul>
2955 *
2956 * @see #getTextAntialias
2957 *
2958 * @since 3.1
2959 */

2960public int getAntialias() {
2961    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2962    if (data.gdipGraphics == 0) return SWT.DEFAULT;
2963    int mode = Gdip.Graphics_GetSmoothingMode(data.gdipGraphics);
2964    switch (mode) {
2965        case Gdip.SmoothingModeDefault: return SWT.DEFAULT;
2966        case Gdip.SmoothingModeHighSpeed:
2967        case Gdip.SmoothingModeNone: return SWT.OFF;
2968        case Gdip.SmoothingModeAntiAlias:
2969        case Gdip.SmoothingModeAntiAlias8x8:
2970        case Gdip.SmoothingModeHighQuality: return SWT.ON;
2971    }
2972    return SWT.DEFAULT;
2973}
2974
2975/**
2976 * Returns the background color.
2977 *
2978 * @return the receiver's background color
2979 *
2980 * @exception SWTException <ul>
2981 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2982 * </ul>
2983 */

2984public Color getBackground() {
2985    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
2986    return Color.win32_new(data.device, data.background);
2987}
2988
2989/**
2990 * Returns the background pattern. The default value is
2991 * <code>null</code>.
2992 *
2993 * @return the receiver's background pattern
2994 *
2995 * @exception SWTException <ul>
2996 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
2997 * </ul>
2998 *
2999 * @see Pattern
3000 *
3001 * @since 3.1
3002 */

3003public Pattern getBackgroundPattern() {
3004    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3005    return data.backgroundPattern;
3006}
3007
3008/**
3009 * Returns the width of the specified character in the font
3010 * selected into the receiver.
3011 * <p>
3012 * The width is defined as the space taken up by the actual
3013 * character, not including the leading and tailing whitespace
3014 * or overhang.
3015 * </p>
3016 *
3017 * @param ch the character to measure
3018 * @return the width of the character
3019 *
3020 * @exception SWTException <ul>
3021 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3022 * </ul>
3023 */

3024public int getCharWidth(char ch) {
3025    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3026    checkGC(FONT);
3027    
3028    /* GetCharABCWidths only succeeds on truetype fonts */
3029    if (!OS.IsWinCE) {
3030        int tch = ch;
3031        if (ch > 0x7F) {
3032            TCHAR buffer = new TCHAR(getCodePage(), ch, false);
3033            tch = buffer.tcharAt (0);
3034        }
3035        int[] width = new int[3];
3036        if (OS.GetCharABCWidths(handle, tch, tch, width)) {
3037            return width[1];
3038        }
3039    }
3040    
3041    /* It wasn't a truetype font */
3042    TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
3043    OS.GetTextMetrics(handle, lptm);
3044    SIZE size = new SIZE();
3045    OS.GetTextExtentPoint32W(handle, new char[]{ch}, 1, size);
3046    return size.cx - lptm.tmOverhang;
3047}
3048
3049/**
3050 * Returns the bounding rectangle of the receiver's clipping
3051 * region. If no clipping region is set, the return value
3052 * will be a rectangle which covers the entire bounds of the
3053 * object the receiver is drawing on.
3054 *
3055 * @return the bounding rectangle of the clipping region
3056 *
3057 * @exception SWTException <ul>
3058 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3059 * </ul>
3060 */

3061public Rectangle getClipping() {
3062    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3063    int gdipGraphics = data.gdipGraphics;
3064    if (gdipGraphics != 0) {
3065        Rect rect = new Rect();
3066        Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone);
3067        Gdip.Graphics_GetVisibleClipBounds(gdipGraphics, rect);
3068        Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf);
3069        return new Rectangle(rect.X, rect.Y, rect.Width, rect.Height);
3070    }
3071    RECT rect = new RECT();
3072    OS.GetClipBox(handle, rect);
3073    return new Rectangle(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
3074}
3075
3076/**
3077 * Sets the region managed by the argument to the current
3078 * clipping region of the receiver.
3079 *
3080 * @param region the region to fill with the clipping region
3081 *
3082 * @exception IllegalArgumentException <ul>
3083 * <li>ERROR_NULL_ARGUMENT - if the region is null</li>
3084 * <li>ERROR_INVALID_ARGUMENT - if the region is disposed</li>
3085 * </ul>
3086 * @exception SWTException <ul>
3087 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3088 * </ul>
3089 */

3090public void getClipping (Region region) {
3091    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3092    if (region == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
3093    if (region.isDisposed()) SWT.error (SWT.ERROR_INVALID_ARGUMENT);
3094    int gdipGraphics = data.gdipGraphics;
3095    if (gdipGraphics != 0) {
3096        int rgn = Gdip.Region_new();
3097        Gdip.Graphics_GetClip(data.gdipGraphics, rgn);
3098        if (Gdip.Region_IsInfinite(rgn, gdipGraphics)) {
3099            Rect rect = new Rect();
3100            Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeNone);
3101            Gdip.Graphics_GetVisibleClipBounds(gdipGraphics, rect);
3102            Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf);
3103            OS.SetRectRgn(region.handle, rect.X, rect.Y, rect.X + rect.Width, rect.Y + rect.Height);
3104        } else {
3105            int matrix = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
3106            int identity = Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
3107            Gdip.Graphics_GetTransform(gdipGraphics, matrix);
3108            Gdip.Graphics_SetTransform(gdipGraphics, identity);
3109            int hRgn = Gdip.Region_GetHRGN(rgn, data.gdipGraphics);
3110            Gdip.Graphics_SetTransform(gdipGraphics, matrix);
3111            Gdip.Matrix_delete(identity);
3112            Gdip.Matrix_delete(matrix);
3113            OS.CombineRgn(region.handle, hRgn, 0, OS.RGN_COPY);
3114            OS.DeleteObject(hRgn);
3115        }
3116        Gdip.Region_delete(rgn);
3117        return;
3118    }
3119    POINT pt = new POINT ();
3120    if (!OS.IsWinCE) OS.GetWindowOrgEx (handle, pt);
3121    int result = OS.GetClipRgn (handle, region.handle);
3122    if (result != 1) {
3123        RECT rect = new RECT();
3124        OS.GetClipBox(handle, rect);
3125        OS.SetRectRgn(region.handle, rect.left, rect.top, rect.right, rect.bottom);
3126    } else {
3127        OS.OffsetRgn (region.handle, pt.x, pt.y);
3128    }
3129    if (!OS.IsWinCE) {
3130        int metaRgn = OS.CreateRectRgn (0, 0, 0, 0);
3131        if (OS.GetMetaRgn (handle, metaRgn) != 0) {
3132            OS.OffsetRgn (metaRgn, pt.x, pt.y);
3133            OS.CombineRgn (region.handle, metaRgn, region.handle, OS.RGN_AND);
3134        }
3135        OS.DeleteObject(metaRgn);
3136        int hwnd = data.hwnd;
3137        if (hwnd != 0 && data.ps != null) {
3138            int sysRgn = OS.CreateRectRgn (0, 0, 0, 0);
3139            if (OS.GetRandomRgn (handle, sysRgn, OS.SYSRGN) == 1) {
3140                if (OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
3141                    if ((OS.GetLayout(handle) & OS.LAYOUT_RTL) != 0) {
3142                        int nBytes = OS.GetRegionData (sysRgn, 0, null);
3143                        int [] lpRgnData = new int [nBytes / 4];
3144                        OS.GetRegionData (sysRgn, nBytes, lpRgnData);
3145                        int newSysRgn = OS.ExtCreateRegion(new float [] {-1, 0, 0, 1, 0, 0}, nBytes, lpRgnData);
3146                        OS.DeleteObject(sysRgn);
3147                        sysRgn = newSysRgn;
3148                    }
3149                }
3150                if (OS.IsWinNT) {
3151                    OS.MapWindowPoints(0, hwnd, pt, 1);
3152                    OS.OffsetRgn(sysRgn, pt.x, pt.y);
3153                }
3154                OS.CombineRgn (region.handle, sysRgn, region.handle, OS.RGN_AND);
3155            }
3156            OS.DeleteObject(sysRgn);
3157        }
3158    }
3159}
3160
3161int getCodePage () {
3162    if (OS.IsUnicode) return OS.CP_ACP;
3163    int[] lpCs = new int[8];
3164    int cs = OS.GetTextCharset(handle);
3165    OS.TranslateCharsetInfo(cs, lpCs, OS.TCI_SRCCHARSET);
3166    return lpCs[1];
3167}
3168
3169int getFgBrush() {
3170    return data.foregroundPattern != null ? data.foregroundPattern.handle : data.gdipFgBrush;
3171}
3172
3173/**
3174 * Returns the receiver's fill rule, which will be one of
3175 * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>.
3176 *
3177 * @return the receiver's fill rule
3178 *
3179 * @exception SWTException <ul>
3180 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3181 * </ul>
3182 *
3183 * @since 3.1
3184 */

3185public int getFillRule() {
3186    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3187    if (OS.IsWinCE) return SWT.FILL_EVEN_ODD;
3188    return OS.GetPolyFillMode(handle) == OS.WINDING ? SWT.FILL_WINDING : SWT.FILL_EVEN_ODD;
3189}
3190
3191/**
3192 * Returns the font currently being used by the receiver
3193 * to draw and measure text.
3194 *
3195 * @return the receiver's font
3196 *
3197 * @exception SWTException <ul>
3198 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3199 * </ul>
3200 */

3201public Font getFont () {
3202    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3203    return Font.win32_new(data.device, data.hFont);
3204}
3205
3206/**
3207 * Returns a FontMetrics which contains information
3208 * about the font currently being used by the receiver
3209 * to draw and measure text.
3210 *
3211 * @return font metrics for the receiver's font
3212 *
3213 * @exception SWTException <ul>
3214 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3215 * </ul>
3216 */

3217public FontMetrics getFontMetrics() {
3218    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3219    checkGC(FONT);
3220    TEXTMETRIC lptm = OS.IsUnicode ? (TEXTMETRIC)new TEXTMETRICW() : new TEXTMETRICA();
3221    OS.GetTextMetrics(handle, lptm);
3222    return FontMetrics.win32_new(lptm);
3223}
3224
3225/**
3226 * Returns the receiver's foreground color.
3227 *
3228 * @return the color used for drawing foreground things
3229 *
3230 * @exception SWTException <ul>
3231 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3232 * </ul>
3233 */

3234public Color getForeground() {
3235    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3236    return Color.win32_new(data.device, data.foreground);
3237}
3238
3239/**
3240 * Returns the foreground pattern. The default value is
3241 * <code>null</code>.
3242 *
3243 * @return the receiver's foreground pattern
3244 *
3245 * @exception SWTException <ul>
3246 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3247 * </ul>
3248 *
3249 * @see Pattern
3250 *
3251 * @since 3.1
3252 */

3253public Pattern getForegroundPattern() {
3254    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3255    return data.foregroundPattern;
3256}
3257
3258/**
3259 * Returns the GCData.
3260 * <p>
3261 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
3262 * API for <code>GC</code>. It is marked public only so that it
3263 * can be shared within the packages provided by SWT. It is not
3264 * available on all platforms, and should never be called from
3265 * application code.
3266 * </p>
3267 *
3268 * @return the receiver's GCData
3269 *
3270 * @exception SWTException <ul>
3271 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3272 * </ul>
3273 *
3274 * @see GCData
3275 *
3276 * @since 3.2
3277 */

3278public GCData getGCData() {
3279    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3280    return data;
3281}
3282
3283/**
3284 * Returns the receiver's interpolation setting, which will be one of
3285 * <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>,
3286 * <code>SWT.LOW</code> or <code>SWT.HIGH</code>.
3287 *
3288 * @return the receiver's interpolation setting
3289 *
3290 * @exception SWTException <ul>
3291 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3292 * </ul>
3293 *
3294 * @since 3.1
3295 */

3296public int getInterpolation() {
3297    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3298    if (data.gdipGraphics == 0) return SWT.DEFAULT;
3299    int mode = Gdip.Graphics_GetInterpolationMode(data.gdipGraphics);
3300    switch (mode) {
3301        case Gdip.InterpolationModeDefault: return SWT.DEFAULT;
3302        case Gdip.InterpolationModeNearestNeighbor: return SWT.NONE;
3303        case Gdip.InterpolationModeBilinear:
3304        case Gdip.InterpolationModeLowQuality: return SWT.LOW;
3305        case Gdip.InterpolationModeBicubic:
3306        case Gdip.InterpolationModeHighQualityBilinear:
3307        case Gdip.InterpolationModeHighQualityBicubic:
3308        case Gdip.InterpolationModeHighQuality: return SWT.HIGH;
3309    }
3310    return SWT.DEFAULT;
3311}
3312
3313/**
3314 * Returns the receiver's line attributes.
3315 *
3316 * @return the line attributes used for drawing lines
3317 *
3318 * @exception SWTException <ul>
3319 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3320 * </ul>
3321 *
3322 * @since 3.3
3323 */

3324public LineAttributes getLineAttributes() {
3325    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3326    float[] dashes = null;
3327    if (data.lineDashes != null) {
3328        dashes = new float[data.lineDashes.length];
3329        System.arraycopy(data.lineDashes, 0, dashes, 0, dashes.length);
3330    }
3331    return new LineAttributes(data.lineWidth, data.lineCap, data.lineJoin, data.lineStyle, dashes, data.lineDashesOffset, data.lineMiterLimit);
3332}
3333
3334/**
3335 * Returns the receiver's line cap style, which will be one
3336 * of the constants <code>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>,
3337 * or <code>SWT.CAP_SQUARE</code>.
3338 *
3339 * @return the cap style used for drawing lines
3340 *
3341 * @exception SWTException <ul>
3342 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3343 * </ul>
3344 *
3345 * @since 3.1
3346 */

3347public int getLineCap() {
3348    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3349    return data.lineCap;
3350}
3351
3352/**
3353 * Returns the receiver's line dash style. The default value is
3354 * <code>null</code>.
3355 *
3356 * @return the line dash style used for drawing lines
3357 *
3358 * @exception SWTException <ul>
3359 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3360 * </ul>
3361 *
3362 * @since 3.1
3363 */

3364public int[] getLineDash() {
3365    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3366    if (data.lineDashes == null) return null;
3367    int[] lineDashes = new int[data.lineDashes.length];
3368    for (int i = 0; i < lineDashes.length; i++) {
3369        lineDashes[i] = (int)data.lineDashes[i];
3370    }
3371    return lineDashes;
3372}
3373
3374/**
3375 * Returns the receiver's line join style, which will be one
3376 * of the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>,
3377 * or <code>SWT.JOIN_BEVEL</code>.
3378 *
3379 * @return the join style used for drawing lines
3380 *
3381 * @exception SWTException <ul>
3382 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3383 * </ul>
3384 *
3385 * @since 3.1
3386 */

3387public int getLineJoin() {
3388    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3389    return data.lineJoin;
3390}
3391
3392/**
3393 * Returns the receiver's line style, which will be one
3394 * of the constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>,
3395 * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or
3396 * <code>SWT.LINE_DASHDOTDOT</code>.
3397 *
3398 * @return the style used for drawing lines
3399 *
3400 * @exception SWTException <ul>
3401 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3402 * </ul>
3403 */

3404public int getLineStyle() {
3405    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3406    return data.lineStyle;
3407}
3408
3409/**
3410 * Returns the width that will be used when drawing lines
3411 * for all of the figure drawing operations (that is,
3412 * <code>drawLine</code>, <code>drawRectangle</code>,
3413 * <code>drawPolyline</code>, and so forth.
3414 *
3415 * @return the receiver's line width
3416 *
3417 * @exception SWTException <ul>
3418 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3419 * </ul>
3420 */

3421public int getLineWidth() {
3422    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3423    return (int)data.lineWidth;
3424}
3425
3426/**
3427 * Returns the receiver's style information.
3428 * <p>
3429 * Note that the value which is returned by this method <em>may
3430 * not match</em> the value which was provided to the constructor
3431 * when the receiver was created. This can occur when the underlying
3432 * operating system does not support a particular combination of
3433 * requested styles.
3434 * </p>
3435 *
3436 * @return the style bits
3437 *
3438 * @exception SWTException <ul>
3439 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3440 * </ul>
3441 *
3442 * @since 2.1.2
3443 */

3444public int getStyle () {
3445    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3446    return data.style;
3447}
3448
3449/**
3450 * Returns the receiver's text drawing anti-aliasing setting value,
3451 * which will be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code> or
3452 * <code>SWT.ON</code>. Note that this controls anti-aliasing
3453 * <em>only</em> for text drawing operations.
3454 *
3455 * @return the anti-aliasing setting
3456 *
3457 * @exception SWTException <ul>
3458 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3459 * </ul>
3460 *
3461 * @see #getAntialias
3462 *
3463 * @since 3.1
3464 */

3465public int getTextAntialias() {
3466    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3467    if (data.gdipGraphics == 0) return SWT.DEFAULT;
3468    int mode = Gdip.Graphics_GetTextRenderingHint(data.gdipGraphics);
3469    switch (mode) {
3470        case Gdip.TextRenderingHintSystemDefault: return SWT.DEFAULT;
3471        case Gdip.TextRenderingHintSingleBitPerPixel:
3472        case Gdip.TextRenderingHintSingleBitPerPixelGridFit: return SWT.OFF;
3473        case Gdip.TextRenderingHintAntiAlias:
3474        case Gdip.TextRenderingHintAntiAliasGridFit:
3475        case Gdip.TextRenderingHintClearTypeGridFit: return SWT.ON;
3476    }
3477    return SWT.DEFAULT;
3478}
3479
3480/**
3481 * Sets the parameter to the transform that is currently being
3482 * used by the receiver.
3483 *
3484 * @param transform the destination to copy the transform into
3485 *
3486 * @exception IllegalArgumentException <ul>
3487 * <li>ERROR_NULL_ARGUMENT - if the parameter is null</li>
3488 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
3489 * </ul>
3490 * @exception SWTException <ul>
3491 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3492 * </ul>
3493 *
3494 * @see Transform
3495 *
3496 * @since 3.1
3497 */

3498public void getTransform(Transform transform) {
3499    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3500    if (transform == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
3501    if (transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
3502    int gdipGraphics = data.gdipGraphics;
3503    if (gdipGraphics != 0) {
3504        Gdip.Graphics_GetTransform(gdipGraphics, transform.handle);
3505        int identity = identity();
3506        Gdip.Matrix_Invert(identity);
3507        Gdip.Matrix_Multiply(transform.handle, identity, Gdip.MatrixOrderAppend);
3508        Gdip.Matrix_delete(identity);
3509    } else {
3510        transform.setElements(1, 0, 0, 1, 0, 0);
3511    }
3512}
3513
3514/**
3515 * Returns <code>true</code> if this GC is drawing in the mode
3516 * where the resulting color in the destination is the
3517 * <em>exclusive or</em> of the color values in the source
3518 * and the destination, and <code>false</code> if it is
3519 * drawing in the mode where the destination color is being
3520 * replaced with the source color value.
3521 *
3522 * @return <code>true</code> true if the receiver is in XOR mode, and false otherwise
3523 *
3524 * @exception SWTException <ul>
3525 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3526 * </ul>
3527 */

3528public boolean getXORMode() {
3529    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3530    int rop2 = 0;
3531    if (OS.IsWinCE) {
3532        rop2 = OS.SetROP2 (handle, OS.R2_COPYPEN);
3533        OS.SetROP2 (handle, rop2);
3534    } else {
3535        rop2 = OS.GetROP2(handle);
3536    }
3537    return rop2 == OS.R2_XORPEN;
3538}
3539
3540void initGdip() {
3541    data.device.checkGDIP();
3542    int gdipGraphics = data.gdipGraphics;
3543    if (gdipGraphics != 0) return;
3544    /*
3545    * Feature in GDI+. The GDI+ clipping set with Graphics->SetClip()
3546    * is always intersected with the GDI clipping at the time the
3547    * GDI+ graphics is created. This means that the clipping
3548    * cannot be reset. The fix is to clear the clipping before
3549    * the GDI+ graphics is created and reset it afterwards.
3550    */

3551    int hRgn = OS.CreateRectRgn(0, 0, 0, 0);
3552    int result = OS.GetClipRgn(handle, hRgn);
3553    if (!OS.IsWinCE) {
3554        POINT pt = new POINT ();
3555        OS.GetWindowOrgEx (handle, pt);
3556        OS.OffsetRgn (hRgn, pt.x, pt.y);
3557    }
3558    OS.SelectClipRgn(handle, 0);
3559
3560    /*
3561    * Bug in GDI+. GDI+ does not work when the HDC layout is RTL. There
3562    * are many issues like pixel corruption, but the most visible problem
3563    * is that it does not have an effect when drawing to an bitmap. The
3564    * fix is to clear the bit before creating the GDI+ graphics and install
3565    * a mirroring matrix ourselves.
3566    */

3567    if ((data.style & SWT.MIRRORED) != 0) {
3568        OS.SetLayout(handle, OS.GetLayout(handle) & ~OS.LAYOUT_RTL);
3569    }
3570
3571    gdipGraphics = data.gdipGraphics = Gdip.Graphics_new(handle);
3572    if (gdipGraphics == 0) SWT.error(SWT.ERROR_NO_HANDLES);
3573    Gdip.Graphics_SetPageUnit(gdipGraphics, Gdip.UnitPixel);
3574    Gdip.Graphics_SetPixelOffsetMode(gdipGraphics, Gdip.PixelOffsetModeHalf);
3575    if ((data.style & SWT.MIRRORED) != 0) {
3576        int matrix = identity();
3577        Gdip.Graphics_SetTransform(gdipGraphics, matrix);
3578        Gdip.Matrix_delete(matrix);
3579    }
3580    if (result == 1) setClipping(hRgn);
3581    OS.DeleteObject(hRgn);
3582    data.state = 0;
3583    if (data.hPen != 0) {
3584        OS.SelectObject(handle, OS.GetStockObject(OS.NULL_PEN));
3585        OS.DeleteObject(data.hPen);
3586        data.hPen = 0;
3587    }
3588    if (data.hBrush != 0) {
3589        OS.SelectObject(handle, OS.GetStockObject(OS.NULL_BRUSH));
3590        OS.DeleteObject(data.hBrush);
3591        data.hBrush = 0;
3592    }
3593}
3594
3595int identity() {
3596    if ((data.style & SWT.MIRRORED) != 0) {
3597        int width = 0;
3598        Image image = data.image;
3599        if (image != null) {
3600            BITMAP bm = new BITMAP();
3601            OS.GetObject(image.handle, BITMAP.sizeof, bm);
3602            width = bm.bmWidth;
3603        } else if (data.hwnd != 0) {
3604            RECT rect = new RECT();
3605            OS.GetClientRect(data.hwnd, rect);
3606            width = rect.right - rect.left;
3607        }
3608        POINT pt = new POINT ();
3609        if (!OS.IsWinCE) OS.GetWindowOrgEx (handle, pt);
3610        return Gdip.Matrix_new(-1, 0, 0, 1, width + 2 * pt.x, 0);
3611    }
3612    return Gdip.Matrix_new(1, 0, 0, 1, 0, 0);
3613}
3614
3615void init(Drawable drawable, GCData data, int hDC) {
3616    int foreground = data.foreground;
3617    if (foreground != -1) {
3618        data.state &= ~(FOREGROUND | FOREGROUND_TEXT | PEN);
3619    } else {
3620        data.foreground = OS.GetTextColor(hDC);
3621    }
3622    int background = data.background;
3623    if (background != -1) {
3624        data.state &= ~(BACKGROUND | BACKGROUND_TEXT | BRUSH);
3625    } else {
3626        data.background = OS.GetBkColor(hDC);
3627    }
3628    data.state &= ~(NULL_BRUSH | NULL_PEN);
3629    int hFont = data.hFont;
3630    if (hFont != 0 && hFont != -1) {
3631        data.state &= ~FONT;
3632    } else {
3633        data.hFont = OS.GetCurrentObject(hDC, OS.OBJ_FONT);
3634    }
3635    int hPalette = data.device.hPalette;
3636    if (hPalette != 0) {
3637        OS.SelectPalette(hDC, hPalette, true);
3638        OS.RealizePalette(hDC);
3639    }
3640    Image image = data.image;
3641    if (image != null) {
3642        data.hNullBitmap = OS.SelectObject(hDC, image.handle);
3643        image.memGC = this;
3644    }
3645    int layout = data.layout;
3646    if (layout != -1) {
3647        if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) {
3648            int flags = OS.GetLayout(hDC);
3649            if ((flags & OS.LAYOUT_RTL) != (layout & OS.LAYOUT_RTL)) {
3650                flags &= ~OS.LAYOUT_RTL;
3651                OS.SetLayout(hDC, flags | layout);
3652            }
3653            if ((data.style & SWT.RIGHT_TO_LEFT) != 0) data.style |= SWT.MIRRORED;
3654        }
3655    }
3656    this.drawable = drawable;
3657    this.data = data;
3658    handle = hDC;
3659}
3660
3661/**
3662 * Returns an integer hash code for the receiver. Any two
3663 * objects that return <code>true</code> when passed to
3664 * <code>equals</code> must return the same value for this
3665 * method.
3666 *
3667 * @return the receiver's hash
3668 *
3669 * @exception SWTException <ul>
3670 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3671 * </ul>
3672 *
3673 * @see #equals
3674 */

3675public int hashCode () {
3676    return handle;
3677}
3678
3679/**
3680 * Returns <code>true</code> if the receiver has a clipping
3681 * region set into it, and <code>false</code> otherwise.
3682 * If this method returns false, the receiver will draw on all
3683 * available space in the destination. If it returns true,
3684 * it will draw only in the area that is covered by the region
3685 * that can be accessed with <code>getClipping(region)</code>.
3686 *
3687 * @return <code>true</code> if the GC has a clipping region, and <code>false</code> otherwise
3688 *
3689 * @exception SWTException <ul>
3690 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3691 * </ul>
3692 */

3693public boolean isClipped() {
3694    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3695    int region = OS.CreateRectRgn(0, 0, 0, 0);
3696    int result = OS.GetClipRgn(handle, region);
3697    OS.DeleteObject(region);
3698    return result > 0;
3699}
3700
3701/**
3702 * Returns <code>true</code> if the GC has been disposed,
3703 * and <code>false</code> otherwise.
3704 * <p>
3705 * This method gets the dispose state for the GC.
3706 * When a GC has been disposed, it is an error to
3707 * invoke any other method using the GC.
3708 *
3709 * @return <code>true</code> when the GC is disposed and <code>false</code> otherwise
3710 */

3711public boolean isDisposed() {
3712    return handle == 0;
3713}
3714
3715float measureSpace(int font, int format) {
3716    PointF pt = new PointF();
3717    RectF bounds = new RectF();
3718    Gdip.Graphics_MeasureString(data.gdipGraphics, new char[]{' '}, 1, font, pt, format, bounds);
3719    return bounds.Width;
3720}
3721
3722/**
3723 * Sets the receiver to always use the operating system's advanced graphics
3724 * subsystem for all graphics operations if the argument is <code>true</code>.
3725 * If the argument is <code>false</code>, the advanced graphics subsystem is
3726 * no longer used, advanced graphics state is cleared and the normal graphics
3727 * subsystem is used from now on.
3728 * <p>
3729 * Normally, the advanced graphics subsystem is invoked automatically when
3730 * any one of the alpha, antialias, patterns, interpolation, paths, clipping
3731 * or transformation operations in the receiver is requested. When the receiver
3732 * is switched into advanced mode, the advanced graphics subsystem performs both
3733 * advanced and normal graphics operations. Because the two subsystems are
3734 * different, their output may differ. Switching to advanced graphics before
3735 * any graphics operations are performed ensures that the output is consistent.
3736 * </p><p>
3737 * Advanced graphics may not be installed for the operating system. In this
3738 * case, this operation does nothing. Some operating system have only one
3739 * graphics subsystem, so switching from normal to advanced graphics does
3740 * nothing. However, switching from advanced to normal graphics will always
3741 * clear the advanced graphics state, even for operating systems that have
3742 * only one graphics subsystem.
3743 * </p>
3744 *
3745 * @param advanced the new advanced graphics state
3746 *
3747 * @exception SWTException <ul>
3748 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3749 * </ul>
3750 *
3751 * @see #setAlpha
3752 * @see #setAntialias
3753 * @see #setBackgroundPattern
3754 * @see #setClipping(Path)
3755 * @see #setForegroundPattern
3756 * @see #setLineAttributes
3757 * @see #setInterpolation
3758 * @see #setTextAntialias
3759 * @see #setTransform
3760 * @see #getAdvanced
3761 *
3762 * @since 3.1
3763 */

3764public void setAdvanced(boolean advanced) {
3765    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3766    if (advanced && data.gdipGraphics != 0) return;
3767    if (advanced) {
3768        try {
3769            initGdip();
3770        } catch (SWTException e) {}
3771    } else {
3772        disposeGdip();
3773        data.alpha = 0xFF;
3774        data.backgroundPattern = data.foregroundPattern = null;
3775        data.state = 0;
3776        setClipping(0);
3777        if ((data.style & SWT.MIRRORED) != 0) {
3778            OS.SetLayout(handle, OS.GetLayout(handle) | OS.LAYOUT_RTL);
3779        }
3780    }
3781}
3782
3783/**
3784 * Sets the receiver's anti-aliasing value to the parameter,
3785 * which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code>
3786 * or <code>SWT.ON</code>. Note that this controls anti-aliasing for all
3787 * <em>non-text drawing</em> operations.
3788 * <p>
3789 * This operation requires the operating system's advanced
3790 * graphics subsystem which may not be available on some
3791 * platforms.
3792 * </p>
3793 *
3794 * @param antialias the anti-aliasing setting
3795 *
3796 * @exception IllegalArgumentException <ul>
3797 * <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>SWT.DEFAULT</code>,
3798 * <code>SWT.OFF</code> or <code>SWT.ON</code></li>
3799 * </ul>
3800 * @exception SWTException <ul>
3801 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3802 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
3803 * </ul>
3804 *
3805 * @see #getAdvanced
3806 * @see #setAdvanced
3807 * @see #setTextAntialias
3808 *
3809 * @since 3.1
3810 */

3811public void setAntialias(int antialias) {
3812    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3813    if (data.gdipGraphics == 0 && antialias == SWT.DEFAULT) return;
3814    int mode = 0;
3815    switch (antialias) {
3816        case SWT.DEFAULT:
3817            mode = Gdip.SmoothingModeDefault;
3818            break;
3819        case SWT.OFF:
3820            mode = Gdip.SmoothingModeNone;
3821            break;
3822        case SWT.ON:
3823            mode = Gdip.SmoothingModeAntiAlias;
3824            break;
3825        default:
3826            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
3827    }
3828    initGdip();
3829    Gdip.Graphics_SetSmoothingMode(data.gdipGraphics, mode);
3830}
3831
3832/**
3833 * Sets the receiver's alpha value.
3834 * <p>
3835 * This operation requires the operating system's advanced
3836 * graphics subsystem which may not be available on some
3837 * platforms.
3838 * </p>
3839 * @param alpha the alpha value
3840 *
3841 * @exception SWTException <ul>
3842 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3843 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
3844 * </ul>
3845 *
3846 * @see #getAdvanced
3847 * @see #setAdvanced
3848 *
3849 * @since 3.1
3850 */

3851public void setAlpha(int alpha) {
3852    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3853    if (data.gdipGraphics == 0 && (alpha & 0xFF) == 0xFF) return;
3854    initGdip();
3855    data.alpha = alpha & 0xFF;
3856    data.state &= ~(BACKGROUND | FOREGROUND);
3857}
3858
3859/**
3860 * Sets the background color. The background color is used
3861 * for fill operations and as the background color when text
3862 * is drawn.
3863 *
3864 * @param color the new background color for the receiver
3865 *
3866 * @exception IllegalArgumentException <ul>
3867 * <li>ERROR_NULL_ARGUMENT - if the color is null</li>
3868 * <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
3869 * </ul>
3870 * @exception SWTException <ul>
3871 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3872 * </ul>
3873 */

3874public void setBackground (Color color) {
3875    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3876    if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
3877    if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
3878    if (data.backgroundPattern == null && data.background == color.handle) return;
3879    data.backgroundPattern = null;
3880    data.background = color.handle;
3881    data.state &= ~(BACKGROUND | BACKGROUND_TEXT);
3882}
3883
3884/**
3885 * Sets the background pattern. The default value is <code>null</code>.
3886 * <p>
3887 * This operation requires the operating system's advanced
3888 * graphics subsystem which may not be available on some
3889 * platforms.
3890 * </p>
3891 *
3892 * @param pattern the new background pattern
3893 *
3894 * @exception IllegalArgumentException <ul>
3895 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
3896 * </ul>
3897 * @exception SWTException <ul>
3898 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3899 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
3900 * </ul>
3901 *
3902 * @see Pattern
3903 * @see #getAdvanced
3904 * @see #setAdvanced
3905 *
3906 * @since 3.1
3907 */

3908public void setBackgroundPattern (Pattern pattern) {
3909    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3910    if (pattern != null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
3911    if (data.gdipGraphics == 0 && pattern == null) return;
3912    initGdip();
3913    if (data.backgroundPattern == pattern) return;
3914    data.backgroundPattern = pattern;
3915    data.state &= ~BACKGROUND;
3916}
3917
3918void setClipping(int clipRgn) {
3919    int hRgn = clipRgn;
3920    int gdipGraphics = data.gdipGraphics;
3921    if (gdipGraphics != 0) {
3922        if (hRgn != 0) {
3923            int region = Gdip.Region_new(hRgn);
3924            Gdip.Graphics_SetClip(gdipGraphics, region, Gdip.CombineModeReplace);
3925            Gdip.Region_delete(region);
3926        } else {
3927            Gdip.Graphics_ResetClip(gdipGraphics);
3928        }
3929    } else {
3930        POINT pt = null;
3931        if (hRgn != 0 && !OS.IsWinCE) {
3932            pt = new POINT();
3933            OS.GetWindowOrgEx(handle, pt);
3934            OS.OffsetRgn(hRgn, -pt.x, -pt.y);
3935        }
3936        OS.SelectClipRgn(handle, hRgn);
3937        if (hRgn != 0 && !OS.IsWinCE) {
3938            OS.OffsetRgn(hRgn, pt.x, pt.y);
3939        }
3940    }
3941    if (hRgn != 0 && hRgn != clipRgn) {
3942        OS.DeleteObject(hRgn);
3943    }
3944}
3945
3946/**
3947 * Sets the area of the receiver which can be changed
3948 * by drawing operations to the rectangular area specified
3949 * by the arguments.
3950 *
3951 * @param x the x coordinate of the clipping rectangle
3952 * @param y the y coordinate of the clipping rectangle
3953 * @param width the width of the clipping rectangle
3954 * @param height the height of the clipping rectangle
3955 *
3956 * @exception SWTException <ul>
3957 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3958 * </ul>
3959 */

3960public void setClipping (int x, int y, int width, int height) {
3961    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3962    int hRgn = OS.CreateRectRgn(x, y, x + width, y + height);
3963    setClipping(hRgn);
3964    OS.DeleteObject(hRgn);
3965}
3966
3967/**
3968 * Sets the area of the receiver which can be changed
3969 * by drawing operations to the path specified
3970 * by the argument.
3971 * <p>
3972 * This operation requires the operating system's advanced
3973 * graphics subsystem which may not be available on some
3974 * platforms.
3975 * </p>
3976 *
3977 * @param path the clipping path.
3978 *
3979 * @exception IllegalArgumentException <ul>
3980 * <li>ERROR_INVALID_ARGUMENT - if the path has been disposed</li>
3981 * </ul>
3982 * @exception SWTException <ul>
3983 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
3984 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
3985 * </ul>
3986 *
3987 * @see Path
3988 * @see #getAdvanced
3989 * @see #setAdvanced
3990 *
3991 * @since 3.1
3992 */

3993public void setClipping (Path path) {
3994    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
3995    if (path != null && path.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
3996    setClipping(0);
3997    if (path != null) {
3998        initGdip();
3999        int mode = OS.GetPolyFillMode(handle) == OS.WINDING ? Gdip.FillModeWinding : Gdip.FillModeAlternate;
4000        Gdip.GraphicsPath_SetFillMode(path.handle, mode);
4001        Gdip.Graphics_SetClip(data.gdipGraphics, path.handle);
4002    }
4003}
4004
4005/**
4006 * Sets the area of the receiver which can be changed
4007 * by drawing operations to the rectangular area specified
4008 * by the argument. Specifying <code>null</code> for the
4009 * rectangle reverts the receiver's clipping area to its
4010 * original value.
4011 *
4012 * @param rect the clipping rectangle or <code>null</code>
4013 *
4014 * @exception SWTException <ul>
4015 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4016 * </ul>
4017 */

4018public void setClipping (Rectangle rect) {
4019    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4020    if (rect == null) {
4021        setClipping(0);
4022    } else {
4023        setClipping(rect.x, rect.y, rect.width, rect.height);
4024    }
4025}
4026
4027/**
4028 * Sets the area of the receiver which can be changed
4029 * by drawing operations to the region specified
4030 * by the argument. Specifying <code>null</code> for the
4031 * region reverts the receiver's clipping area to its
4032 * original value.
4033 *
4034 * @param region the clipping region or <code>null</code>
4035 *
4036 * @exception IllegalArgumentException <ul>
4037 * <li>ERROR_INVALID_ARGUMENT - if the region has been disposed</li>
4038 * </ul>
4039 * @exception SWTException <ul>
4040 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4041 * </ul>
4042 */

4043public void setClipping (Region region) {
4044    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4045    if (region != null && region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4046    setClipping(region != null ? region.handle : 0);
4047}
4048
4049/**
4050 * Sets the receiver's fill rule to the parameter, which must be one of
4051 * <code>SWT.FILL_EVEN_ODD</code> or <code>SWT.FILL_WINDING</code>.
4052 *
4053 * @param rule the new fill rule
4054 *
4055 * @exception IllegalArgumentException <ul>
4056 * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>SWT.FILL_EVEN_ODD</code>
4057 * or <code>SWT.FILL_WINDING</code></li>
4058 * </ul>
4059 * @exception SWTException <ul>
4060 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4061 * </ul>
4062 *
4063 * @since 3.1
4064 */

4065public void setFillRule(int rule) {
4066    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4067    if (OS.IsWinCE) return;
4068    int mode = OS.ALTERNATE;
4069    switch (rule) {
4070        case SWT.FILL_WINDING: mode = OS.WINDING; break;
4071        case SWT.FILL_EVEN_ODD: mode = OS.ALTERNATE; break;
4072        default:
4073            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4074    }
4075    OS.SetPolyFillMode(handle, mode);
4076}
4077
4078/**
4079 * Sets the font which will be used by the receiver
4080 * to draw and measure text to the argument. If the
4081 * argument is null, then a default font appropriate
4082 * for the platform will be used instead.
4083 *
4084 * @param font the new font for the receiver, or null to indicate a default font
4085 *
4086 * @exception IllegalArgumentException <ul>
4087 * <li>ERROR_INVALID_ARGUMENT - if the font has been disposed</li>
4088 * </ul>
4089 * @exception SWTException <ul>
4090 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4091 * </ul>
4092 */

4093public void setFont (Font font) {
4094    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4095    if (font != null && font.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4096    data.hFont = font != null ? font.handle : data.device.systemFont;
4097    data.state &= ~FONT;
4098}
4099
4100/**
4101 * Sets the foreground color. The foreground color is used
4102 * for drawing operations including when text is drawn.
4103 *
4104 * @param color the new foreground color for the receiver
4105 *
4106 * @exception IllegalArgumentException <ul>
4107 * <li>ERROR_NULL_ARGUMENT - if the color is null</li>
4108 * <li>ERROR_INVALID_ARGUMENT - if the color has been disposed</li>
4109 * </ul>
4110 * @exception SWTException <ul>
4111 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4112 * </ul>
4113 */

4114public void setForeground (Color color) {
4115    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4116    if (color == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
4117    if (color.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4118    if (data.foregroundPattern == null && color.handle == data.foreground) return;
4119    data.foregroundPattern = null;
4120    data.foreground = color.handle;
4121    data.state &= ~(FOREGROUND | FOREGROUND_TEXT);
4122}
4123
4124/**
4125 * Sets the foreground pattern. The default value is <code>null</code>.
4126 * <p>
4127 * This operation requires the operating system's advanced
4128 * graphics subsystem which may not be available on some
4129 * platforms.
4130 * </p>
4131 * @param pattern the new foreground pattern
4132 *
4133 * @exception IllegalArgumentException <ul>
4134 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
4135 * </ul>
4136 * @exception SWTException <ul>
4137 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4138 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
4139 * </ul>
4140 *
4141 * @see Pattern
4142 * @see #getAdvanced
4143 * @see #setAdvanced
4144 *
4145 * @since 3.1
4146 */

4147public void setForegroundPattern (Pattern pattern) {
4148    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4149    if (pattern != null && pattern.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4150    if (data.gdipGraphics == 0 && pattern == null) return;
4151    initGdip();
4152    if (data.foregroundPattern == pattern) return;
4153    data.foregroundPattern = pattern;
4154    data.state &= ~FOREGROUND;
4155}
4156
4157/**
4158 * Sets the receiver's interpolation setting to the parameter, which
4159 * must be one of <code>SWT.DEFAULT</code>, <code>SWT.NONE</code>,
4160 * <code>SWT.LOW</code> or <code>SWT.HIGH</code>.
4161 * <p>
4162 * This operation requires the operating system's advanced
4163 * graphics subsystem which may not be available on some
4164 * platforms.
4165 * </p>
4166 *
4167 * @param interpolation the new interpolation setting
4168 *
4169 * @exception IllegalArgumentException <ul>
4170 * <li>ERROR_INVALID_ARGUMENT - if the rule is not one of <code>SWT.DEFAULT</code>,
4171 * <code>SWT.NONE</code>, <code>SWT.LOW</code> or <code>SWT.HIGH</code>
4172 * </ul>
4173 * @exception SWTException <ul>
4174 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4175 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
4176 * </ul>
4177 *
4178 * @see #getAdvanced
4179 * @see #setAdvanced
4180 *
4181 * @since 3.1
4182 */

4183public void setInterpolation(int interpolation) {
4184    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4185    if (data.gdipGraphics == 0 && interpolation == SWT.DEFAULT) return;
4186    int mode = 0;
4187    switch (interpolation) {
4188        case SWT.DEFAULT: mode = Gdip.InterpolationModeDefault; break;
4189        case SWT.NONE: mode = Gdip.InterpolationModeNearestNeighbor; break;
4190        case SWT.LOW: mode = Gdip.InterpolationModeLowQuality; break;
4191        case SWT.HIGH: mode = Gdip.InterpolationModeHighQuality; break;
4192        default:
4193            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4194    }
4195    initGdip();
4196    Gdip.Graphics_SetInterpolationMode(data.gdipGraphics, mode);
4197}
4198
4199/**
4200 * Sets the receiver's line attributes.
4201 * <p>
4202 * This operation requires the operating system's advanced
4203 * graphics subsystem which may not be available on some
4204 * platforms.
4205 * </p>
4206 * @param attributes the line attributes
4207 *
4208 * @exception IllegalArgumentException <ul>
4209 * <li>ERROR_NULL_ARGUMENT - if the attributes is null</li>
4210 * <li>ERROR_INVALID_ARGUMENT - if any of the line attributes is not valid</li>
4211 * </ul>
4212 * @exception SWTException <ul>
4213 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4214 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
4215 * </ul>
4216 *
4217 * @see LineAttributes
4218 * @see #getAdvanced
4219 * @see #setAdvanced
4220 *
4221 * @since 3.3
4222 */

4223public void setLineAttributes(LineAttributes attributes) {
4224    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4225    if (attributes == null) SWT.error(SWT.ERROR_NULL_ARGUMENT);
4226    int mask = 0;
4227    float lineWidth = attributes.width;
4228    if (lineWidth != data.lineWidth) {
4229        mask |= LINE_WIDTH | DRAW_OFFSET;
4230    }
4231    int lineStyle = attributes.style;
4232    if (lineStyle != data.lineStyle) {
4233        mask |= LINE_STYLE;
4234        switch (lineStyle) {
4235            case SWT.LINE_SOLID:
4236            case SWT.LINE_DASH:
4237            case SWT.LINE_DOT:
4238            case SWT.LINE_DASHDOT:
4239            case SWT.LINE_DASHDOTDOT:
4240                break;
4241            case SWT.LINE_CUSTOM:
4242                if (attributes.dash == null) lineStyle = SWT.LINE_SOLID;
4243                break;
4244            default:
4245                SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4246        }
4247    }
4248    int join = attributes.join;
4249    if (join != data.lineJoin) {
4250        mask |= LINE_JOIN;
4251        switch (join) {
4252            case SWT.CAP_ROUND:
4253            case SWT.CAP_FLAT:
4254            case SWT.CAP_SQUARE:
4255                break;
4256            default:
4257                SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4258        }
4259    }
4260    int cap = attributes.join;
4261    if (cap != data.lineCap) {
4262        mask |= LINE_CAP;
4263        switch (cap) {
4264            case SWT.JOIN_MITER:
4265            case SWT.JOIN_ROUND:
4266            case SWT.JOIN_BEVEL:
4267                break;
4268            default:
4269                SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4270        }
4271    }
4272    float[] dashes = attributes.dash;
4273    float[] lineDashes = data.lineDashes;
4274    if (dashes != null && dashes.length > 0) {
4275        boolean changed = lineDashes == null || lineDashes.length != dashes.length;
4276        for (int i = 0; i < dashes.length; i++) {
4277            float dash = dashes[i];
4278            if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4279            if (!changed && lineDashes[i] != dash) changed = true;
4280        }
4281        if (changed) {
4282            float[] newDashes = new float[dashes.length];
4283            System.arraycopy(dashes, 0, newDashes, 0, dashes.length);
4284            dashes = newDashes;
4285            mask |= LINE_STYLE;
4286        } else {
4287            dashes = lineDashes;
4288        }
4289    } else {
4290        if (lineDashes != null && lineDashes.length > 0) {
4291            mask |= LINE_STYLE;
4292        } else {
4293            dashes = lineDashes;
4294        }
4295    }
4296    float dashOffset = attributes.dashOffset;
4297    if (dashOffset != data.lineDashesOffset) {
4298        mask |= LINE_STYLE;
4299    }
4300    float miterLimit = attributes.miterLimit;
4301    if (miterLimit != data.lineMiterLimit) {
4302        mask |= LINE_MITERLIMIT;
4303    }
4304    initGdip();
4305    if (mask == 0) return;
4306    data.lineWidth = lineWidth;
4307    data.lineStyle = lineStyle;
4308    data.lineCap = cap;
4309    data.lineJoin = join;
4310    data.lineDashes = dashes;
4311    data.lineDashesOffset = dashOffset;
4312    data.lineMiterLimit = miterLimit;
4313    data.state &= ~mask;
4314}
4315
4316/**
4317 * Sets the receiver's line cap style to the argument, which must be one
4318 * of the constants <code>SWT.CAP_FLAT</code>, <code>SWT.CAP_ROUND</code>,
4319 * or <code>SWT.CAP_SQUARE</code>.
4320 *
4321 * @param cap the cap style to be used for drawing lines
4322 *
4323 * @exception IllegalArgumentException <ul>
4324 * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
4325 * </ul>
4326 * @exception SWTException <ul>
4327 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4328 * </ul>
4329 *
4330 * @since 3.1
4331 */

4332public void setLineCap(int cap) {
4333    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4334    if (data.lineCap == cap) return;
4335    switch (cap) {
4336        case SWT.CAP_ROUND:
4337        case SWT.CAP_FLAT:
4338        case SWT.CAP_SQUARE:
4339            break;
4340        default:
4341            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4342    }
4343    data.lineCap = cap;
4344    data.state &= ~LINE_CAP;
4345}
4346
4347/**
4348 * Sets the receiver's line dash style to the argument. The default
4349 * value is <code>null</code>. If the argument is not <code>null</code>,
4350 * the receiver's line style is set to <code>SWT.LINE_CUSTOM</code>, otherwise
4351 * it is set to <code>SWT.LINE_SOLID</code>.
4352 *
4353 * @param dashes the dash style to be used for drawing lines
4354 *
4355 * @exception IllegalArgumentException <ul>
4356 * <li>ERROR_INVALID_ARGUMENT - if any of the values in the array is less than or equal 0</li>
4357 * </ul>
4358 * @exception SWTException <ul>
4359 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4360 * </ul>
4361 *
4362 * @since 3.1
4363 */

4364public void setLineDash(int[] dashes) {
4365    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4366    float[] lineDashes = data.lineDashes;
4367    if (dashes != null && dashes.length > 0) {
4368        boolean changed = data.lineStyle != SWT.LINE_CUSTOM || lineDashes == null || lineDashes.length != dashes.length;
4369        for (int i = 0; i < dashes.length; i++) {
4370            int dash = dashes[i];
4371            if (dash <= 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4372            if (!changed && lineDashes[i] != dash) changed = true;
4373        }
4374        if (!changed) return;
4375        data.lineDashes = new float[dashes.length];
4376        for (int i = 0; i < dashes.length; i++) {
4377            data.lineDashes[i] = dashes[i];
4378        }
4379        data.lineStyle = SWT.LINE_CUSTOM;
4380    } else {
4381        if (data.lineStyle == SWT.LINE_SOLID && (lineDashes == null || lineDashes.length == 0)) return;
4382        data.lineDashes = null;
4383        data.lineStyle = SWT.LINE_SOLID;
4384    }
4385    data.state &= ~LINE_STYLE;
4386}
4387
4388/**
4389 * Sets the receiver's line join style to the argument, which must be one
4390 * of the constants <code>SWT.JOIN_MITER</code>, <code>SWT.JOIN_ROUND</code>,
4391 * or <code>SWT.JOIN_BEVEL</code>.
4392 *
4393 * @param join the join style to be used for drawing lines
4394 *
4395 * @exception IllegalArgumentException <ul>
4396 * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
4397 * </ul>
4398 * @exception SWTException <ul>
4399 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4400 * </ul>
4401 *
4402 * @since 3.1
4403 */

4404public void setLineJoin(int join) {
4405    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4406    if (data.lineJoin == join) return;
4407    switch (join) {
4408        case SWT.JOIN_MITER:
4409        case SWT.JOIN_ROUND:
4410        case SWT.JOIN_BEVEL:
4411            break;
4412        default:
4413            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4414    }
4415    data.lineJoin = join;
4416    data.state &= ~LINE_JOIN;
4417}
4418
4419/**
4420 * Sets the receiver's line style to the argument, which must be one
4421 * of the constants <code>SWT.LINE_SOLID</code>, <code>SWT.LINE_DASH</code>,
4422 * <code>SWT.LINE_DOT</code>, <code>SWT.LINE_DASHDOT</code> or
4423 * <code>SWT.LINE_DASHDOTDOT</code>.
4424 *
4425 * @param lineStyle the style to be used for drawing lines
4426 *
4427 * @exception IllegalArgumentException <ul>
4428 * <li>ERROR_INVALID_ARGUMENT - if the style is not valid</li>
4429 * </ul>
4430 * @exception SWTException <ul>
4431 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4432 * </ul>
4433 */

4434public void setLineStyle(int lineStyle) {
4435    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4436    if (data.lineStyle == lineStyle) return;
4437    switch (lineStyle) {
4438        case SWT.LINE_SOLID:
4439        case SWT.LINE_DASH:
4440        case SWT.LINE_DOT:
4441        case SWT.LINE_DASHDOT:
4442        case SWT.LINE_DASHDOTDOT:
4443            break;
4444        case SWT.LINE_CUSTOM:
4445            if (data.lineDashes == null) lineStyle = SWT.LINE_SOLID;
4446            break;
4447        default:
4448            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4449    }
4450    data.lineStyle = lineStyle;
4451    data.state &= ~LINE_STYLE;
4452}
4453
4454/**
4455 * Sets the width that will be used when drawing lines
4456 * for all of the figure drawing operations (that is,
4457 * <code>drawLine</code>, <code>drawRectangle</code>,
4458 * <code>drawPolyline</code>, and so forth.
4459 * <p>
4460 * Note that line width of zero is used as a hint to
4461 * indicate that the fastest possible line drawing
4462 * algorithms should be used. This means that the
4463 * output may be different from line width one.
4464 * </p>
4465 *
4466 * @param lineWidth the width of a line
4467 *
4468 * @exception SWTException <ul>
4469 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4470 * </ul>
4471 */

4472public void setLineWidth(int lineWidth) {
4473    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4474    if (data.lineWidth == lineWidth) return;
4475    data.lineWidth = lineWidth;
4476    data.state &= ~(LINE_WIDTH | DRAW_OFFSET);
4477}
4478
4479/**
4480 * If the argument is <code>true</code>, puts the receiver
4481 * in a drawing mode where the resulting color in the destination
4482 * is the <em>exclusive or</em> of the color values in the source
4483 * and the destination, and if the argument is <code>false</code>,
4484 * puts the receiver in a drawing mode where the destination color
4485 * is replaced with the source color value.
4486 * <p>
4487 * Note that this mode in fundamentally unsupportable on certain
4488 * platforms, notably Carbon (Mac OS X). Clients that want their
4489 * code to run on all platforms need to avoid this method.
4490 * </p>
4491 *
4492 * @param xor if <code>true</code>, then <em>xor</em> mode is used, otherwise <em>source copy</em> mode is used
4493 *
4494 * @exception SWTException <ul>
4495 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4496 * </ul>
4497 *
4498 * @deprecated this functionality is not supported on some platforms
4499 */

4500public void setXORMode(boolean xor) {
4501    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4502    OS.SetROP2(handle, xor ? OS.R2_XORPEN : OS.R2_COPYPEN);
4503}
4504
4505/**
4506 * Sets the receiver's text anti-aliasing value to the parameter,
4507 * which must be one of <code>SWT.DEFAULT</code>, <code>SWT.OFF</code>
4508 * or <code>SWT.ON</code>. Note that this controls anti-aliasing only
4509 * for all <em>text drawing</em> operations.
4510 * <p>
4511 * This operation requires the operating system's advanced
4512 * graphics subsystem which may not be available on some
4513 * platforms.
4514 * </p>
4515 *
4516 * @param antialias the anti-aliasing setting
4517 *
4518 * @exception IllegalArgumentException <ul>
4519 * <li>ERROR_INVALID_ARGUMENT - if the parameter is not one of <code>SWT.DEFAULT</code>,
4520 * <code>SWT.OFF</code> or <code>SWT.ON</code></li>
4521 * </ul>
4522 * @exception SWTException <ul>
4523 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4524 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
4525 * </ul>
4526 *
4527 * @see #getAdvanced
4528 * @see #setAdvanced
4529 * @see #setAntialias
4530 *
4531 * @since 3.1
4532 */

4533public void setTextAntialias(int antialias) {
4534    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4535    if (data.gdipGraphics == 0 && antialias == SWT.DEFAULT) return;
4536    int textMode = 0;
4537    switch (antialias) {
4538        case SWT.DEFAULT:
4539            textMode = Gdip.TextRenderingHintSystemDefault;
4540            break;
4541        case SWT.OFF:
4542            textMode = Gdip.TextRenderingHintSingleBitPerPixelGridFit;
4543            break;
4544        case SWT.ON:
4545            int[] type = new int[1];
4546            OS.SystemParametersInfo(OS.SPI_GETFONTSMOOTHINGTYPE, 0, type, 0);
4547            if (type[0] == OS.FE_FONTSMOOTHINGCLEARTYPE) {
4548                textMode = Gdip.TextRenderingHintClearTypeGridFit;
4549            } else {
4550                textMode = Gdip.TextRenderingHintAntiAliasGridFit;
4551            }
4552            break;
4553        default:
4554            SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4555    }
4556    initGdip();
4557    Gdip.Graphics_SetTextRenderingHint(data.gdipGraphics, textMode);
4558}
4559
4560/**
4561 * Sets the transform that is currently being used by the receiver. If
4562 * the argument is <code>null</code>, the current transform is set to
4563 * the identity transform.
4564 * <p>
4565 * This operation requires the operating system's advanced
4566 * graphics subsystem which may not be available on some
4567 * platforms.
4568 * </p>
4569 *
4570 * @param transform the transform to set
4571 *
4572 * @exception IllegalArgumentException <ul>
4573 * <li>ERROR_INVALID_ARGUMENT - if the parameter has been disposed</li>
4574 * </ul>
4575 * @exception SWTException <ul>
4576 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4577 * <li>ERROR_NO_GRAPHICS_LIBRARY - if advanced graphics are not available</li>
4578 * </ul>
4579 *
4580 * @see Transform
4581 * @see #getAdvanced
4582 * @see #setAdvanced
4583 *
4584 * @since 3.1
4585 */

4586public void setTransform(Transform transform) {
4587    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4588    if (transform != null && transform.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT);
4589    if (data.gdipGraphics == 0 && transform == null) return;
4590    initGdip();
4591    int identity = identity();
4592    if (transform != null) {
4593         Gdip.Matrix_Multiply(identity, transform.handle, Gdip.MatrixOrderPrepend);
4594    }
4595    Gdip.Graphics_SetTransform(data.gdipGraphics, identity);
4596    Gdip.Matrix_delete(identity);
4597    data.state &= ~DRAW_OFFSET;
4598}
4599
4600/**
4601 * Returns the extent of the given string. No tab
4602 * expansion or carriage return processing will be performed.
4603 * <p>
4604 * The <em>extent</em> of a string is the width and height of
4605 * the rectangular area it would cover if drawn in a particular
4606 * font (in this case, the current font in the receiver).
4607 * </p>
4608 *
4609 * @param string the string to measure
4610 * @return a point containing the extent of the string
4611 *
4612 * @exception IllegalArgumentException <ul>
4613 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
4614 * </ul>
4615 * @exception SWTException <ul>
4616 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4617 * </ul>
4618 */

4619public Point stringExtent(String JavaDoc string) {
4620    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4621    if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
4622    checkGC(FONT);
4623    int length = string.length();
4624    if (data.gdipGraphics != 0) {
4625        PointF pt = new PointF();
4626        RectF bounds = new RectF();
4627        char[] buffer;
4628        if (length != 0) {
4629            buffer = new char [length];
4630            string.getChars(0, length, buffer, 0);
4631        } else {
4632            buffer = new char[]{' '};
4633        }
4634        int format = Gdip.StringFormat_Clone(Gdip.StringFormat_GenericTypographic());
4635        int formatFlags = Gdip.StringFormat_GetFormatFlags(format) | Gdip.StringFormatFlagsMeasureTrailingSpaces;
4636        if ((data.style & SWT.MIRRORED) != 0) formatFlags |= Gdip.StringFormatFlagsDirectionRightToLeft;
4637        Gdip.StringFormat_SetFormatFlags(format, formatFlags);
4638        Gdip.Graphics_MeasureString(data.gdipGraphics, buffer, buffer.length, data.gdipFont, pt, format, bounds);
4639        Gdip.StringFormat_delete(format);
4640        return new Point(length == 0 ? 0 : Math.round(bounds.Width), Math.round(bounds.Height));
4641    }
4642    SIZE size = new SIZE();
4643    if (length == 0) {
4644// OS.GetTextExtentPoint32(handle, SPACE, SPACE.length(), size);
4645
OS.GetTextExtentPoint32W(handle, new char[]{' '}, 1, size);
4646        return new Point(0, size.cy);
4647    } else {
4648// TCHAR buffer = new TCHAR (getCodePage(), string, false);
4649
char[] buffer = new char [length];
4650        string.getChars(0, length, buffer, 0);
4651        OS.GetTextExtentPoint32W(handle, buffer, length, size);
4652        return new Point(size.cx, size.cy);
4653    }
4654}
4655
4656/**
4657 * Returns the extent of the given string. Tab expansion and
4658 * carriage return processing are performed.
4659 * <p>
4660 * The <em>extent</em> of a string is the width and height of
4661 * the rectangular area it would cover if drawn in a particular
4662 * font (in this case, the current font in the receiver).
4663 * </p>
4664 *
4665 * @param string the string to measure
4666 * @return a point containing the extent of the string
4667 *
4668 * @exception IllegalArgumentException <ul>
4669 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
4670 * </ul>
4671 * @exception SWTException <ul>
4672 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4673 * </ul>
4674 */

4675public Point textExtent(String JavaDoc string) {
4676    return textExtent(string, SWT.DRAW_DELIMITER | SWT.DRAW_TAB);
4677}
4678
4679/**
4680 * Returns the extent of the given string. Tab expansion, line
4681 * delimiter and mnemonic processing are performed according to
4682 * the specified flags, which can be a combination of:
4683 * <dl>
4684 * <dt><b>DRAW_DELIMITER</b></dt>
4685 * <dd>draw multiple lines</dd>
4686 * <dt><b>DRAW_TAB</b></dt>
4687 * <dd>expand tabs</dd>
4688 * <dt><b>DRAW_MNEMONIC</b></dt>
4689 * <dd>underline the mnemonic character</dd>
4690 * <dt><b>DRAW_TRANSPARENT</b></dt>
4691 * <dd>transparent background</dd>
4692 * </dl>
4693 * <p>
4694 * The <em>extent</em> of a string is the width and height of
4695 * the rectangular area it would cover if drawn in a particular
4696 * font (in this case, the current font in the receiver).
4697 * </p>
4698 *
4699 * @param string the string to measure
4700 * @param flags the flags specifying how to process the text
4701 * @return a point containing the extent of the string
4702 *
4703 * @exception IllegalArgumentException <ul>
4704 * <li>ERROR_NULL_ARGUMENT - if the string is null</li>
4705 * </ul>
4706 * @exception SWTException <ul>
4707 * <li>ERROR_GRAPHIC_DISPOSED - if the receiver has been disposed</li>
4708 * </ul>
4709 */

4710public Point textExtent(String JavaDoc string, int flags) {
4711    if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED);
4712    if (string == null) SWT.error (SWT.ERROR_NULL_ARGUMENT);
4713    checkGC(FONT);
4714    if (data.gdipGraphics != 0) {
4715        PointF pt = new PointF();
4716        RectF bounds = new RectF();
4717        char[] buffer;
4718        int length = string.length();
4719        if (length != 0) {
4720            buffer = new char [length];
4721            string.getChars(0, length, buffer, 0);
4722        } else {
4723            buffer = new char[]{' '};
4724        }
4725        int format = Gdip.StringFormat_Clone(Gdip.StringFormat_GenericTypographic());
4726        int formatFlags = Gdip.StringFormat_GetFormatFlags(format) | Gdip.StringFormatFlagsMeasureTrailingSpaces;
4727        if ((data.style & SWT.MIRRORED) != 0) formatFlags |= Gdip.StringFormatFlagsDirectionRightToLeft;
4728        Gdip.StringFormat_SetFormatFlags(format, formatFlags);
4729        float[] tabs = (flags & SWT.DRAW_TAB) != 0 ? new float[]{measureSpace(data.gdipFont, format) * 8} : new float[1];
4730        Gdip.StringFormat_SetTabStops(format, 0, tabs.length, tabs);
4731        Gdip.StringFormat_SetHotkeyPrefix(format, (flags & SWT.DRAW_MNEMONIC) != 0 ? Gdip.HotkeyPrefixShow : Gdip.HotkeyPrefixNone);
4732        Gdip.Graphics_MeasureString(data.gdipGraphics, buffer, buffer.length, data.gdipFont, pt, format, bounds);
4733        Gdip.StringFormat_delete(format);
4734        return new Point(length == 0 ? 0 : Math.round(bounds.Width), Math.round(bounds.Height));
4735    }
4736    if (string.length () == 0) {
4737        SIZE size = new SIZE();
4738// OS.GetTextExtentPoint32(handle, SPACE, SPACE.length(), size);
4739
OS.GetTextExtentPoint32W(handle, new char [] {' '}, 1, size);
4740        return new Point(0, size.cy);
4741    }
4742    RECT rect = new RECT();
4743    TCHAR buffer = new TCHAR(getCodePage(), string, false);
4744    int uFormat = OS.DT_LEFT | OS.DT_CALCRECT;
4745    if ((flags & SWT.DRAW_DELIMITER) == 0) uFormat |= OS.DT_SINGLELINE;
4746    if ((flags & SWT.DRAW_TAB) != 0) uFormat |= OS.DT_EXPANDTABS;
4747    if ((flags & SWT.DRAW_MNEMONIC) == 0) uFormat |= OS.DT_NOPREFIX;
4748    OS.DrawText(handle, buffer, buffer.length(), rect, uFormat);
4749    return new Point(rect.right, rect.bottom);
4750}
4751
4752/**
4753 * Returns a string containing a concise, human-readable
4754 * description of the receiver.
4755 *
4756 * @return a string representation of the receiver
4757 */

4758public String JavaDoc toString () {
4759    if (isDisposed()) return "GC {*DISPOSED*}";
4760    return "GC {" + handle + "}";
4761}
4762
4763/**
4764 * Invokes platform specific functionality to allocate a new graphics context.
4765 * <p>
4766 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
4767 * API for <code>GC</code>. It is marked public only so that it
4768 * can be shared within the packages provided by SWT. It is not
4769 * available on all platforms, and should never be called from
4770 * application code.
4771 * </p>
4772 *
4773 * @param drawable the Drawable for the receiver.
4774 * @param data the data for the receiver.
4775 *
4776 * @return a new <code>GC</code>
4777 */

4778public static GC win32_new(Drawable drawable, GCData data) {
4779    GC gc = new GC();
4780    int hDC = drawable.internal_new_GC(data);
4781    gc.device = data.device;
4782    gc.init(drawable, data, hDC);
4783    return gc;
4784}
4785
4786/**
4787 * Invokes platform specific functionality to wrap a graphics context.
4788 * <p>
4789 * <b>IMPORTANT:</b> This method is <em>not</em> part of the public
4790 * API for <code>GC</code>. It is marked public only so that it
4791 * can be shared within the packages provided by SWT. It is not
4792 * available on all platforms, and should never be called from
4793 * application code.
4794 * </p>
4795 *
4796 * @param hDC the Windows HDC.
4797 * @param data the data for the receiver.
4798 *
4799 * @return a new <code>GC</code>
4800 */

4801public static GC win32_new(int hDC, GCData data) {
4802    GC gc = new GC();
4803    gc.device = data.device;
4804    gc.init(null, data, hDC);
4805    return gc;
4806}
4807
4808}
4809
Popular Tags