001: /*
002: * @(#)X11Graphics.java 1.27 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027: package java.awt;
028:
029: import java.io.*;
030: import java.util.*;
031: import java.awt.image.ImageObserver;
032:
033: /**
034: * X11Graphics is an object that encapsulates a graphics context for a
035: * particular canvas.
036: *
037: * @version 1.22, 08/19/02
038: */
039:
040: class X11Graphics extends Graphics {
041: private static final Font DEFAULT_FONT = new Font("Dialog",
042: Font.PLAIN, 12);
043: private boolean disposed = false;
044: Color foreground;
045: Color background;
046: Font font;
047: int originX; // TODO: change to float
048: int originY; // TODO: change to float
049: int gc;
050: private int drawable;
051: private Rectangle clip;
052: private X11FontMetrics fontmetrics;
053:
054: // private native void imageCreate(ImageRepresentation ir);
055:
056: private native int createGC(int drawable);
057:
058: private native int copyGC(int drawable, int gc);
059:
060: private native void destroyGC(int gc);
061:
062: // private native void pSetFont(int gc, byte[] f);
063: private native void pSetForeground(int gc, Color c);
064:
065: private native void pSetPaintMode(int gc, Color c);
066:
067: private native void pSetXORMode(int gc, Color cxor);
068:
069: private native void pDrawBytes(int drawable, int gc, int xfontset,
070: byte[] data, int dataLen, int x, int y);
071:
072: private native void pClearRect(int drawable, int x, int y, int w,
073: int h);
074:
075: private native void pFillRect(int drawable, int gc, int x, int y,
076: int w, int h);
077:
078: private native void pDrawRect(int drawable, int gc, int x, int y,
079: int w, int h);
080:
081: private native void pCopyArea(int drawable, int gc, int x, int y,
082: int w, int h, int dx, int dy);
083:
084: private native void pDrawLine(int drawable, int gc, int x1, int y1,
085: int x2, int y2);
086:
087: private native void pDrawPolygon(int drawable, int gc,
088: int xPoints[], int yPoints[], int nPoints);
089:
090: private native void pFillPolygon(int drawable, int gc,
091: int XPoints[], int yPoints[], int nPoints);
092:
093: private native void pDrawArc(int drawable, int gc, int x, int y,
094: int w, int h, int start, int end);
095:
096: private native void pFillArc(int drawable, int gc, int x, int y,
097: int w, int h, int start, int end);
098:
099: private native void pDrawRoundRect(int drawable, int gc, int x,
100: int y, int w, int h, int arcWidth, int arcHeight);
101:
102: private native void pFillRoundRect(int drawable, int gc, int x,
103: int y, int w, int h, int arcWidth, int arcHeight);
104:
105: private native void pDrawImage(int drawableSrc, int drawableDest,
106: int clipmask, int x, int y, int w, int h, int sx, int sy);
107:
108: private native void pDrawImageBG(int drawableSrc, int drawableDest,
109: int clipmask, int x, int y, int w, int h, int sx, int sy,
110: Color c);
111:
112: private native void pDrawImageScale(int src, int drawableDest,
113: int clipmask, int gc, int x, int y, int w, int h, int newW,
114: int newH, int sx, int sy, int clipW, int clipH);
115:
116: private native void pDrawImageScaleBG(int src, int drawableDest,
117: int clipmask, int gc, int x, int y, int w, int h, int newW,
118: int newH, int sx, int sy, int clipW, int clipH, Color c);
119:
120: private native void pDrawImageSub(int drawableSrc,
121: int drawableDest, int clipmask, int gc, int x, int y,
122: int w, int h, int newX, int newY, int newW, int newH,
123: int originx, int originy);
124:
125: private native void pDrawImageSubBG(int drawableSrc,
126: int drawableDest, int clipmask, int gc, int x, int y,
127: int w, int h, int newX, int newY, int newW, int newH,
128: int originx, int originy, Color c);
129:
130: private native void pChangeClipRect(int gc, int x, int y, int w,
131: int h);
132:
133: private native void pRemoveClip(int gc);
134:
135: X11Graphics(HeavyweightComponentXWindow xwindow) {
136: drawable = xwindow.windowID;
137: gc = createGC(drawable);
138: foreground = xwindow.component.foreground;
139: background = xwindow.component.background;
140: if (xwindow instanceof WindowXWindow) {
141: originX = -((WindowXWindow) xwindow).leftBorder;
142: originY = -((WindowXWindow) xwindow).topBorder;
143: }
144: setFont(DEFAULT_FONT);
145: }
146:
147: X11Graphics(X11Graphics g) {
148: drawable = g.drawable;
149: gc = copyGC(drawable, g.gc);
150: foreground = g.foreground;
151: background = g.background;
152: font = g.font;
153: fontmetrics = g.fontmetrics;
154: originX = g.originX;
155: originY = g.originY;
156: clip = g.clip;
157: }
158:
159: X11Graphics(X11Image img) {
160: drawable = img.Xpixmap;
161: gc = createGC(drawable);
162: setFont(DEFAULT_FONT);
163: }
164:
165: /**
166: * Create a new X11Graphics Object based on this one.
167: */
168: public Graphics create() {
169: return new X11Graphics(this );
170: }
171:
172: /**
173: * Translate
174: */
175: public void translate(int x, int y) {
176: originX += x;
177: originY += y;
178: }
179:
180: /*
181: * Subclasses should override disposeImpl() instead of dispose(). Client
182: * code should always invoke dispose(), never disposeImpl().
183: *
184: * An X11Graphics cannot be used after being disposed.
185: */
186: protected native void disposeImpl();
187:
188: public final void dispose() {
189: if (!disposed) {
190: disposed = true;
191: disposeImpl();
192: destroyGC(gc);
193: }
194: }
195:
196: public void setFont(Font font) {
197: if (font == null)
198: font = DEFAULT_FONT;
199: this .font = font;
200: fontmetrics = font.getX11FontMetrics();
201: }
202:
203: public Font getFont() {
204: return font;
205: }
206:
207: /**
208: * Gets the font metrics of the current font.
209: * @return the font metrics of this graphics
210: * context's current font.
211: * @see java.awt.Graphics#getFont
212: * @see java.awt.FontMetrics
213: * @see java.awt.Graphics#getFontMetrics(Font)
214: * @since JDK1.0
215: */
216: public FontMetrics getFontMetrics() {
217: return fontmetrics;
218: }
219:
220: /**
221: * Gets font metrics for the given font.
222: */
223: public FontMetrics getFontMetrics(Font font) {
224: return font.getX11FontMetrics();
225: }
226:
227: /**
228: * Sets the foreground color.
229: */
230: public void setColor(Color c) {
231: if ((c != null) && (c != foreground)) {
232: pSetForeground(gc, c);
233: foreground = c;
234: }
235: }
236:
237: public Color getColor() {
238: return foreground;
239: }
240:
241: /**
242: * Sets the paint mode to overwrite the destination with the
243: * current color. This is the default paint mode.
244: */
245: public void setPaintMode() {
246: pSetPaintMode(gc, foreground);
247: }
248:
249: /**
250: * Sets the paint mode to alternate between the current color
251: * and the given color.
252: */
253: public void setXORMode(Color c1) {
254: pSetXORMode(gc, c1);
255: }
256:
257: /** Clears the rectangle indicated by x,y,w,h. */
258: public void clearRect(int x, int y, int w, int h) {
259: if (clip != null) {
260: Rectangle dim = new Rectangle(x + originX, y + originY, w,
261: h);
262: if ((dim = clip.intersection(dim)) != null)
263: pClearRect(drawable, dim.x, dim.y, dim.width,
264: dim.height);
265: } else
266:
267: pClearRect(drawable, x + originX, y + originY, w, h);
268: }
269:
270: /** Fills the given rectangle with the foreground color. */
271: public void fillRect(int X, int Y, int W, int H) {
272: pFillRect(drawable, gc, X + originX, Y + originY, W, H);
273: }
274:
275: /** Draws the given rectangle. */
276: public void drawRect(int X, int Y, int W, int H) {
277: pDrawRect(drawable, gc, X + originX, Y + originY, W, H);
278: }
279:
280: /** Draws the given line. */
281: public void drawLine(int x1, int y1, int x2, int y2) {
282: pDrawLine(drawable, gc, x1 + originX, y1 + originY, x2
283: + originX, y2 + originY);
284: }
285:
286: /**
287: * Copies an area of the canvas that this graphics context paints to.
288: * @param X the x-coordinate of the source.
289: * @param Y the y-coordinate of the source.
290: * @param W the width.
291: * @param H the height.
292: * @param dx the x-coordinate of the destination.
293: * @param dy the y-coordinate of the destination.
294: */
295: public void copyArea(int X, int Y, int W, int H, int dx, int dy) {
296: if (drawable != 0)
297: pCopyArea(drawable, gc, X + originX, Y + originY, W, H, X
298: + dx + originX, Y + dy + originY);
299: }
300:
301: /** Draws a bunch of lines defined by an array of x points and y points */
302: public void drawPolyline(int xPoints[], int yPoints[], int nPoints) {
303: int i;
304: for (i = 0; i < nPoints; i++) {
305: xPoints[i] += originX;
306: yPoints[i] += originY;
307: }
308: pDrawPolygon(drawable, gc, xPoints, yPoints, nPoints);
309: }
310:
311: /** Draws a polygon defined by an array of x points and y points */
312: public void drawPolygon(int xPoints[], int yPoints[], int nPoints) {
313: int nxPoints[] = new int[nPoints + 1];
314: int nyPoints[] = new int[nPoints + 1];
315: int i;
316: for (i = 0; i < nPoints; i++) {
317: nxPoints[i] += originX;
318: nyPoints[i] += originY;
319: }
320: nxPoints[i] = nxPoints[0] + originX;
321: nyPoints[i] = nyPoints[0] + originY;
322: pDrawPolygon(drawable, gc, xPoints, yPoints, nPoints + 1);
323: }
324:
325: /** Fills a polygon with the current fill mask */
326: public void fillPolygon(int xPoints[], int yPoints[], int nPoints) {
327: int i;
328: for (i = 0; i < nPoints; i++) {
329: xPoints[i] += originX;
330: yPoints[i] += originY;
331: }
332: pFillPolygon(drawable, gc, xPoints, yPoints, nPoints);
333: }
334:
335: /** Draws an oval to fit in the given rectangle */
336: public void drawOval(int x, int y, int w, int h) {
337: pDrawArc(drawable, gc, x + originX, y + originY, w, h, 0,
338: 360 * 64);
339: }
340:
341: /** Fills an oval to fit in the given rectangle */
342: public void fillOval(int x, int y, int w, int h) {
343: pFillArc(drawable, gc, x + originX, y + originY, w, h, 0,
344: 360 * 64);
345: }
346:
347: /**
348: * Draws an arc bounded by the given rectangle from startAngle to
349: * endAngle. 0 degrees is a vertical line straight up from the
350: * center of the rectangle. Positive angles indicate clockwise
351: * rotations, negative angle are counter-clockwise.
352: */
353: public void drawArc(int x, int y, int w, int h, int startAngle,
354: int endAngle) {
355: pDrawArc(drawable, gc, x + originX, y + originY, w, h,
356: startAngle * 64, endAngle * 64);
357: }
358:
359: /** fills an arc. arguments are the same as drawArc. */
360: public void fillArc(int x, int y, int w, int h, int startAngle,
361: int endAngle) {
362: pFillArc(drawable, gc, x + originX, y + originY, w, h,
363: startAngle * 64, endAngle * 64);
364: }
365:
366: /** Draws a rounded rectangle. */
367: public void drawRoundRect(int x, int y, int w, int h, int arcWidth,
368: int arcHeight) {
369: pDrawRoundRect(drawable, gc, x + originX, y + originY, w, h,
370: arcWidth, arcHeight);
371: }
372:
373: /** Draws a filled rounded rectangle. */
374: public void fillRoundRect(int x, int y, int w, int h, int arcWidth,
375: int arcHeight) {
376: pFillRoundRect(drawable, gc, x + originX, y + originY, w, h,
377: arcWidth, arcHeight);
378: }
379:
380: /** Draws the given string. */
381: public void drawString(String string, int x, int y) {
382: if (string == null)
383: return;
384: byte[] newstr = string.getBytes();
385: pDrawBytes(drawable, gc, fontmetrics.XFontSet, newstr,
386: newstr.length, x + originX, y + originY);
387: }
388:
389: /** Draws the given character array. */
390: public void drawChars(char chars[], int offset, int length, int x,
391: int y) {
392: String tmpstr = new String(chars);
393: String substr = tmpstr.substring(offset, offset + length);
394: byte[] newstr = substr.getBytes();
395: pDrawBytes(drawable, gc, fontmetrics.XFontSet, newstr,
396: newstr.length, x + originX, y + originY);
397: }
398:
399: /**
400: * Gets the current clipping area
401: */
402: public Rectangle getClipBounds() {
403: if (clip != null)
404: return new Rectangle(clip.x - originX, clip.y - originY,
405: clip.width, clip.height);
406: return null;
407: }
408:
409: /** Returns a Shape object representing the X11Graphics clip. */
410: public Shape getClip() {
411: return getClipBounds();
412: }
413:
414: /** Crops the clipping rectangle for this X11Graphics context. */
415: public void clipRect(int x, int y, int w, int h) {
416: Rectangle rect = new Rectangle(x + originX, y + originY, w, h);
417: if (clip != null)
418: rect = clip.intersection(rect);
419: clip = rect;
420: pChangeClipRect(gc, clip.x, clip.y, clip.width, clip.height);
421: }
422:
423: /** Sets the clipping rectangle for this X11Graphics context. */
424: public void setClip(int x, int y, int w, int h) {
425: clip = new Rectangle(x + originX, y + originY, w, h);
426: pChangeClipRect(gc, clip.x, clip.y, w, h);
427: }
428:
429: /** Sets the X11Graphics clip to a Shape (only Rectangle allowed). */
430: public void setClip(Shape clip) {
431: if (clip == null) {
432: pRemoveClip(gc);
433: } else if (clip instanceof Rectangle) {
434: Rectangle rect = (Rectangle) clip;
435: setClip(rect.x, rect.y, rect.width, rect.height);
436: } else {
437: throw new IllegalArgumentException(
438: "setClip(Shape) only supports Rectangle objects");
439: }
440: }
441:
442: /**
443: * Draws an image at x,y in nonblocking mode with a callback object.
444: */
445: public boolean drawImage(Image img, int x, int y,
446: ImageObserver observer) {
447: X11Image ximg = (X11Image) img;
448: if ((drawable != 0) && (ximg.Xpixmap != 0)) {
449: x += originX;
450: y += originY;
451: Rectangle dim = new Rectangle(x, y, ximg.width, ximg.height);
452: int sx = 0, sy = 0;
453: if (clip != null) {
454: dim = clip.intersection(dim);
455: int diff;
456: diff = clip.x - x;
457: if (diff > 0)
458: sx = diff;
459: diff = clip.y - y;
460: if (diff > 0)
461: sy = diff;
462: }
463: if ((dim.width > 0) && (dim.height > 0))
464: pDrawImage(ximg.Xpixmap, drawable, ximg.Xclipmask,
465: dim.x, dim.y, dim.width, dim.height, sx, sy);
466: }
467: ximg.addObserver(observer);
468: return true;
469: }
470:
471: /**
472: * Draws an image at x,y in nonblocking mode with a solid background
473: * color and a callback object.
474: */
475: public boolean drawImage(Image img, int x, int y, Color bg,
476: ImageObserver observer) {
477: X11Image ximg = (X11Image) img;
478: if ((drawable != 0) && (ximg.Xpixmap != 0)) {
479: x += originX;
480: y += originY;
481: Rectangle dim = new Rectangle(x, y, ximg.width, ximg.height);
482: int sx = 0, sy = 0;
483: if (clip != null) {
484: dim = clip.intersection(dim);
485: int diff;
486: diff = clip.x - x;
487: if (diff > 0)
488: sx = diff;
489: diff = clip.y - y;
490: if (diff > 0)
491: sy = diff;
492: }
493: if ((dim.width > 0) && (dim.height > 0))
494:
495: pDrawImageBG(ximg.Xpixmap, drawable, ximg.Xclipmask,
496: dim.x, dim.y, dim.width, dim.height, sx, sy, bg);
497: }
498: ximg.addObserver(observer);
499: return true;
500: }
501:
502: /**
503: * Draws an image scaled to x,y,w,h in nonblocking mode with a
504: * callback object.
505: */
506: public boolean drawImage(Image img, int x, int y, int width,
507: int height, ImageObserver observer) {
508: X11Image ximg = (X11Image) img;
509: if ((drawable != 0) && (ximg.Xpixmap != 0)) {
510: x += originX;
511: y += originY;
512: Rectangle dim = new Rectangle(x, y, width, height);
513: int sx = 0, sy = 0;
514: if (clip != null) {
515: dim = clip.intersection(dim);
516: int diff;
517: diff = clip.x - x;
518: if (diff > 0)
519: sx = (diff * ximg.width) / width;
520: diff = clip.y - y;
521: if (diff > 0)
522: sy = (diff * ximg.height) / height;
523: }
524: if ((dim.width > 0) && (dim.height > 0))
525: pDrawImageScale(ximg.Xpixmap, drawable, ximg.Xclipmask,
526: gc, dim.x, dim.y, ximg.width, ximg.height,
527: width, height, sx, sy, dim.width, dim.height);
528: }
529: ximg.addObserver(observer);
530: return true;
531: }
532:
533: /**
534: * Draws an image scaled to x,y,w,h in nonblocking mode with a
535: * solid background color and a callback object.
536: */
537: public boolean drawImage(Image img, int x, int y, int width,
538: int height, Color bg, ImageObserver observer) {
539: X11Image ximg = (X11Image) img;
540: if ((drawable != 0) && (ximg.Xpixmap != 0)) {
541: x += originX;
542: y += originY;
543: Rectangle dim = new Rectangle(x, y, width, height);
544: int sx = 0, sy = 0;
545: if (clip != null) {
546: dim = clip.intersection(dim);
547: int diff;
548: diff = clip.x - x;
549: if (diff > 0)
550: sx = (diff * ximg.width) / width;
551: diff = clip.y - y;
552: if (diff > 0)
553: sy = (diff * ximg.height) / height;
554: }
555: if ((dim.width > 0) && (dim.height > 0))
556:
557: pDrawImageScaleBG(ximg.Xpixmap, drawable,
558: ximg.Xclipmask, gc, dim.x, dim.y, ximg.width,
559: ximg.height, width, height, sx, sy, dim.width,
560: dim.height, bg);
561: }
562: ximg.addObserver(observer);
563: return true;
564: }
565:
566: /**
567: * Draws a subrectangle of an image scaled to a destination rectangle
568: * in nonblocking mode with a callback object.
569: */
570: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
571: int dy2, int sx1, int sy1, int sx2, int sy2,
572: ImageObserver observer) {
573: X11Image ximg = (X11Image) img;
574: if ((drawable != 0) && (ximg.Xpixmap != 0)) {
575: Rectangle srcRect = new Rectangle(Math.min(sx1, sx2), Math
576: .min(sy1, sy2), Math.abs(sx2 - sx1), Math.abs(sy2
577: - sy1));
578: Rectangle newRect = srcRect.intersection(new Rectangle(0,
579: 0, ximg.width, ximg.height));
580: int nx1, nx2;
581: nx1 = nx2 = newRect.x;
582: if (sx1 < sx2)
583: nx2 += newRect.width - 1;
584: else
585: nx1 += newRect.width - 1;
586: int ny1, ny2;
587: ny1 = ny2 = newRect.y;
588: if (sy1 < sy2)
589: ny2 += newRect.height - 1;
590: else
591: ny1 += newRect.height - 1;
592: pDrawImageSub(ximg.Xpixmap, drawable, ximg.Xclipmask, gc,
593: nx1, ny1, nx2, ny2, dx1, dy1, dx2, dy2, originX,
594: originY);
595: }
596: ximg.addObserver(observer);
597: return true;
598: }
599:
600: /**
601: * Draws a subrectangle of an image scaled to a destination rectangle in
602: * nonblocking mode with a solid background color and a callback object.
603: */
604: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
605: int dy2, int sx1, int sy1, int sx2, int sy2, Color bg,
606: ImageObserver observer) {
607: X11Image ximg = (X11Image) img;
608: if ((drawable != 0) && (ximg.Xpixmap != 0)) {
609: Rectangle srcRect = new Rectangle(Math.min(sx1, sx2), Math
610: .min(sy1, sy2), Math.abs(sx2 - sx1), Math.abs(sy2
611: - sy1));
612: Rectangle newRect = srcRect.intersection(new Rectangle(0,
613: 0, ximg.width, ximg.height));
614: int nx1, nx2;
615: nx1 = nx2 = newRect.x;
616: if (sx1 < sx2)
617: nx2 += newRect.width - 1;
618: else
619: nx1 += newRect.width - 1;
620: int ny1, ny2;
621: ny1 = ny2 = newRect.y;
622: if (sy1 < sy2)
623: ny2 += newRect.height - 1;
624: else
625: ny1 += newRect.height - 1;
626: pDrawImageSubBG(ximg.Xpixmap, drawable, ximg.Xclipmask, gc,
627: nx1, ny1, nx2, ny2, dx1, dy1, dx2, dy2, originX,
628: originY, bg);
629: }
630: ximg.addObserver(observer);
631: return true;
632: }
633:
634: public String toString() {
635: return getClass().getName() + "[" + originX + "," + originY
636: + "]";
637: }
638: /* Outline the given region. */
639: //public native void drawRegion(Region r);
640: /* Fill the given region. */
641: //public native void fillRegion(Region r);
642: }
|