/*******************************************************************************
* Copyright (c) 2000, 2006 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.carbon.*;
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
.
*
* 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 */ 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; static final int TAB_COUNT = 32; final static int FOREGROUND = 1 << 0; final static int BACKGROUND = 1 << 1; final static int FONT = 1 << 2; final static int LINE_STYLE = 1 << 3; final static int LINE_CAP = 1 << 4; final static int LINE_JOIN = 1 << 5; final static int LINE_WIDTH = 1 << 6; final static int LINE_MITERLIMIT = 1 << 7; final static int FOREGROUND_FILL = 1 << 8; final static int DRAW = FOREGROUND | LINE_WIDTH | LINE_STYLE | LINE_CAP | LINE_JOIN | LINE_MITERLIMIT; final static int FILL = BACKGROUND; static final float[] LINE_DOT = new float[]{1, 1}; static final float[] LINE_DASH = new float[]{3, 1}; static final float[] LINE_DASHDOT = new float[]{3, 1, 1, 1}; static final float[] LINE_DASHDOTDOT = new float[]{3, 1, 1, 1, 1, 1}; static final float[] LINE_DOT_ZERO = new float[]{3, 3}; static final float[] LINE_DASH_ZERO = new float[]{18, 6}; static final float[] LINE_DASHDOT_ZERO = new float[]{9, 6, 3, 6}; static final float[] LINE_DASHDOTDOT_ZERO = new float[]{9, 3, 3, 3, 3, 3}; GC() { } /** * Constructs a new instance of this class which has been * configured to draw on the specified drawable. Sets the * foreground and background color 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* 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
* IMPORTANT: This method is not part of the public
* API for GC
. It is marked public only so that it
* can be shared within the packages provided by SWT. It is not
* available on all platforms, and should never be called from
* application code.
*
GC
*
* @private
*/
public static GC carbon_new(Drawable drawable, GCData data) {
GC gc = new GC();
int context = drawable.internal_new_GC(data);
gc.device = data.device;
gc.init(drawable, data, context);
return gc;
}
/**
* Invokes platform specific functionality to wrap a graphics context.
*
* IMPORTANT: This method is not part of the public
* API for GC
. It is marked public only so that it
* can be shared within the packages provided by SWT. It is not
* available on all platforms, and should never be called from
* application code.
*
GC
*/
public static GC carbon_new(int context, GCData data) {
GC gc = new GC();
gc.device = data.device;
gc.init(null, data, context);
return gc;
}
void checkGC (int mask) {
int state = data.state;
if ((state & mask) == mask) return;
state = (state ^ mask) & mask;
data.state |= mask;
if ((state & FOREGROUND) != 0) {
Pattern pattern = data.foregroundPattern;
if (pattern != null) {
int colorspace = OS.CGColorSpaceCreatePattern(data.device.colorspace);
OS.CGContextSetStrokeColorSpace(handle, colorspace);
OS.CGColorSpaceRelease(colorspace);
if (data.forePattern == 0) data.forePattern = pattern.createPattern(handle);
OS.CGContextSetStrokePattern(handle, data.forePattern, data.foreground);
} else {
OS.CGContextSetStrokeColorSpace(handle, data.device.colorspace);
OS.CGContextSetStrokeColor(handle, data.foreground);
}
}
if ((state & FOREGROUND_FILL) != 0) {
Pattern pattern = data.foregroundPattern;
if (pattern != null) {
int colorspace = OS.CGColorSpaceCreatePattern(data.device.colorspace);
OS.CGContextSetFillColorSpace(handle, colorspace);
OS.CGColorSpaceRelease(colorspace);
if (data.forePattern == 0) data.forePattern = pattern.createPattern(handle);
OS.CGContextSetFillPattern(handle, data.forePattern, data.foreground);
} else {
OS.CGContextSetFillColorSpace(handle, data.device.colorspace);
OS.CGContextSetFillColor(handle, data.foreground);
}
data.state &= ~BACKGROUND;
}
if ((state & BACKGROUND) != 0) {
Pattern pattern = data.backgroundPattern;
if (pattern != null) {
int colorspace = OS.CGColorSpaceCreatePattern(data.device.colorspace);
OS.CGContextSetFillColorSpace(handle, colorspace);
OS.CGColorSpaceRelease(colorspace);
if (data.backPattern == 0) data.backPattern = pattern.createPattern(handle);
OS.CGContextSetFillPattern(handle, data.backPattern, data.background);
} else {
OS.CGContextSetFillColorSpace(handle, data.device.colorspace);
OS.CGContextSetFillColor(handle, data.background);
}
data.state &= ~FOREGROUND_FILL;
}
if ((state & FONT) != 0) {
setCGFont();
}
if ((state & LINE_WIDTH) != 0) {
OS.CGContextSetLineWidth(handle, data.lineWidth == 0 ? 1 : data.lineWidth);
switch (data.lineStyle) {
case SWT.LINE_DOT:
case SWT.LINE_DASH:
case SWT.LINE_DASHDOT:
case SWT.LINE_DASHDOTDOT:
state |= LINE_STYLE;
}
}
if ((state & LINE_STYLE) != 0) {
float[] dashes = null;
float width = data.lineWidth;
switch (data.lineStyle) {
case SWT.LINE_SOLID: break;
case SWT.LINE_DASH: dashes = width != 0 ? LINE_DASH : LINE_DASH_ZERO; break;
case SWT.LINE_DOT: dashes = width != 0 ? LINE_DOT : LINE_DOT_ZERO; break;
case SWT.LINE_DASHDOT: dashes = width != 0 ? LINE_DASHDOT : LINE_DASHDOT_ZERO; break;
case SWT.LINE_DASHDOTDOT: dashes = width != 0 ? LINE_DASHDOTDOT : LINE_DASHDOTDOT_ZERO; break;
case SWT.LINE_CUSTOM: dashes = data.lineDashes; break;
}
if (dashes != null) {
float[] lengths = new float[dashes.length];
for (int i = 0; i < lengths.length; i++) {
lengths[i] = width == 0 || data.lineStyle == SWT.LINE_CUSTOM ? dashes[i] : dashes[i] * width;
}
OS.CGContextSetLineDash(handle, data.lineDashesOffset, lengths, lengths.length);
} else {
OS.CGContextSetLineDash(handle, 0, null, 0);
}
}
if ((state & LINE_MITERLIMIT) != 0) {
OS.CGContextSetMiterLimit(handle, data.lineMiterLimit);
}
if ((state & LINE_JOIN) != 0) {
int joinStyle = 0;
switch (data.lineJoin) {
case SWT.JOIN_MITER: joinStyle = OS.kCGLineJoinMiter; break;
case SWT.JOIN_ROUND: joinStyle = OS.kCGLineJoinRound; break;
case SWT.JOIN_BEVEL: joinStyle = OS.kCGLineJoinBevel; break;
}
OS.CGContextSetLineJoin(handle, joinStyle);
}
if ((state & LINE_CAP) != 0) {
int capStyle = 0;
switch (data.lineCap) {
case SWT.CAP_ROUND: capStyle = OS.kCGLineCapRound; break;
case SWT.CAP_FLAT: capStyle = OS.kCGLineCapButt; break;
case SWT.CAP_SQUARE: capStyle = OS.kCGLineCapSquare; break;
}
OS.CGContextSetLineCap(handle, capStyle);
}
}
int convertRgn(int rgn, float[] transform) {
int newRgn = OS.NewRgn();
Callback callback = new Callback(this, "convertRgn", 4);
int proc = callback.getAddress();
if (proc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS);
float[] clippingTranform = data.clippingTransform;
data.clippingTransform = transform;
OS.QDRegionToRects(rgn, OS.kQDParseRegionFromTopLeft, proc, newRgn);
data.clippingTransform = clippingTranform;
callback.dispose();
return newRgn;
}
int convertRgn(int message, int rgn, int r, int newRgn) {
if (message == OS.kQDRegionToRectsMsgParse) {
Rect rect = new Rect();
OS.memcpy(rect, r, Rect.sizeof);
CGPoint point = new CGPoint();
int polyRgn = OS.NewRgn();
OS.OpenRgn();
point.x = rect.left;
point.y = rect.top;
float[] transform = data.clippingTransform;
OS.CGPointApplyAffineTransform(point, transform, point);
short startX, startY;
OS.MoveTo(startX = (short)point.x, startY = (short)point.y);
point.x = rect.right;
point.y = rect.top;
OS.CGPointApplyAffineTransform(point, transform, point);
OS.LineTo((short)Math.round(point.x), (short)point.y);
point.x = rect.right;
point.y = rect.bottom;
OS.CGPointApplyAffineTransform(point, transform, point);
OS.LineTo((short)Math.round(point.x), (short)Math.round(point.y));
point.x = rect.left;
point.y = rect.bottom;
OS.CGPointApplyAffineTransform(point, transform, point);
OS.LineTo((short)point.x, (short)Math.round(point.y));
OS.LineTo(startX, startY);
OS.CloseRgn(polyRgn);
OS.UnionRgn(newRgn, polyRgn, newRgn);
OS.DisposeRgn(polyRgn);
}
return 0;
}
/**
* 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 true
paint events will be generated for old and obscured areas
*
* @exception SWTException 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.
*
x1
, y1
) and (x2
, y2
).
*
* @param x1 the first point's x coordinate
* @param y1 the first point's y coordinate
* @param x2 the second point's x coordinate
* @param y2 the second point's y coordinate
*
* @exception SWTException
* The result is a circle or ellipse that fits within the
* rectangle specified by the x
, y
,
* width
, and height
arguments.
*
* The oval covers an area that is width + 1
* pixels wide and height + 1
pixels tall.
*
x
, y
).
* * Note that the receiver's line attributes do not affect this * operation. *
* * @param x the point's x coordinate * @param y the point's y coordinate * * @exception SWTExceptionx + width
.
* The top and bottom edges are at y
and y + height
.
*
* @param x the x coordinate of the rectangle to be drawn
* @param y the y coordinate of the rectangle to be drawn
* @param width the width of the rectangle to be drawn
* @param height the height of the rectangle to be drawn
*
* @exception SWTException rect.x
and rect.x + rect.width
. The top
* and bottom edges are at rect.y
and
* rect.y + rect.height
.
*
* @param rect the rectangle to draw
*
* @exception IllegalArgumentException x
and x + width
.
* The top and bottom edges are at y
and y + height
.
* The roundness of the corners is specified by the
* arcWidth
and arcHeight
arguments, which
* are respectively the width and height of the ellipse used to draw
* the corners.
*
* @param x the x coordinate of the rectangle to be drawn
* @param y the y coordinate of the rectangle to be drawn
* @param width the width of the rectangle to be drawn
* @param height the height of the rectangle to be drawn
* @param arcWidth the width of the arc
* @param arcHeight the height of the arc
*
* @exception SWTException isTransparent
is true
,
* then the background of the rectangular area where the string is being
* drawn will not be modified, otherwise it will be filled with the
* receiver's background color.
*
* @param string the string to be drawn
* @param x the x coordinate of the top left corner of the rectangular area where the string is to be drawn
* @param y the y coordinate of the top left corner of the rectangular area where the string is to be drawn
* @param isTransparent if true
the background will be transparent, otherwise it will be opaque
*
* @exception IllegalArgumentException isTransparent
is true
,
* then the background of the rectangular area where the text is being
* drawn will not be modified, otherwise it will be filled with the
* receiver's background color.
*
* @param string the string to be drawn
* @param x the x coordinate of the top left corner of the rectangular area where the text is to be drawn
* @param y the y coordinate of the top left corner of the rectangular area where the text is to be drawn
* @param isTransparent if true
the background will be transparent, otherwise it will be opaque
*
* @exception IllegalArgumentException flags
includes DRAW_TRANSPARENT
,
* then the background of the rectangular area where the text is being
* drawn will not be modified, otherwise it will be filled with the
* receiver's background color.
*
* The parameter flags
may be a combination of:
*
true
if the object is the same as this object and false
otherwise
*
* @see #hashCode
*/
public boolean equals(Object object) {
if (object == this) return true;
if (!(object instanceof GC)) return false;
return handle == ((GC)object).handle;
}
/**
* Fills the interior of a circular or elliptical arc within
* the specified rectangular area, with the receiver's background
* color.
*
* 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.
*
* The advance width is defined as the horizontal distance the cursor * should move after printing the character in the selected font. *
* * @param ch the character to measure * @return the distance in the x direction to move past the character before painting the next * * @exception SWTExceptionnull
.
*
* @return the receiver's background pattern
*
* @exception SWTException true
if receiver is using the operating system's
* advanced graphics subsystem. Otherwise, false
is returned
* to indicate that normal graphics are in use.
*
* Advanced graphics may not be installed for the operating system. In this
* case, false
is always returned. Some operating system have
* only one graphics subsystem. If this subsystem supports advanced graphics,
* then true
is always returned. If any graphics operation such
* as alpha, antialias, patterns, interpolation, paths, clipping or transformation
* has caused the receiver to switch from regular to advanced graphics mode,
* true
is returned. If the receiver has been explicitly switched
* to advanced mode and this mode is supported, true
is returned.
*
SWT.DEFAULT
, SWT.OFF
or
* SWT.ON
. Note that this controls anti-aliasing for all
* non-text drawing operations.
*
* @return the anti-aliasing setting
*
* @exception SWTException * The width is defined as the space taken up by the actual * character, not including the leading and tailing whitespace * or overhang. *
* * @param ch the character to measure * @return the width of the character * * @exception SWTExceptionSWT.FILL_EVEN_ODD
or SWT.FILL_WINDING
.
*
* @return the receiver's fill rule
*
* @exception SWTException null
.
*
* @return the receiver's foreground pattern
*
* @exception SWTException
* IMPORTANT: This method is not part of the public
* API for GC
. It is marked public only so that it
* can be shared within the packages provided by SWT. It is not
* available on all platforms, and should never be called from
* application code.
*
SWT.DEFAULT
, SWT.NONE
,
* SWT.LOW
or SWT.HIGH
.
*
* @return the receiver's interpolation setting
*
* @exception SWTException SWT.CAP_FLAT
, SWT.CAP_ROUND
,
* or SWT.CAP_SQUARE
.
*
* @return the cap style used for drawing lines
*
* @exception SWTException null
.
*
* @return the lin dash style used for drawing lines
*
* @exception SWTException SWT.JOIN_MITER
, SWT.JOIN_ROUND
,
* or SWT.JOIN_BEVEL
.
*
* @return the join style used for drawing lines
*
* @exception SWTException SWT.LINE_SOLID
, SWT.LINE_DASH
,
* SWT.LINE_DOT
, SWT.LINE_DASHDOT
or
* SWT.LINE_DASHDOTDOT
.
*
* @return the style used for drawing lines
*
* @exception SWTException drawLine
, drawRectangle
,
* drawPolyline
, and so forth.
*
* @return the receiver's line width
*
* @exception SWTException * Note that the value which is returned by this method may * not match the value which was provided to the constructor * when the receiver was created. This can occur when the underlying * operating system does not support a particular combination of * requested styles. *
* * @return the style bits * * @exception SWTExceptionSWT.DEFAULT
, SWT.OFF
or
* SWT.ON
. Note that this controls anti-aliasing
* only for text drawing operations.
*
* @return the anti-aliasing setting
*
* @exception SWTException true
if this GC is drawing in the mode
* where the resulting color in the destination is the
* exclusive or of the color values in the source
* and the destination, and false
if it is
* drawing in the mode where the destination color is being
* replaced with the source color value.
*
* @return true
true if the receiver is in XOR mode, and false otherwise
*
* @exception SWTException true
when passed to
* equals
must return the same value for this
* method.
*
* @return the receiver's hash
*
* @exception SWTException true
if the receiver has a clipping
* region set into it, and false
otherwise.
* If this method returns false, the receiver will draw on all
* available space in the destination. If it returns true,
* it will draw only in the area that is covered by the region
* that can be accessed with getClipping(region)
.
*
* @return true
if the GC has a clipping region, and false
otherwise
*
* @exception SWTException true
if the GC has been disposed,
* and false
otherwise.
*
* This method gets the dispose state for the GC.
* When a GC has been disposed, it is an error to
* invoke any other method using the GC.
*
* @return true
when the GC is disposed and false
otherwise
*/
public boolean isDisposed() {
return handle == 0;
}
boolean isIdentity(float[] transform) {
return transform[0] == 1 && transform[1] == 0 && transform[2] == 0
&& transform[3] == 1 && transform[4] == 0 && transform[5] == 0;
}
/**
* Sets the receiver to always use the operating system's advanced graphics
* subsystem for all graphics operations if the argument is true
.
* If the argument is false
, the advanced graphics subsystem is
* no longer used, advanced graphics state is cleared and the normal graphics
* subsystem is used from now on.
*
* Normally, the advanced graphics subsystem is invoked automatically when * any one of the alpha, antialias, patterns, interpolation, paths, clipping * or transformation operations in the receiver is requested. When the receiver * is switched into advanced mode, the advanced graphics subsystem performs both * advanced and normal graphics operations. Because the two subsystems are * different, their output may differ. Switching to advanced graphics before * any graphics operations are performed ensures that the output is consistent. *
** Advanced graphics may not be installed for the operating system. In this * case, this operation does nothing. Some operating system have only one * graphics subsystem, so switching from normal to advanced graphics does * nothing. However, switching from advanced to normal graphics will always * clear the advanced graphics state, even for operating systems that have * only one graphics subsystem. *
* * @param advanced the new advanced graphics state * * @exception SWTExceptionSWT.DEFAULT
, SWT.OFF
* or SWT.ON
. Note that this controls anti-aliasing for all
* non-text drawing operations.
*
* @param antialias the anti-aliasing setting
*
* @exception IllegalArgumentException SWT.DEFAULT
,
* SWT.OFF
or SWT.ON
null
.
*
* @param pattern the new background pattern
*
* @exception IllegalArgumentException null
for the
* rectangle reverts the receiver's clipping area to its
* original value.
*
* @param rect the clipping rectangle or null
*
* @exception SWTException null
for the
* region reverts the receiver's clipping area to its
* original value.
*
* @param region the clipping region or null
*
* @exception IllegalArgumentException SWT.FILL_EVEN_ODD
or SWT.FILL_WINDING
.
*
* @param rule the new fill rule
*
* @exception IllegalArgumentException SWT.FILL_EVEN_ODD
* or SWT.FILL_WINDING
null
.
*
* @param pattern the new foreground pattern
*
* @exception IllegalArgumentException SWT.DEFAULT
, SWT.NONE
,
* SWT.LOW
or SWT.HIGH
.
*
* @param interpolation the new interpolation setting
*
* @exception IllegalArgumentException SWT.DEFAULT
,
* SWT.NONE
, SWT.LOW
or SWT.HIGH
* SWT.CAP_FLAT
, SWT.CAP_ROUND
,
* or SWT.CAP_SQUARE
.
*
* @param cap the cap style to be used for drawing lines
*
* @exception IllegalArgumentException null
. If the argument is not null
,
* the receiver's line style is set to SWT.LINE_CUSTOM
, otherwise
* it is set to SWT.LINE_SOLID
.
*
* @param dashes the dash style to be used for drawing lines
*
* @exception IllegalArgumentException SWT.JOIN_MITER
, SWT.JOIN_ROUND
,
* or SWT.JOIN_BEVEL
.
*
* @param join the join style to be used for drawing lines
*
* @exception IllegalArgumentException SWT.LINE_SOLID
, SWT.LINE_DASH
,
* SWT.LINE_DOT
, SWT.LINE_DASHDOT
or
* SWT.LINE_DASHDOTDOT
.
*
* @param lineStyle the style to be used for drawing lines
*
* @exception IllegalArgumentException drawLine
, drawRectangle
,
* drawPolyline
, and so forth.
* * Note that line width of zero is used as a hint to * indicate that the fastest possible line drawing * algorithms should be used. This means that the * output may be different from line width one. *
* * @param lineWidth the width of a line * * @exception SWTExceptionfalse
,
* puts the receiver in a drawing mode where the destination color
* is replaced with the source color value.
* * Note that this mode in fundamentally unsupportable on certain * platforms, notably Carbon (Mac OS X). Clients that want their * code to run on all platforms need to avoid this method. *
* * @param xor iftrue
, then xor mode is used, otherwise source copy mode is used
*
* @exception SWTException SWT.DEFAULT
, SWT.OFF
* or SWT.ON
. Note that this controls anti-aliasing only
* for all text drawing operations.
*
* @param antialias the anti-aliasing setting
*
* @exception IllegalArgumentException SWT.DEFAULT
,
* SWT.OFF
or SWT.ON
null
, the current transform is set to
* the identity transform.
*
* @param transform the transform to set
*
* @exception IllegalArgumentException * The extent of a string is the width and height of * the rectangular area it would cover if drawn in a particular * font (in this case, the current font in the receiver). *
* * @param string the string to measure * @return a point containing the extent of the string * * @exception IllegalArgumentException* The extent of a string is the width and height of * the rectangular area it would cover if drawn in a particular * font (in this case, the current font in the receiver). *
* * @param string the string to measure * @return a point containing the extent of the string * * @exception IllegalArgumentException* The extent of a string is the width and height of * the rectangular area it would cover if drawn in a particular * font (in this case, the current font in the receiver). *
* * @param string the string to measure * @param flags the flags specifing how to process the text * @return a point containing the extent of the string * * @exception IllegalArgumentException