/******************************************************************************* * Copyright (c) 2000, 2011 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.graphics; import org.eclipse.swt.*; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.cocoa.*; /** * 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. *

* *

* The result of drawing on an image that was created with an indexed * palette using a color that is not in the palette is platform specific. * Some platforms will match to the nearest color while other will draw * the color itself. This happens because the allocated image might use * a direct palette on platforms that do not support indexed palette. *

* *

* 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. *

* * @noreference This field is not intended to be referenced by clients. */ public NSGraphicsContext handle; Drawable drawable; GCData data; CGPathElement element; int count, typeCount; byte[] types; float /*double*/[] points; float /*double*/ [] point; static final int TAB_COUNT = 32; final static int FOREGROUND = 1 << 0; final static int BACKGROUND = 1 << 1; final static int FONT = 1 << 2; final static int LINE_STYLE = 1 << 3; final static int LINE_CAP = 1 << 4; final static int LINE_JOIN = 1 << 5; final static int LINE_WIDTH = 1 << 6; final static int LINE_MITERLIMIT = 1 << 7; final static int FOREGROUND_FILL = 1 << 8; final static int DRAW_OFFSET = 1 << 9; final static int CLIPPING = 1 << 10; final static int TRANSFORM = 1 << 11; final static int VISIBLE_REGION = 1 << 12; final static int DRAW = CLIPPING | TRANSFORM | FOREGROUND | LINE_WIDTH | LINE_STYLE | LINE_CAP | LINE_JOIN | LINE_MITERLIMIT | DRAW_OFFSET; final static int FILL = CLIPPING | TRANSFORM | BACKGROUND; static final float[] LINE_DOT = new float[]{1, 1}; static final float[] LINE_DASH = new float[]{3, 1}; static final float[] LINE_DASHDOT = new float[]{3, 1, 1, 1}; static final float[] LINE_DASHDOTDOT = new float[]{3, 1, 1, 1, 1, 1}; static final float[] LINE_DOT_ZERO = new float[]{3, 3}; static final float[] LINE_DASH_ZERO = new float[]{18, 6}; static final float[] LINE_DASHDOT_ZERO = new float[]{9, 6, 3, 6}; static final float[] LINE_DASHDOTDOT_ZERO = new float[]{9, 3, 3, 3, 3, 3}; GC() { } /** * Constructs a new instance of this class which has been * configured to draw on the specified drawable. Sets the * foreground color, background color and font in the GC * to match those in the drawable. *

* 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) { if (drawable == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { GCData data = new GCData(); data.style = checkStyle(style); int /*long*/ contextId = 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, contextId); init(); } finally { if (pool != null) pool.release(); } } 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); } /** * Invokes platform specific functionality to allocate a new 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. *

* * @param drawable the Drawable for the receiver. * @param data the data for the receiver. * * @return a new GC * * @noreference This method is not intended to be referenced by clients. */ public static GC cocoa_new(Drawable drawable, GCData data) { GC gc = new GC(); int /*long*/ context = drawable.internal_new_GC(data); gc.device = data.device; gc.init(drawable, data, context); return gc; } int /*long*/ applierFunc(int /*long*/ info, int /*long*/ elementPtr) { OS.memmove(element, elementPtr, CGPathElement.sizeof); int type = 0, length = 1; switch (element.type) { case OS.kCGPathElementMoveToPoint: type = SWT.PATH_MOVE_TO; break; case OS.kCGPathElementAddLineToPoint: type = SWT.PATH_LINE_TO; break; case OS.kCGPathElementAddQuadCurveToPoint: type = SWT.PATH_QUAD_TO; length = 2; break; case OS.kCGPathElementAddCurveToPoint: type = SWT.PATH_CUBIC_TO; length = 3; break; case OS.kCGPathElementCloseSubpath: type = SWT.PATH_CLOSE; length = 0; break; } if (types != null) { types[typeCount] = (byte)type; if (length > 0) { OS.memmove(point, element.points, length * CGPoint.sizeof); System.arraycopy(point, 0, points, count, length * 2); } } typeCount++; count += length * 2; return 0; } NSAutoreleasePool checkGC (int mask) { NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); if (data.flippedContext != null && !handle.isEqual(NSGraphicsContext.currentContext())) { data.restoreContext = true; NSGraphicsContext.static_saveGraphicsState(); NSGraphicsContext.setCurrentContext(handle); } if ((mask & (CLIPPING | TRANSFORM)) != 0) { NSView view = data.view; if ((data.state & CLIPPING) == 0 || (data.state & TRANSFORM) == 0 || (data.state & VISIBLE_REGION) == 0) { boolean antialias = handle.shouldAntialias(); handle.restoreGraphicsState(); handle.saveGraphicsState(); handle.setShouldAntialias(antialias); if (view != null && (data.paintRect == null || !view.isFlipped())) { NSAffineTransform transform = NSAffineTransform.transform(); NSRect rect = view.convertRect_toView_(view.bounds(), null); if (data.paintRect == null) { transform.translateXBy(rect.x, rect.y + rect.height); float /*double*/ userSpaceScaleFactor = view.window().userSpaceScaleFactor(); transform.scaleXBy(userSpaceScaleFactor, userSpaceScaleFactor); } else { transform.translateXBy(0, rect.height); } transform.scaleXBy(1, -1); transform.concat(); if (data.visibleRgn != 0) { if (data.visiblePath == null || (data.state & VISIBLE_REGION) == 0) { if (data.visiblePath != null) data.visiblePath.release(); data.visiblePath = Region.cocoa_new(device, data.visibleRgn).getPath(); } data.visiblePath.addClip(); data.state |= VISIBLE_REGION; } } if (data.clipPath != null) data.clipPath.addClip(); if (data.transform != null) data.transform.concat(); mask &= ~(TRANSFORM | CLIPPING); data.state |= TRANSFORM | CLIPPING; data.state &= ~(BACKGROUND | FOREGROUND); } } OS.CGContextSetBlendMode(handle.graphicsPort(), data.xorMode ? OS.kCGBlendModeDifference : OS.kCGBlendModeNormal); int state = data.state; if ((state & mask) == mask) return pool; state = (state ^ mask) & mask; data.state |= mask; if ((state & FOREGROUND) != 0) { Pattern pattern = data.foregroundPattern; if (pattern != null) { if (pattern.color != null) pattern.color.setStroke(); } else { float /*double*/ [] color = data.foreground; if (data.fg != null) data.fg.release(); NSColor fg = data.fg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f); fg.retain(); fg.setStroke(); } } if ((state & FOREGROUND_FILL) != 0) { Pattern pattern = data.foregroundPattern; if (pattern != null) { if (pattern.color != null) pattern.color.setFill(); } else { float /*double*/ [] color = data.foreground; if (data.fg != null) data.fg.release(); NSColor fg = data.fg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f); fg.retain(); fg.setFill(); } data.state &= ~BACKGROUND; } if ((state & BACKGROUND) != 0) { Pattern pattern = data.backgroundPattern; if (pattern != null) { if (pattern.color != null) pattern.color.setFill(); } else { float /*double*/ [] color = data.background; if (data.bg != null) data.bg.release(); NSColor bg = data.bg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f); bg.retain(); bg.setFill(); } data.state &= ~FOREGROUND_FILL; } NSBezierPath path = data.path; if ((state & LINE_WIDTH) != 0) { path.setLineWidth(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 /*double*/[] lengths = new float /*double*/[dashes.length]; for (int i = 0; i < lengths.length; i++) { lengths[i] = width == 0 || data.lineStyle == SWT.LINE_CUSTOM ? dashes[i] : dashes[i] * width; } path.setLineDash(lengths, lengths.length, data.lineDashesOffset); } else { path.setLineDash(null, 0, 0); } } if ((state & LINE_MITERLIMIT) != 0) { path.setMiterLimit(data.lineMiterLimit); } if ((state & LINE_JOIN) != 0) { int joinStyle = 0; switch (data.lineJoin) { case SWT.JOIN_MITER: joinStyle = OS.NSMiterLineJoinStyle; break; case SWT.JOIN_ROUND: joinStyle = OS.NSRoundLineJoinStyle; break; case SWT.JOIN_BEVEL: joinStyle = OS.NSBevelLineJoinStyle; break; } path.setLineJoinStyle(joinStyle); } if ((state & LINE_CAP) != 0) { int capStyle = 0; switch (data.lineCap) { case SWT.CAP_ROUND: capStyle = OS.NSRoundLineCapStyle; break; case SWT.CAP_FLAT: capStyle = OS.NSButtLineCapStyle; break; case SWT.CAP_SQUARE: capStyle = OS.NSSquareLineCapStyle; break; } path.setLineCapStyle(capStyle); } if ((state & DRAW_OFFSET) != 0) { data.drawXOffset = data.drawYOffset = 0; NSSize size = new NSSize(); size.width = size.height = 1; if (data.transform != null) { size = data.transform.transformSize(size); } float /*double*/ scaling = size.width; if (scaling < 0) scaling = -scaling; float /*double*/ strokeWidth = data.lineWidth * scaling; if (strokeWidth == 0 || ((int)strokeWidth % 2) == 1) { data.drawXOffset = 0.5f / scaling; } scaling = size.height; if (scaling < 0) scaling = -scaling; strokeWidth = data.lineWidth * scaling; if (strokeWidth == 0 || ((int)strokeWidth % 2) == 1) { data.drawYOffset = 0.5f / scaling; } } return pool; } /** * 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 == null) 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); NSAutoreleasePool pool = checkGC(TRANSFORM | CLIPPING); try { if (data.image != null) { int srcX = x, srcY = y, destX = 0, destY = 0; NSSize srcSize = data.image.handle.size(); int imgHeight = (int)srcSize.height; int destWidth = (int)srcSize.width - x, destHeight = (int)srcSize.height - y; int srcWidth = destWidth, srcHeight = destHeight; NSGraphicsContext context = NSGraphicsContext.graphicsContextWithBitmapImageRep(image.getRepresentation()); NSGraphicsContext.static_saveGraphicsState(); NSGraphicsContext.setCurrentContext(context); NSAffineTransform transform = NSAffineTransform.transform(); NSSize size = image.handle.size(); transform.translateXBy(0, size.height-(destHeight + 2 * destY)); transform.concat(); NSRect srcRect = new NSRect(); srcRect.x = srcX; srcRect.y = imgHeight - (srcY + srcHeight); srcRect.width = srcWidth; srcRect.height = srcHeight; NSRect destRect = new NSRect(); destRect.x = destX; destRect.y = destY; destRect.width = destWidth; destRect.height = destHeight; data.image.handle.drawInRect(destRect, srcRect, OS.NSCompositeCopy, 1); NSGraphicsContext.static_restoreGraphicsState(); return; } if (data.view != null) { NSPoint pt = new NSPoint(); pt.x = x; pt.y = y; NSWindow window = data.view.window(); pt = data.view.convertPoint_toView_(pt, window.contentView().superview()); NSRect frame = window.frame(); pt.y = frame.height - pt.y; NSSize size = image.handle.size(); CGRect destRect = new CGRect(); destRect.size.width = size.width; destRect.size.height = size.height; CGRect srcRect = new CGRect(); srcRect.origin.x = pt.x; srcRect.origin.y = pt.y; srcRect.size.width = size.width; srcRect.size.height = size.height; NSBitmapImageRep imageRep = image.getRepresentation(); NSGraphicsContext context = NSGraphicsContext.graphicsContextWithBitmapImageRep(imageRep); NSGraphicsContext.static_saveGraphicsState(); NSGraphicsContext.setCurrentContext(context); int /*long*/ contextID = OS.objc_msgSend(NSApplication.sharedApplication().id, OS.sel_contextID); OS.CGContextCopyWindowContentsToRect(context.graphicsPort(), destRect, contextID, window.windowNumber(), srcRect); NSGraphicsContext.static_restoreGraphicsState(); return; } if (handle.isDrawingToScreen()) { NSImage imageHandle = image.handle; NSSize size = imageHandle.size(); CGRect rect = new CGRect(); rect.origin.x = x; rect.origin.y = y; rect.size.width = size.width; rect.size.height = size.height; int displayCount = 16; int /*long*/ displays = OS.malloc(4 * displayCount), countPtr = OS.malloc(4); if (OS.CGGetDisplaysWithRect(rect, displayCount, displays, countPtr) != 0) return; int[] count = new int[1], display = new int[1]; OS.memmove(count, countPtr, OS.PTR_SIZEOF); for (int i = 0; i < count[0]; i++) { OS.memmove(display, displays + (i * 4), 4); OS.CGDisplayBounds(display[0], rect); int /*long*/ srcImage = 0; int /*long*/ address = OS.VERSION >= 0x1070 ? 0 : OS.CGDisplayBaseAddress(display[0]); if (address != 0) { int /*long*/ width = OS.CGDisplayPixelsWide(display[0]); int /*long*/ height = OS.CGDisplayPixelsHigh(display[0]); int /*long*/ bpr = OS.CGDisplayBytesPerRow(display[0]); int /*long*/ bpp = OS.CGDisplayBitsPerPixel(display[0]); int /*long*/ bps = OS.CGDisplayBitsPerSample(display[0]); int bitmapInfo = OS.kCGImageAlphaNoneSkipFirst; switch ((int)/*63*/bpp) { case 16: bitmapInfo |= OS.kCGBitmapByteOrder16Host; break; case 32: bitmapInfo |= OS.kCGBitmapByteOrder32Host; break; } if (OS.__BIG_ENDIAN__() && OS.VERSION >= 0x1040) { int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB(); int /*long*/ context = OS.CGBitmapContextCreate(address, width, height, bps, bpr, colorspace, bitmapInfo); OS.CGColorSpaceRelease(colorspace); srcImage = OS.CGBitmapContextCreateImage(context); OS.CGContextRelease(context); } else { int /*long*/ provider = OS.CGDataProviderCreateWithData(0, address, bpr * height, 0); int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB(); srcImage = OS.CGImageCreate(width, height, bps, bpp, bpr, colorspace, bitmapInfo, provider, 0, true, 0); OS.CGColorSpaceRelease(colorspace); OS.CGDataProviderRelease(provider); } } else { if (OS.VERSION >= 0x1060) srcImage = OS.CGDisplayCreateImage(display[0]); } if (srcImage != 0) { copyArea(image, x - (int)rect.origin.x, y - (int)rect.origin.y, srcImage); OS.CGImageRelease(srcImage); } } OS.free(displays); OS.free(countPtr); } } finally { uncheckGC(pool); } } void copyArea (Image image, int x, int y, int /*long*/ srcImage) { if (srcImage == 0) return; NSBitmapImageRep rep = image.getRepresentation(); int /*long*/ bpc = rep.bitsPerSample(); int /*long*/ width = rep.pixelsWide(); int /*long*/ height = rep.pixelsHigh(); int /*long*/ bpr = rep.bytesPerRow(); int /*long*/ data = rep.bitmapData(); int /*long*/ format = rep.bitmapFormat(); int alphaInfo; if (rep.hasAlpha()) { alphaInfo = (format & OS.NSAlphaFirstBitmapFormat) != 0 ? OS.kCGImageAlphaFirst : OS.kCGImageAlphaLast; } else { alphaInfo = (format & OS.NSAlphaFirstBitmapFormat) != 0 ? OS.kCGImageAlphaNoneSkipFirst : OS.kCGImageAlphaNoneSkipLast; } int /*long*/ colorspace = OS.CGColorSpaceCreateDeviceRGB(); int /*long*/ context = OS.CGBitmapContextCreate(data, width, height, bpc, bpr, colorspace, alphaInfo); OS.CGColorSpaceRelease(colorspace); if (context != 0) { CGRect rect = new CGRect(); rect.origin.x = -x; rect.origin.y = y; rect.size.width = OS.CGImageGetWidth(srcImage); rect.size.height = OS.CGImageGetHeight(srcImage); OS.CGContextTranslateCTM(context, 0, -(rect.size.height - height)); OS.CGContextDrawImage(context, rect, srcImage); OS.CGContextRelease(context); } } /** * Copies a rectangular area of the receiver at the source * position onto the receiver at the destination position. * * @param srcX the x coordinate in the receiver of the area to be copied * @param srcY the y coordinate in the receiver of the area to be copied * @param width the width of the area to copy * @param height the height of the area to copy * @param destX the x coordinate in the receiver of the area to copy to * @param destY the y coordinate in the receiver of the area to copy to * * @exception SWTException */ public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY) { copyArea(srcX, srcY, width, height, destX, destY, true); } /** * Copies a rectangular area of the receiver at the source * position onto the receiver at the destination position. * * @param srcX the x coordinate in the receiver of the area to be copied * @param srcY the y coordinate in the receiver of the area to be copied * @param width the width of the area to copy * @param height the height of the area to copy * @param destX the x coordinate in the receiver of the area to copy to * @param destY the y coordinate in the receiver of the area to copy to * @param paint if true paint events will be generated for old and obscured areas * * @exception SWTException * * @since 3.1 */ public void copyArea(int srcX, int srcY, int width, int height, int destX, int destY, boolean paint) { if (handle == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (width <= 0 || height <= 0) return; int deltaX = destX - srcX, deltaY = destY - srcY; if (deltaX == 0 && deltaY == 0) return; NSAutoreleasePool pool = checkGC(TRANSFORM | CLIPPING); try { Image image = data.image; if (image != null) { NSImage imageHandle = image.handle; NSSize size = imageHandle.size(); int imgHeight = (int)size.height; handle.saveGraphicsState(); NSAffineTransform transform = NSAffineTransform.transform(); transform.scaleXBy(1, -1); transform.translateXBy(0, -(height + 2 * destY)); transform.concat(); NSRect srcRect = new NSRect(); srcRect.x = srcX; srcRect.y = imgHeight - (srcY + height); srcRect.width = width; srcRect.height = height; NSRect destRect = new NSRect(); destRect.x = destX; destRect.y = destY; destRect.width = width; destRect.height = height; imageHandle.drawInRect(destRect, srcRect, OS.NSCompositeCopy, 1); handle.restoreGraphicsState(); return; } if (data.view != null) { NSView view = data.view; NSRect visibleRect = view.visibleRect(); if (visibleRect.width <= 0 || visibleRect.height <= 0) return; NSRect damage = new NSRect(); damage.x = srcX; damage.y = srcY; damage.width = width; damage.height = height; NSPoint dest = new NSPoint(); dest.x = destX; dest.y = destY; view.lockFocus(); OS.NSCopyBits(0, damage , dest); view.unlockFocus(); if (paint) { boolean disjoint = (destX + width < srcX) || (srcX + width < destX) || (destY + height < srcY) || (srcY + height < destY); if (disjoint) { view.setNeedsDisplayInRect(damage); } else { if (deltaX != 0) { int newX = destX - deltaX; if (deltaX < 0) newX = destX + width; damage.x = newX; damage.width = Math.abs(deltaX); view.setNeedsDisplayInRect(damage); } if (deltaY != 0) { int newY = destY - deltaY; if (deltaY < 0) newY = destY + height; damage.x = srcX; damage.y = newY; damage.width = width; damage.height = Math.abs (deltaY); view.setNeedsDisplayInRect(damage); } } NSRect srcRect = new NSRect(); srcRect.x = srcX; srcRect.y = srcY; srcRect.width = width; srcRect.height = height; OS.NSIntersectionRect(visibleRect, visibleRect, srcRect); if (!OS.NSEqualRects(visibleRect, srcRect)) { if (srcRect.x != visibleRect.x) { damage.x = srcRect.x + deltaX; damage.y = srcRect.y + deltaY; damage.width = visibleRect.x - srcRect.x; damage.height = srcRect.height; view.setNeedsDisplayInRect(damage); } if (visibleRect.x + visibleRect.width != srcRect.x + srcRect.width) { damage.x = srcRect.x + visibleRect.width + deltaX; damage.y = srcRect.y + deltaY; damage.width = srcRect.width - visibleRect.width; damage.height = srcRect.height; view.setNeedsDisplayInRect(damage); } if (visibleRect.y != srcRect.y) { damage.x = visibleRect.x + deltaX; damage.y = srcRect.y + deltaY; damage.width = visibleRect.width; damage.height = visibleRect.y - srcRect.y; view.setNeedsDisplayInRect(damage); } if (visibleRect.y + visibleRect.height != srcRect.y + srcRect.height) { damage.x = visibleRect.x + deltaX; damage.y = visibleRect.y + visibleRect.height + deltaY; damage.width = visibleRect.width; damage.height = srcRect.y + srcRect.height - (visibleRect.y + visibleRect.height); view.setNeedsDisplayInRect(damage); } } } return; } } finally { uncheckGC(pool); } } static int /*long*/ createCGPathRef(NSBezierPath nsPath) { int /*long*/ count = nsPath.elementCount(); if (count > 0) { int /*long*/ cgPath = OS.CGPathCreateMutable(); if (cgPath == 0) SWT.error(SWT.ERROR_NO_HANDLES); int /*long*/ points = OS.malloc(NSPoint.sizeof * 3); if (points == 0) SWT.error(SWT.ERROR_NO_HANDLES); float /*double*/ [] pt = new float /*double*/ [6]; for (int i = 0; i < count; i++) { int element = (int)/*64*/nsPath.elementAtIndex(i, points); switch (element) { case OS.NSMoveToBezierPathElement: OS.memmove(pt, points, NSPoint.sizeof); OS.CGPathMoveToPoint(cgPath, 0, pt[0], pt[1]); break; case OS.NSLineToBezierPathElement: OS.memmove(pt, points, NSPoint.sizeof); OS.CGPathAddLineToPoint(cgPath, 0, pt[0], pt[1]); break; case OS.NSCurveToBezierPathElement: OS.memmove(pt, points, NSPoint.sizeof * 3); OS.CGPathAddCurveToPoint(cgPath, 0, pt[0], pt[1], pt[2], pt[3], pt[4], pt[5]); break; case OS.NSClosePathBezierPathElement: OS.CGPathCloseSubpath(cgPath); break; } } OS.free(points); return cgPath; } return 0; } void createLayout () { NSSize size = new NSSize(); size.width = OS.MAX_TEXT_CONTAINER_SIZE; size.height = OS.MAX_TEXT_CONTAINER_SIZE; NSTextStorage textStorage = (NSTextStorage)new NSTextStorage().alloc().init(); NSLayoutManager layoutManager = (NSLayoutManager)new NSLayoutManager().alloc().init(); layoutManager.setBackgroundLayoutEnabled(NSThread.isMainThread()); NSTextContainer textContainer = (NSTextContainer)new NSTextContainer().alloc(); textContainer = textContainer.initWithContainerSize(size); textContainer.setLineFragmentPadding(0); textStorage.addLayoutManager(layoutManager); layoutManager.addTextContainer(textContainer); layoutManager.release(); textContainer.release(); data.textContainer = textContainer; data.layoutManager = layoutManager; data.textStorage = textStorage; } NSAttributedString createString(String string, int flags, boolean draw) { NSMutableDictionary dict = ((NSMutableDictionary)new NSMutableDictionary().alloc()).initWithCapacity(5); Font font = data.font; dict.setObject(font.handle, OS.NSFontAttributeName); font.addTraits(dict); if (draw) { Pattern pattern = data.foregroundPattern; if (pattern != null) { if (pattern.color != null) dict.setObject(pattern.color, OS.NSForegroundColorAttributeName); } else { NSColor fg = data.fg; if (fg == null) { float /*double*/ [] color = data.foreground; fg = data.fg = NSColor.colorWithDeviceRed(color[0], color[1], color[2], data.alpha / 255f); fg.retain(); } dict.setObject(fg, OS.NSForegroundColorAttributeName); } } if ((flags & SWT.DRAW_TAB) == 0) { dict.setObject(device.paragraphStyle, OS.NSParagraphStyleAttributeName); } int length = string.length(); char[] chars = new char[length]; string.getChars(0, length, chars, 0); if ((flags & SWT.DRAW_MNEMONIC) !=0 || (flags & SWT.DRAW_DELIMITER) == 0) { int i=0, j=0; while (i < chars.length) { char c = chars [j++] = chars [i++]; switch (c) { case '&': { if ((flags & SWT.DRAW_MNEMONIC) != 0) { if (i == chars.length) {continue;} if (chars [i] == '&') {i++; continue;} j--; } break; } case '\r': case '\n': { if ((flags & SWT.DRAW_DELIMITER) == 0) { if (c == '\r' && i != chars.length && chars[i] == '\n') i++; j--; } break; } } } length = j; } NSString str = ((NSString)new NSString().alloc()).initWithCharacters(chars, length); NSAttributedString attribStr = ((NSAttributedString)new NSAttributedString().alloc()).initWithString(str, dict); dict.release(); str.release(); return attribStr; } NSBezierPath createNSBezierPath (int /*long*/ cgPath) { Callback callback = new Callback(this, "applierFunc", 2); int /*long*/ proc = callback.getAddress(); if (proc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); count = typeCount = 0; element = new CGPathElement(); OS.CGPathApply(cgPath, 0, proc); types = new byte[typeCount]; points = new float /*double*/ [count]; point = new float /*double*/ [6]; count = typeCount = 0; OS.CGPathApply(cgPath, 0, proc); callback.dispose(); NSBezierPath bezierPath = NSBezierPath.bezierPath(); NSPoint nsPoint = new NSPoint(), nsPoint2 = new NSPoint(), nsPoint3 = new NSPoint(); for (int i = 0, j = 0; i < types.length; i++) { switch (types[i]) { case SWT.PATH_MOVE_TO: nsPoint.x = points[j++]; nsPoint.y = points[j++]; bezierPath.moveToPoint(nsPoint); break; case SWT.PATH_LINE_TO: nsPoint.x = points[j++]; nsPoint.y = points[j++]; bezierPath.lineToPoint(nsPoint); break; case SWT.PATH_CUBIC_TO: nsPoint2.x = points[j++]; nsPoint2.y = points[j++]; nsPoint3.x = points[j++]; nsPoint3.y = points[j++]; nsPoint.x = points[j++]; nsPoint.y = points[j++]; bezierPath.curveToPoint(nsPoint, nsPoint2, nsPoint3); break; case SWT.PATH_QUAD_TO: float /*double*/ currentX = nsPoint.x; float /*double*/ currentY = nsPoint.y; nsPoint2.x = points[j++]; nsPoint2.y = points[j++]; nsPoint.x = points[j++]; nsPoint.y = points[j++]; float /*double*/ x0 = currentX; float /*double*/ y0 = currentY; float /*double*/ cx1 = x0 + 2 * (nsPoint2.x - x0) / 3; float /*double*/ cy1 = y0 + 2 * (nsPoint2.y - y0) / 3; float /*double*/ cx2 = cx1 + (nsPoint.x - x0) / 3; float /*double*/ cy2 = cy1 + (nsPoint.y - y0) / 3; nsPoint2.x = cx1; nsPoint2.y = cy1; nsPoint3.x = cx2; nsPoint3.y = cy2; bezierPath.curveToPoint(nsPoint, nsPoint2, nsPoint3); break; case SWT.PATH_CLOSE: bezierPath.closePath(); break; default: dispose(); SWT.error(SWT.ERROR_INVALID_ARGUMENT); } } element = null; types = null; points = null; nsPoint = null; return bezierPath; } void destroy() { /* Free resources */ Image image = data.image; if (image != null) { image.memGC = null; image.createAlpha(); } if (data.textStorage != null) data.textStorage.release(); data.textStorage = null; data.layoutManager = null; data.textContainer = null; if (data.fg != null) data.fg.release(); if (data.bg != null) data.bg.release(); if (data.path != null) data.path.release(); if (data.clipPath != null) data.clipPath.release(); if (data.visiblePath != null) data.visiblePath.release(); if (data.transform != null) data.transform.release(); if (data.inverseTransform != null) data.inverseTransform.release(); data.path = data.clipPath = data.visiblePath = null; data.transform = data.inverseTransform = null; data.fg = data.bg = null; /* Dispose the GC */ if (drawable != null) drawable.internal_dispose_GC(handle.id, data); handle.restoreGraphicsState(); handle.release(); drawable = null; data.image = null; data = null; handle = null; } /** * Draws the outline of a circular or elliptical arc * within the specified rectangular area. *

* 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 == null) 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; NSAutoreleasePool pool = checkGC(DRAW); try { handle.saveGraphicsState(); NSAffineTransform transform = NSAffineTransform.transform(); float /*double*/ xOffset = data.drawXOffset, yOffset = data.drawYOffset; transform.translateXBy(x + xOffset + width / 2f, y + yOffset + height / 2f); transform.scaleXBy(width / 2f, height / 2f); NSBezierPath path = data.path; NSPoint center = new NSPoint(); float sAngle = -startAngle; float eAngle = -(startAngle + arcAngle); path.appendBezierPathWithArcWithCenter(center, 1, sAngle, eAngle, arcAngle>0); path.transformUsingAffineTransform(transform); Pattern pattern = data.foregroundPattern; if (pattern != null && pattern.gradient != null) { strokePattern(path, pattern); } else { path.stroke(); } path.removeAllPoints(); handle.restoreGraphicsState(); } finally { uncheckGC(pool); } } /** * 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 == null) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); NSAutoreleasePool pool = checkGC(CLIPPING | TRANSFORM); try { int[] metric = new int[1]; OS.GetThemeMetric(OS.kThemeMetricFocusRectOutset, metric); CGRect rect = new CGRect(); rect.origin.x = x + metric[0]; rect.origin.y = y + metric[0]; rect.size.width = width - metric[0] * 2; rect.size.height = height - metric[0] * 2; OS.HIThemeDrawFocusRect(rect, true, handle.graphicsPort(), OS.kHIThemeOrientationNormal); } finally { uncheckGC(pool); } } /** * 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