/******************************************************************************* * Copyright (c) 2000, 2008 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.graphics; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.photon.*; import org.eclipse.swt.*; /** * Class GC is where all of the drawing capabilities that are * supported by SWT are located. Instances are used to draw on either an * Image, a Control, or directly on a Display. *
*
Styles:
*
LEFT_TO_RIGHT, RIGHT_TO_LEFT
*
* *

* The SWT drawing coordinate system is the two-dimensional space with the origin * (0,0) at the top left corner of the drawing area and with (x,y) values increasing * to the right and downward respectively. *

* *

* Application code must explicitly invoke the GC.dispose() * method to release the operating system resources managed by each instance * when those instances are no longer required. This is particularly * important on Windows95 and Windows98 where the operating system has a limited * number of device contexts available. *

* *

* Note: Only one of LEFT_TO_RIGHT and RIGHT_TO_LEFT may be specified. *

* * @see org.eclipse.swt.events.PaintEvent * @see GC snippets * @see SWT Examples: GraphicsExample, PaintExample * @see Sample code and further information */ public final class GC extends Resource { /** * the handle to the OS device context * (Warning: This field is platform dependent) *

* IMPORTANT: This field is not part of the SWT * public API. It is marked public only so that it can be shared * within the packages provided by SWT. It is not available on all * platforms and should never be accessed from application code. *

*/ public int handle; Drawable drawable; GCData data; int dirtyBits; static final int DefaultBack = 0xffffff; static final int DefaultFore = 0x000000; static final byte[][] DashList = { { }, // SWT.LINE_SOLID { 18, 6 }, // SWT.LINE_DASH { 3, 3 }, // SWT.LINE_DOT { 9, 6, 3, 6 }, // SWT.LINE_DASHDOT { 9, 3, 3, 3, 3, 3 } // SWT.LINE_DASHDOTDOT }; // Photon Draw Buffer Size for off screen drawing. static int DrawBufferSize = 48 * 1024; static final int DIRTY_BACKGROUND = 1 << 0; static final int DIRTY_FOREGROUND = 1 << 1; static final int DIRTY_CLIPPING = 1 << 2; static final int DIRTY_FONT = 1 << 3; static final int DIRTY_LINESTYLE = 1 << 4; static final int DIRTY_LINEWIDTH = 1 << 5; static final int DIRTY_LINECAP = 1 << 6; static final int DIRTY_LINEJOIN = 1 << 7; static final int DIRTY_XORMODE = 1 << 8; GC() { } /** * Constructs a new instance of this class which has been * configured to draw on the specified drawable. Sets the * foreground color, background color and font in the GC * to match those in the drawable. *

* You must dispose the graphics context when it is no longer required. *

* @param drawable the drawable to draw on * @exception IllegalArgumentException * @exception SWTError */ public GC(Drawable drawable) { this(drawable, 0); } /** * Constructs a new instance of this class which has been * configured to draw on the specified drawable. Sets the * foreground color, background color and font in the GC * to match those in the drawable. *

* You must dispose the graphics context when it is no longer required. *

* * @param drawable the drawable to draw on * @param style the style of GC to construct * * @exception IllegalArgumentException * @exception SWTError * * @since 2.1.2 */ public GC(Drawable drawable, int style) { int flags = OS.PtEnter(0); try { if (drawable == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); GCData data = new GCData (); data.style = checkStyle(style); int hDC = drawable.internal_new_GC (data); Device device = data.device; if (device == null) device = Device.getDevice(); if (device == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); this.device = data.device = device; init (drawable, data, hDC); init(); } finally { if (flags >= 0) OS.PtLeave(flags); } } static int checkStyle (int style) { if ((style & SWT.LEFT_TO_RIGHT) != 0) style &= ~SWT.RIGHT_TO_LEFT; return style & (SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT); } /** * Copies a rectangular area of the receiver at the specified * position into the image, which must be of type SWT.BITMAP. * * @param image the image to copy into * @param x the x coordinate in the receiver of the area to be copied * @param y the y coordinate in the receiver of the area to be copied * * @exception IllegalArgumentException * @exception SWTException */ public void copyArea(Image image, int x, int y) { if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (image == null) SWT.error (SWT.ERROR_NULL_ARGUMENT); if (image.type != SWT.BITMAP || image.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); int flags = OS.PtEnter(0); try { Rectangle bounds = image.getBounds(); int memImage = 0; PhRect_t rect = new PhRect_t(); rect.ul_x = (short)x; rect.ul_y = (short)y; rect.lr_x = (short)(x + bounds.width - 1); rect.lr_y = (short)(y + bounds.height - 1); boolean sharedMem = true; int rid = data.rid; int widget = data.widget; if (rid == OS.Ph_DEV_RID) { memImage = OS.PgShmemCreate(OS.PgReadScreenSize(rect), null); if (memImage != 0) memImage = OS.PgReadScreen(rect, memImage); } else if (widget != 0) { short [] widget_x = new short [1], widget_y = new short [1]; OS.PtGetAbsPosition(widget, widget_x, widget_y); rect.ul_x += widget_x[0]; rect.ul_y += widget_y[0]; rect.lr_x += widget_y[0]; rect.lr_y += widget_y[0]; memImage = OS.PgShmemCreate(OS.PgReadScreenSize(rect), null); if (memImage != 0) memImage = OS.PgReadScreen(rect, memImage); } else if (data.image != null) { memImage = OS.PiCropImage(data.image.handle, rect, 0); sharedMem = false; } if (memImage == 0) SWT.error(SWT.ERROR_NO_HANDLES); PhImage_t phImage = new PhImage_t(); OS.memmove(phImage, memImage, PhImage_t.sizeof); PhPoint_t trans = new PhPoint_t(); PhPoint_t pos = new PhPoint_t(); PhDim_t scale = new PhDim_t(); scale.w = (short)bounds.width; scale.h = (short)bounds.height; int mc = OS.PmMemCreateMC(image.handle, scale, trans); int prevContext = OS.PmMemStart(mc); OS.PgSetDrawBufferSize(DrawBufferSize); if (phImage.palette != 0) OS.PgSetPalette(phImage.palette, 0, (short)0, (short)phImage.colors, OS.Pg_PALSET_SOFT, 0); OS.PgDrawImage(phImage.image, phImage.type, pos, scale, phImage.bpl, 0); if (phImage.palette != 0) OS.PgSetPalette(0, 0, (short)0, (short)-1, 0, 0); OS.PmMemFlush(mc, image.handle); OS.PmMemStop(mc); OS.PmMemReleaseMC(mc); OS.PhDCSetCurrent(prevContext); if (sharedMem) { OS.PgShmemDestroy(memImage); } else { phImage.flags = (byte)OS.Ph_RELEASE_IMAGE_ALL; OS.memmove(memImage, phImage, PhImage_t.sizeof); OS.PhReleaseImage(memImage); OS.free(memImage); } } finally { if (flags >= 0) OS.PtLeave(flags); } } /** * Copies a rectangular area of the receiver at the source * position onto the receiver at the destination position. * * @param srcX the x coordinate in the receiver of the area to be copied * @param srcY the y coordinate in the receiver of the area to be copied * @param width the width of the area to copy * @param height the height of the area to copy * @param destX the x coordinate in the receiver of the area to copy to * @param destY the y coordinate in the receiver of the area to copy to * * @exception SWTException */ public void copyArea(int x, int y, int width, int height, int destX, int destY) { copyArea(x, y, width, height, destX, destY, true); } /** * Copies a rectangular area of the receiver at the source * position onto the receiver at the destination position. * * @param srcX the x coordinate in the receiver of the area to be copied * @param srcY the y coordinate in the receiver of the area to be copied * @param width the width of the area to copy * @param height the height of the area to copy * @param destX the x coordinate in the receiver of the area to copy to * @param destY the y coordinate in the receiver of the area to copy to * @param paint if true paint events will be generated for old and obscured areas * * @exception SWTException * * @since 3.1 */ public void copyArea(int x, int y, int width, int height, int destX, int destY, boolean paint) { if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (width == 0 || height == 0) return; int deltaX = destX - x, deltaY = destY - y; if (deltaX == 0 && deltaY == 0) return; int flags = OS.PtEnter(0); try { boolean overlaps = (destX < x + width) && (destY < y + height) && (destX + width > x) && (destY + height > y); int widget = data.widget; Image image = data.image; if (image != null) { int drawImage = image.handle; PhImage_t phDrawImage = new PhImage_t(); OS.memmove(phDrawImage, drawImage, PhImage_t.sizeof); if (overlaps) { PhPoint_t trans = new PhPoint_t(); PhDim_t scale = new PhDim_t(); scale.w = (short)width; scale.h = (short)height; PhPoint_t pos = new PhPoint_t(); pos.x = (short)-x; pos.y = (short)-y; PhDim_t dim = new PhDim_t(); dim.w = (short)Math.min(phDrawImage.size_w, x + width); dim.h = (short)Math.min(phDrawImage.size_h, y + height); /* Feature on Photon - It is only possible to draw on images of type Pg_IMAGE_PALETTE_BYTE and Pg_IMAGE_DIRECT_888. */ int type = OS.Pg_IMAGE_PALETTE_BYTE; if ((phDrawImage.type & OS.Pg_IMAGE_CLASS_MASK) == OS.Pg_IMAGE_CLASS_DIRECT) { type = OS.Pg_IMAGE_DIRECT_888; } int memImage = OS.PhCreateImage(null, (short)width, (short)height, type, phDrawImage.palette, phDrawImage.colors, 0); int mc = OS.PmMemCreateMC(memImage, scale, trans); int prevContext = OS.PmMemStart(mc); OS.PgSetDrawBufferSize(DrawBufferSize); if (phDrawImage.palette != 0) OS.PgSetPalette(phDrawImage.palette, 0, (short)0, (short)phDrawImage.colors, OS.Pg_PALSET_SOFT, 0); OS.PgDrawImage(phDrawImage.image, phDrawImage.type, pos, dim, phDrawImage.bpl, 0); if (phDrawImage.palette != 0) OS.PgSetPalette(0, 0, (short)0, (short)-1, 0, 0); OS.PmMemFlush(mc, memImage); OS.PmMemStop(mc); OS.PmMemReleaseMC(mc); OS.PhDCSetCurrent(prevContext); x = (short)0; y = (short)0; drawImage = memImage; OS.memmove(phDrawImage, drawImage, PhImage_t.sizeof); phDrawImage.flags = (byte)OS.Ph_RELEASE_IMAGE_ALL; OS.memmove(drawImage, phDrawImage, PhImage_t.sizeof); } PhPoint_t pos = new PhPoint_t(); pos.x = (short)(destX - x); pos.y = (short)(destY - y); PhRect_t clip = new PhRect_t(); clip.ul_x = (short)destX; clip.ul_y = (short)destY; clip.lr_x = (short)(destX + width - 1); clip.lr_y = (short)(destY + height - 1); PhDim_t dim = new PhDim_t(); dim.w = (short)Math.min(phDrawImage.size_w, x + width); dim.h = (short)Math.min(phDrawImage.size_h, y + height); int prevContext = setGC(); setGCTranslation(); setGCClipping(); OS.PgSetUserClip(clip); if (phDrawImage.palette != 0) OS.PgSetPalette(phDrawImage.palette, 0, (short)0, (short)phDrawImage.colors, OS.Pg_PALSET_SOFT, 0); OS.PgDrawImage(phDrawImage.image, phDrawImage.type, pos, dim, phDrawImage.bpl, 0); if (phDrawImage.palette != 0) OS.PgSetPalette(0, 0, (short)0, (short)-1, 0, 0); OS.PgSetUserClip(null); unsetGC(prevContext); if (drawImage != image.handle) { OS.PhReleaseImage(drawImage); OS.free(drawImage); } } else if (widget != 0) { PhRect_t rect = new PhRect_t(); rect.ul_x = (short)x; rect.ul_y = (short)y; rect.lr_x = (short)(x + width - 1); rect.lr_y = (short)(y + height - 1); PhPoint_t delta = new PhPoint_t(); delta.x = (short)deltaX; delta.y = (short)deltaY; int visibleTiles = getClipping(widget, data.topWidget, true, true, null); if ( visibleTiles == 0 ) OS.PtBlit(widget, rect, delta); else { int srcTile = OS.PhGetTile(); OS.memmove(srcTile, rect, PhRect_t.sizeof); OS.PtClippedBlit(widget, srcTile, delta, visibleTiles); OS.PhFreeTiles(srcTile);; OS.PhFreeTiles(visibleTiles); } } } finally { if (flags >= 0) OS.PtLeave(flags); } } void destroy() { int flags = OS.PtEnter(0); try { int clipRects = data.clipRects; if (clipRects != 0) { OS.free(clipRects); data.clipRects = data.clipRectsCount = 0; } Image image = data.image; if (image != null) { flushImage(); /* Regenerate the mask if necessary */ if (image.transparentPixel != -1) { PhImage_t phImage = new PhImage_t (); OS.memmove(phImage, image.handle, PhImage_t.sizeof); if (phImage.mask_bm == 0) { createMask(image.handle, phImage.type, image.transparentPixel); } } image.memGC = null; } /* * Dispose the HDC. */ drawable.internal_dispose_GC(handle, data); drawable = null; handle = 0; data.image = null; data.font = null; data.rid = data.widget = data.topWidget = 0; data = null; } finally { if (flags >= 0) OS.PtLeave(flags); } } /** * Draws the outline of a circular or elliptical arc * within the specified rectangular area. *

* The resulting arc begins at startAngle and extends * for arcAngle degrees, using the current color. * Angles are interpreted such that 0 degrees is at the 3 o'clock * position. A positive value indicates a counter-clockwise rotation * while a negative value indicates a clockwise rotation. *

* The center of the arc is the center of the rectangle whose origin * is (x, y) and whose size is specified by the * width and height arguments. *

* The resulting arc covers an area width + 1 pixels wide * by height + 1 pixels tall. *

* * @param x the x coordinate of the upper-left corner of the arc to be drawn * @param y the y coordinate of the upper-left corner of the arc to be drawn * @param width the width of the arc to be drawn * @param height the height of the arc to be drawn * @param startAngle the beginning angle * @param arcAngle the angular extent of the arc, relative to the start angle * * @exception SWTException */ public void drawArc (int x, int y, int width, int height, int startAngle, int arcAngle) { if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (width < 0) { x = x + width; width = -width; } if (height < 0) { y = y + height; height = -height; } if (width == 0 || height == 0 || arcAngle == 0) return; if (startAngle > 0) { if (arcAngle > 0) { //No need to modify start angle. arcAngle += startAngle; } else { int newStartAngle; int newStopAngle = startAngle; if (startAngle > Math.abs(arcAngle)) { newStartAngle = startAngle - Math.abs(arcAngle); } else { newStartAngle = startAngle + 360 - Math.abs(arcAngle); } startAngle = newStartAngle; arcAngle = newStopAngle; } } else { if (arcAngle > 0) { arcAngle = arcAngle + startAngle; startAngle = 360 - Math.abs(startAngle); } else { int newStopAngle = 360 + startAngle; startAngle = newStopAngle - Math.abs(arcAngle); arcAngle = newStopAngle; } } startAngle = (int) (startAngle * 65536 / 360); arcAngle = (int) (arcAngle * 65536 / 360); PhPoint_t center = new PhPoint_t(); center.x = (short)(x + (width / 2)); center.y = (short)(y + (height / 2)); PhPoint_t radii = new PhPoint_t(); radii.x = (short)(width / 2); radii.y = (short)(height / 2); int flags = OS.PtEnter(0); try { int prevContext = setGC(); setGCTranslation(); setGCClipping(); OS.PgDrawArc(center, radii, startAngle, arcAngle, OS.Pg_ARC | OS.Pg_DRAW_STROKE); unsetGC(prevContext); } finally { if (flags >= 0) OS.PtLeave(flags); } } /** * Draws a rectangle, based on the specified arguments, which has * the appearance of the platform's focus rectangle if the * platform supports such a notion, and otherwise draws a simple * rectangle in the receiver's foreground color. * * @param x the x coordinate of the rectangle * @param y the y coordinate of the rectangle * @param width the width of the rectangle * @param height the height of the rectangle * * @exception SWTException * * @see #drawRectangle(int, int, int, int) */ public void drawFocus (int x, int y, int width, int height) { if (handle == 0) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); int flags = OS.PtEnter(0); try { int prevContext = setGC(); setGCTranslation(); setGCClipping(); if (width < 0) width -= width; if (height < 0) height -= height; OS.PgSetStrokeColor(0x9098F8); OS.PgDrawIRect(x, y, x + width - 1, y + height - 1, OS.Pg_DRAW_STROKE); OS.PgSetStrokeColor(data.foreground); unsetGC(prevContext); } finally { if (flags >= 0) OS.PtLeave(flags); } } /** * Draws the given image in the receiver at the specified * coordinates. * * @param image the image to draw * @param x the x coordinate of where to draw * @param y the y coordinate of where to draw * * @exception IllegalArgumentException