/******************************************************************************* * Copyright (c) 2000, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.swt.graphics; import org.eclipse.swt.internal.*; import org.eclipse.swt.internal.cocoa.*; import org.eclipse.swt.*; /** * Instances of this class represent areas of an x-y coordinate * system that are aggregates of the areas covered by a number * of polygons. *

* Application code must explicitly invoke the Region.dispose() * method to release the operating system resources managed by each instance * when those instances are no longer required. *

* * @see SWT Example: GraphicsExample * @see Sample code and further information */ public final class Region extends Resource { /** * the OS resource for the region * (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 long /*int*/ handle; /** * Constructs a new empty region. * * @exception SWTError */ public Region() { this(null); } /** * Constructs a new empty region. *

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

* * @param device the device on which to allocate the region * * @exception IllegalArgumentException * @exception SWTError * * @see #dispose * * @since 3.0 */ public Region(Device device) { super(device); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { handle = OS.NewRgn(); if (handle == 0) SWT.error(SWT.ERROR_NO_HANDLES); init(); } finally { if (pool != null) pool.release(); } } Region(Device device, long /*int*/ handle) { super(device); this.handle = handle; } public static Region cocoa_new(Device device, long /*int*/ handle) { return new Region(device, handle); } static long /*int*/ polyToRgn(int[] poly, int length) { short[] r = new short[4]; long /*int*/ polyRgn = OS.NewRgn(), rectRgn = OS.NewRgn(); int minY = poly[1], maxY = poly[1]; for (int y = 3; y < length; y += 2) { if (poly[y] < minY) minY = poly[y]; if (poly[y] > maxY) maxY = poly[y]; } int[] inter = new int[length + 1]; for (int y = minY; y <= maxY; y++) { int count = 0; int x1 = poly[0], y1 = poly[1]; for (int p = 2; p < length; p += 2) { int x2 = poly[p], y2 = poly[p + 1]; if (y1 != y2 && ((y1 <= y && y < y2) || (y2 <= y && y < y1))) { inter[count++] = (int)((((y - y1) / (float)(y2 - y1)) * (x2 - x1)) + x1 + 0.5f); } x1 = x2; y1 = y2; } int x2 = poly[0], y2 = poly[1]; if (y1 != y2 && ((y1 <= y && y < y2) || (y2 <= y && y < y1))) { inter[count++] = (int)((((y - y1) / (float)(y2 - y1)) * (x2 - x1)) + x1 + 0.5f); } for (int gap=count/2; gap>0; gap/=2) { for (int i=gap; i=0; j-=gap) { if ((inter[j] - inter[j + gap]) <= 0) break; int temp = inter[j]; inter[j] = inter[j + gap]; inter[j + gap] = temp; } } } for (int i = 0; i < count; i += 2) { OS.SetRect(r, (short)inter[i], (short)y, (short)(inter[i + 1]),(short)(y + 1)); OS.RectRgn(rectRgn, r); OS.UnionRgn(polyRgn, rectRgn, polyRgn); } } OS.DisposeRgn(rectRgn); return polyRgn; } static long /*int*/ polyRgn(int[] pointArray, int count) { NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { long /*int*/ polyRgn; if (C.PTR_SIZEOF == 4) { polyRgn = OS.NewRgn(); OS.OpenRgn(); OS.MoveTo((short)pointArray[0], (short)pointArray[1]); for (int i = 1; i < count / 2; i++) { OS.LineTo((short)pointArray[2 * i], (short)pointArray[2 * i + 1]); } OS.LineTo((short)pointArray[0], (short)pointArray[1]); OS.CloseRgn(polyRgn); } else { polyRgn = polyToRgn(pointArray, count); } return polyRgn; } finally { if (pool != null) pool.release(); } } /** * Adds the given polygon to the collection of polygons * the receiver maintains to describe its area. * * @param pointArray points that describe the polygon to merge with the receiver * * @exception IllegalArgumentException * @exception SWTException * * @since 3.0 * */ public void add (int[] pointArray) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { add(pointArray, pointArray.length); } finally { if (pool != null) pool.release(); } } void add(int[] pointArray, int count) { count = count / 2 * 2; if (count <= 2) return; NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { long /*int*/ polyRgn = polyRgn(pointArray, count); OS.UnionRgn(handle, polyRgn, handle); OS.DisposeRgn(polyRgn); } finally { if (pool != null) pool.release(); } } /** * Adds the given rectangle to the collection of polygons * the receiver maintains to describe its area. * * @param rect the rectangle to merge with the receiver * * @exception IllegalArgumentException * @exception SWTException */ public void add(Rectangle rect) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (rect.width < 0 || rect.height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { add (rect.x, rect.y, rect.width, rect.height); } finally { if (pool != null) pool.release(); } } /** * Adds the given rectangle to the collection of polygons * the receiver maintains to describe its area. * * @param x the x coordinate of the rectangle * @param y the y coordinate of the rectangle * @param width the width coordinate of the rectangle * @param height the height coordinate of the rectangle * * @exception IllegalArgumentException * @exception SWTException * * @since 3.1 */ public void add(int x, int y, int width, int height) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { long /*int*/ rectRgn = OS.NewRgn(); short[] r = new short[4]; OS.SetRect(r, (short)x, (short)y, (short)(x + width),(short)(y + height)); OS.RectRgn(rectRgn, r); OS.UnionRgn(handle, rectRgn, handle); OS.DisposeRgn(rectRgn); } finally { if (pool != null) pool.release(); } } /** * Adds all of the polygons which make up the area covered * by the argument to the collection of polygons the receiver * maintains to describe its area. * * @param region the region to merge * * @exception IllegalArgumentException * @exception SWTException */ public void add(Region region) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { OS.UnionRgn(handle, region.handle, handle); } finally { if (pool != null) pool.release(); } } /** * Returns true if the point specified by the * arguments is inside the area specified by the receiver, * and false otherwise. * * @param x the x coordinate of the point to test for containment * @param y the y coordinate of the point to test for containment * @return true if the region contains the point and false otherwise * * @exception SWTException */ public boolean contains(int x, int y) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { short[] point = new short[]{(short)y, (short)x}; return OS.PtInRgn(point, handle); } finally { if (pool != null) pool.release(); } } /** * Returns true if the given point is inside the * area specified by the receiver, and false * otherwise. * * @param pt the point to test for containment * @return true if the region contains the point and false otherwise * * @exception IllegalArgumentException * @exception SWTException */ public boolean contains(Point pt) { if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); return contains(pt.x, pt.y); } NSAffineTransform transform; void convertRgn(NSAffineTransform transform) { long /*int*/ newRgn = OS.NewRgn(); Callback callback = new Callback(this, "convertRgn", 4); long /*int*/ proc = callback.getAddress(); if (proc == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); this.transform = transform; OS.QDRegionToRects(handle, OS.kQDParseRegionFromTopLeft, proc, newRgn); this.transform = null; callback.dispose(); OS.CopyRgn(newRgn, handle); OS.DisposeRgn(newRgn); } long /*int*/ convertRgn(long /*int*/ message, long /*int*/ rgn, long /*int*/ r, long /*int*/ newRgn) { if (message == OS.kQDRegionToRectsMsgParse) { short[] rect = new short[4]; OS.memmove(rect, r, rect.length * 2); int i = 0; NSPoint point = new NSPoint(); int[] points = new int[10]; point.x = rect[1]; point.y = rect[0]; point = transform.transformPoint(point); short startX, startY; points[i++] = startX = (short)point.x; points[i++] = startY = (short)point.y; point.x = rect[3]; point.y = rect[0]; point = transform.transformPoint(point); points[i++] = (short)Math.round(point.x); points[i++] = (short)point.y; point.x = rect[3]; point.y = rect[2]; point = transform.transformPoint(point); points[i++] = (short)Math.round(point.x); points[i++] = (short)Math.round(point.y); point.x = rect[1]; point.y = rect[2]; point = transform.transformPoint(point); points[i++] = (short)point.x; points[i++] = (short)Math.round(point.y); points[i++] = startX; points[i++] = startY; long /*int*/ polyRgn = polyRgn(points, points.length); OS.UnionRgn(newRgn, polyRgn, newRgn); OS.DisposeRgn(polyRgn); } return 0; } void destroy() { OS.DisposeRgn(handle); handle = 0; } /** * Compares the argument to the receiver, and returns true * if they represent the same object using a class * specific comparison. * * @param object the object to compare with this object * @return true if the object is the same as this object and false otherwise * * @see #hashCode */ public boolean equals(Object object) { if (this == object) return true; if (!(object instanceof Region)) return false; Region region = (Region)object; return handle == region.handle; } /** * Returns a rectangle which represents the rectangular * union of the collection of polygons the receiver * maintains to describe its area. * * @return a bounding rectangle for the region * * @exception SWTException * * @see Rectangle#union */ public Rectangle getBounds() { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { short[] bounds = new short[4]; OS.GetRegionBounds(handle, bounds); int width = bounds[3] - bounds[1]; int height = bounds[2] - bounds[0]; return new Rectangle(bounds[1], bounds[0], width, height); } finally { if (pool != null) pool.release(); } } NSBezierPath getPath() { Callback callback = new Callback(this, "regionToRects", 4); if (callback.getAddress() == 0) SWT.error(SWT.ERROR_NO_MORE_CALLBACKS); NSBezierPath path = NSBezierPath.bezierPath(); path.retain(); OS.QDRegionToRects(handle, OS.kQDParseRegionFromTopLeft, callback.getAddress(), path.id); callback.dispose(); if (path.isEmpty()) path.appendBezierPathWithRect(new NSRect()); return path; } NSPoint pt = new NSPoint(); short[] rect = new short[4]; long /*int*/ regionToRects(long /*int*/ message, long /*int*/ rgn, long /*int*/ r, long /*int*/ path) { if (message == OS.kQDRegionToRectsMsgParse) { OS.memmove(rect, r, rect.length * 2); pt.x = rect[1]; pt.y = rect[0]; OS.objc_msgSend(path, OS.sel_moveToPoint_, pt); pt.x = rect[3]; OS.objc_msgSend(path, OS.sel_lineToPoint_, pt); pt.x = rect[3]; pt.y = rect[2]; OS.objc_msgSend(path, OS.sel_lineToPoint_, pt); pt.x = rect[1]; OS.objc_msgSend(path, OS.sel_lineToPoint_, pt); OS.objc_msgSend(path, OS.sel_closePath); } return 0; } /** * Returns an integer hash code for the receiver. Any two * objects that return true when passed to * equals must return the same value for this * method. * * @return the receiver's hash * * @see #equals */ public int hashCode() { return (int)/*64*/handle; } /** * Intersects the given rectangle to the collection of polygons * the receiver maintains to describe its area. * * @param rect the rectangle to intersect with the receiver * * @exception IllegalArgumentException * @exception SWTException * * @since 3.0 */ public void intersect(Rectangle rect) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); intersect (rect.x, rect.y, rect.width, rect.height); } /** * Intersects the given rectangle to the collection of polygons * the receiver maintains to describe its area. * * @param x the x coordinate of the rectangle * @param y the y coordinate of the rectangle * @param width the width coordinate of the rectangle * @param height the height coordinate of the rectangle * * @exception IllegalArgumentException * @exception SWTException * * @since 3.1 */ public void intersect(int x, int y, int width, int height) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { long /*int*/ rectRgn = OS.NewRgn(); short[] r = new short[4]; OS.SetRect(r, (short)x, (short)y, (short)(x + width),(short)(y + height)); OS.RectRgn(rectRgn, r); OS.SectRgn(handle, rectRgn, handle); OS.DisposeRgn(rectRgn); } finally { if (pool != null) pool.release(); } } /** * Intersects all of the polygons which make up the area covered * by the argument to the collection of polygons the receiver * maintains to describe its area. * * @param region the region to intersect * * @exception IllegalArgumentException * @exception SWTException * * @since 3.0 */ public void intersect(Region region) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { OS.SectRgn(handle, region.handle, handle); } finally { if (pool != null) pool.release(); } } /** * Returns true if the rectangle described by the * arguments intersects with any of the polygons the receiver * maintains to describe its area, and false otherwise. * * @param x the x coordinate of the origin of the rectangle * @param y the y coordinate of the origin of the rectangle * @param width the width of the rectangle * @param height the height of the rectangle * @return true if the rectangle intersects with the receiver, and false otherwise * * @exception SWTException * * @see Rectangle#intersects(Rectangle) */ public boolean intersects (int x, int y, int width, int height) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { short[] r = new short[4]; OS.SetRect(r, (short)x, (short)y, (short)(x + width),(short)(y + height)); return OS.RectInRgn(r, handle); } finally { if (pool != null) pool.release(); } } /** * Returns true if the given rectangle intersects * with any of the polygons the receiver maintains to describe * its area and false otherwise. * * @param rect the rectangle to test for intersection * @return true if the rectangle intersects with the receiver, and false otherwise * * @exception IllegalArgumentException * @exception SWTException * * @see Rectangle#intersects(Rectangle) */ public boolean intersects(Rectangle rect) { if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); return intersects(rect.x, rect.y, rect.width, rect.height); } /** * Returns true if the region has been disposed, * and false otherwise. *

* This method gets the dispose state for the region. * When a region has been disposed, it is an error to * invoke any other method (except {@link #dispose()}) using the region. * * @return true when the region is disposed, and false otherwise */ public boolean isDisposed() { return handle == 0; } /** * Returns true if the receiver does not cover any * area in the (x, y) coordinate plane, and false if * the receiver does cover some area in the plane. * * @return true if the receiver is empty, and false otherwise * * @exception SWTException

*/ public boolean isEmpty() { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { return OS.EmptyRgn(handle); } finally { if (pool != null) pool.release(); } } /** * Subtracts the given polygon from the collection of polygons * the receiver maintains to describe its area. * * @param pointArray points that describe the polygon to merge with the receiver * * @exception IllegalArgumentException * @exception SWTException * * @since 3.0 */ public void subtract (int[] pointArray) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (pointArray == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (pointArray.length < 2) return; NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { long /*int*/ polyRgn = polyRgn(pointArray, pointArray.length); OS.DiffRgn(handle, polyRgn, handle); OS.DisposeRgn(polyRgn); } finally { if (pool != null) pool.release(); } } /** * Subtracts the given rectangle from the collection of polygons * the receiver maintains to describe its area. * * @param rect the rectangle to subtract from the receiver * * @exception IllegalArgumentException * @exception SWTException * * @since 3.0 */ public void subtract(Rectangle rect) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (rect == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); subtract (rect.x, rect.y, rect.width, rect.height); } /** * Subtracts the given rectangle from the collection of polygons * the receiver maintains to describe its area. * * @param x the x coordinate of the rectangle * @param y the y coordinate of the rectangle * @param width the width coordinate of the rectangle * @param height the height coordinate of the rectangle * * @exception IllegalArgumentException * @exception SWTException * * @since 3.1 */ public void subtract(int x, int y, int width, int height) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (width < 0 || height < 0) SWT.error(SWT.ERROR_INVALID_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { long /*int*/ rectRgn = OS.NewRgn(); short[] r = new short[4]; OS.SetRect(r, (short)x, (short)y, (short)(x + width),(short)(y + height)); OS.RectRgn(rectRgn, r); OS.DiffRgn(handle, rectRgn, handle); OS.DisposeRgn(rectRgn); } finally { if (pool != null) pool.release(); } } /** * Subtracts all of the polygons which make up the area covered * by the argument from the collection of polygons the receiver * maintains to describe its area. * * @param region the region to subtract * * @exception IllegalArgumentException * @exception SWTException * * @since 3.0 */ public void subtract(Region region) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (region == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); if (region.isDisposed()) SWT.error(SWT.ERROR_INVALID_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { OS.DiffRgn(handle, region.handle, handle); } finally { if (pool != null) pool.release(); } } /** * Translate all of the polygons the receiver maintains to describe * its area by the specified point. * * @param x the x coordinate of the point to translate * @param y the y coordinate of the point to translate * * @exception SWTException * * @since 3.1 */ public void translate (int x, int y) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { OS.OffsetRgn (handle, (short)x, (short)y); } finally { if (pool != null) pool.release(); } } /** * Translate all of the polygons the receiver maintains to describe * its area by the specified point. * * @param pt the point to translate * * @exception IllegalArgumentException * @exception SWTException * * @since 3.1 */ public void translate (Point pt) { if (isDisposed()) SWT.error(SWT.ERROR_GRAPHIC_DISPOSED); if (pt == null) SWT.error(SWT.ERROR_NULL_ARGUMENT); NSAutoreleasePool pool = null; if (!NSThread.isMainThread()) pool = (NSAutoreleasePool) new NSAutoreleasePool().alloc().init(); try { translate (pt.x, pt.y); } finally { if (pool != null) pool.release(); } } /** * Returns a string containing a concise, human-readable * description of the receiver. * * @return a string representation of the receiver */ public String toString () { if (isDisposed()) return "Region {*DISPOSED*}"; return "Region {" + handle + "}"; } }