001: /*
002: * @(#)MWGraphics.java 1.46 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.BufferedImage;
032: import java.awt.image.ImageObserver;
033: import sun.awt.ConstrainableGraphics;
034:
035: /**
036: * MWGraphics is an object that encapsulates a graphics context for drawing with Microwindows.
037: *
038: * @version 1.12, 11/27/01
039: */
040:
041: class MWGraphics extends Graphics2D implements ConstrainableGraphics {
042: /** The default font to use when no font has been set or null is used. */
043:
044: private static final Font DEFAULT_FONT = new Font("Dialog",
045: Font.PLAIN, 12);
046: private boolean disposed = false;
047: private AlphaComposite composite;
048: /** The current foreground color. */
049:
050: private Color foreground;
051: /** The current background color. This is used by clearRect. */
052:
053: private Color background;
054: /** The current xor color. If null then we are in paint mode. */
055:
056: private Color xorColor;
057: /** The currently selected font for text operations. */
058:
059: private Font font;
060: /** The font metrics for the font. Cached for performance. */
061:
062: private MWFontMetrics fontMetrics;
063: /** Translated X offset from native offset. */
064:
065: private int originX;
066: /** Translated Y offset from native offset. */
067:
068: private int originY;
069: /** The MicoWindows PSD used to represent this Graphics object. */
070:
071: int psd;
072: /** The current user clip rectangle or null if no clip has been set. This is stored in the
073: native coordinate system and not the possibly translated Java coordinate system. */
074:
075: private Rectangle clip;
076: /** The rectangle this graphics object has been constrained too. This is stored in the
077: native coordinate system and not the (possibly) translated Java coordinate system.
078: If it is null then this graphics has not been constrained. The constrained rectangle
079: is another layer of clipping independant of the user clip. The actaul clip used is the
080: intersection */
081:
082: private Rectangle constrainedRect;
083: /** The GraphicsConfiguration that this graphics uses. */
084:
085: private GraphicsConfiguration graphicsConfiguration;
086:
087: static native int pClonePSD(int psd);
088:
089: static native void pDisposePSD(int psd);
090:
091: private static native void pSetColor(int psd, int rgb);
092:
093: private static native void pSetComposite(int psd, int rule,
094: float extraAlpha);
095:
096: private static native void pSetPaintMode(int psd);
097:
098: private static native void pSetXORMode(int psd, int rgb);
099:
100: private static native void pDrawString(int psd, int font,
101: String string, int x, int y);
102:
103: private static native void pDrawChars(int psd, int font,
104: char[] chars, int offset, int length, int x, int y);
105:
106: private static native void pFillRect(int psd, int x, int y,
107: int width, int height);
108:
109: private static native void pClearRect(int psd, int x, int y,
110: int width, int height, int rgb);
111:
112: private static native void pDrawRect(int psd, int x, int y,
113: int width, int height);
114:
115: private static native void pCopyArea(int psd, int x, int y,
116: int width, int height, int dx, int dy);
117:
118: private static native void pDrawLine(int psd, int x1, int y1,
119: int x2, int y2);
120:
121: private static native void pDrawPolygon(int psd, int orinX,
122: int originY, int xPoints[], int yPoints[], int nPoints,
123: boolean close);
124:
125: private static native void pFillPolygon(int psd, int orinX,
126: int originY, int xPoints[], int yPoints[], int nPoints);
127:
128: private static native void pDrawArc(int psd, int x, int y,
129: int width, int height, int start, int end);
130:
131: private static native void pFillArc(int psd, int x, int y,
132: int width, int height, int start, int end);
133:
134: private static native void pDrawOval(int psd, int x, int y,
135: int width, int height);
136:
137: private static native void pFillOval(int psd, int x, int y,
138: int width, int height);
139:
140: private static native void pDrawRoundRect(int psd, int x, int y,
141: int width, int height, int arcWidth, int arcHeight);
142:
143: private static native void pFillRoundRect(int psd, int x, int y,
144: int width, int height, int arcWidth, int arcHeight);
145:
146: private static native void pChangeClipRect(int psd, int x, int y,
147: int width, int height);
148:
149: private static native void pRemoveClip(int psd);
150:
151: private static native MWImage getBufferedImagePeer(BufferedImage bi);
152:
153: MWGraphics(Window window) {
154: psd = pClonePSD(((MWGraphicsDevice) window
155: .getGraphicsConfiguration().getDevice()).psd);
156: foreground = window.foreground;
157: if (foreground == null)
158: foreground = Color.black;
159: pSetColor(psd, foreground.value);
160: background = window.background;
161: if (background == null)
162: background = Color.black;
163: composite = AlphaComposite.SrcOver;
164: graphicsConfiguration = window.getGraphicsConfiguration();
165: setFont(DEFAULT_FONT);
166: }
167:
168: MWGraphics(MWGraphics g) {
169: psd = pClonePSD(g.psd);
170: foreground = g.foreground;
171: background = g.background;
172: composite = g.composite;
173: graphicsConfiguration = g.graphicsConfiguration;
174: font = g.font;
175: fontMetrics = g.fontMetrics;
176: originX = g.originX;
177: originY = g.originY;
178: clip = g.clip;
179: constrainedRect = g.constrainedRect;
180: }
181:
182: MWGraphics(MWOffscreenImage image) {
183: psd = pClonePSD(image.psd);
184: foreground = image.foreground;
185: if (foreground == null)
186: foreground = Color.black;
187: background = image.background;
188: if (background == null)
189: background = Color.black;
190: composite = AlphaComposite.SrcOver;
191: graphicsConfiguration = image.gc;
192: font = image.font;
193: if (font == null)
194: font = DEFAULT_FONT;
195: fontMetrics = MWFontMetrics.getFontMetrics(font);
196: }
197:
198: MWGraphics(MWSubimage image, int x, int y) {
199: psd = pClonePSD(image.psd);
200: composite = AlphaComposite.SrcOver;
201: originX = x;
202: originY = y;
203: }
204:
205: /**
206: * Create a new MWGraphics Object based on this one.
207: */
208: public Graphics create() {
209: return new MWGraphics(this );
210: }
211:
212: /**
213: * Translate
214: */
215: public void translate(int x, int y) {
216: originX += x;
217: originY += y;
218: }
219:
220: public void finalize() {
221: dispose();
222: }
223:
224: public final void dispose() {
225: if (!disposed) {
226: disposed = true;
227: pDisposePSD(psd);
228: }
229: }
230:
231: public void setFont(Font font) {
232: if (font != null && !font.equals(this .font)) {
233: this .font = font;
234: fontMetrics = MWFontMetrics.getFontMetrics(font);
235: }
236: }
237:
238: public Font getFont() {
239: return font;
240: }
241:
242: /**
243: * Gets the font metrics of the current font.
244: * @return the font metrics of this graphics
245: * context's current font.
246: * @see java.awt.Graphics#getFont
247: * @see java.awt.FontMetrics
248: * @see java.awt.Graphics#getFontMetrics(Font)
249: * @since JDK1.0
250: */
251: public FontMetrics getFontMetrics() {
252: return fontMetrics;
253: }
254:
255: /**
256: * Gets font metrics for the given font.
257: */
258: public FontMetrics getFontMetrics(Font font) {
259: return MWFontMetrics.getFontMetrics(font);
260: }
261:
262: /**
263: * Sets the foreground color.
264: */
265: public void setColor(Color c) {
266: if ((c != null) && (c != foreground)) {
267: foreground = c;
268: pSetColor(psd, foreground.value);
269: }
270: }
271:
272: public Color getColor() {
273: return foreground;
274: }
275:
276: public Composite getComposite() {
277: return composite;
278: }
279:
280: public GraphicsConfiguration getDeviceConfiguration() {
281: return graphicsConfiguration;
282: }
283:
284: public void setComposite(Composite comp) {
285: if ((comp != null) && (comp != composite)) {
286: if (!(comp instanceof AlphaComposite))
287: throw new IllegalArgumentException(
288: "Only AlphaComposite is supported");
289: composite = (AlphaComposite) comp;
290: pSetComposite(psd, composite.rule, composite.extraAlpha);
291: }
292: }
293:
294: /**
295: * Sets the paint mode to overwrite the destination with the
296: * current color. This is the default paint mode.
297: */
298: public void setPaintMode() {
299: xorColor = null;
300: pSetPaintMode(psd);
301: }
302:
303: /**
304: * Sets the paint mode to alternate between the current color
305: * and the given color.
306: */
307: public void setXORMode(Color color) {
308: xorColor = color;
309: pSetXORMode(psd, color.value);
310: }
311:
312: /** Clears the rectangle indicated by x,y,w,h. */
313:
314: public void clearRect(int x, int y, int w, int h) {
315: pClearRect(psd, x + originX, y + originY, w, h,
316: background.value);
317: }
318:
319: /** Fills the given rectangle with the foreground color. */
320:
321: public void fillRect(int x, int y, int w, int h) {
322: pFillRect(psd, x + originX, y + originY, w, h);
323: }
324:
325: /** Draws the given rectangle. */
326: public void drawRect(int x, int y, int w, int h) {
327: pDrawRect(psd, x + originX, y + originY, w, h);
328: }
329:
330: /** Draws the given line. */
331: public void drawLine(int x1, int y1, int x2, int y2) {
332: pDrawLine(psd, x1 + originX, y1 + originY, x2 + originX, y2
333: + originY);
334: }
335:
336: /**
337: * Copies an area of the canvas that this graphics context paints to.
338: * @param X the x-coordinate of the source.
339: * @param Y the y-coordinate of the source.
340: * @param W the width.
341: * @param H the height.
342: * @param dx the horizontal distance to copy the pixels.
343: * @param dy the vertical distance to copy the pixels.
344: */
345: public void copyArea(int X, int Y, int W, int H, int dx, int dy) {
346: X += originX;
347: Y += originY;
348: pCopyArea(psd, X, Y, W, H, dx, dy);
349: }
350:
351: /** Draws lines defined by an array of x points and y points */
352:
353: public void drawPolyline(int xPoints[], int yPoints[], int nPoints) {
354: pDrawPolygon(psd, originX, originY, xPoints, yPoints, nPoints,
355: false);
356: }
357:
358: /** Draws a polygon defined by an array of x points and y points */
359:
360: public void drawPolygon(int xPoints[], int yPoints[], int nPoints) {
361: pDrawPolygon(psd, originX, originY, xPoints, yPoints, nPoints,
362: true);
363: }
364:
365: /** Fills a polygon with the current fill mask */
366:
367: public void fillPolygon(int xPoints[], int yPoints[], int nPoints) {
368: pFillPolygon(psd, originX, originY, xPoints, yPoints, nPoints);
369: }
370:
371: /** Draws an oval to fit in the given rectangle */
372: public void drawOval(int x, int y, int w, int h) {
373: pDrawOval(psd, x + originX, y + originY, w, h);
374: }
375:
376: /** Fills an oval to fit in the given rectangle */
377: public void fillOval(int x, int y, int w, int h) {
378: pFillOval(psd, x + originX, y + originY, w, h);
379: }
380:
381: /**
382: * Draws an arc bounded by the given rectangle from startAngle to
383: * endAngle. 0 degrees is a vertical line straight up from the
384: * center of the rectangle. Positive start angle indicate clockwise
385: * rotations, negative angle are counter-clockwise.
386: */
387: public void drawArc(int x, int y, int w, int h, int startAngle,
388: int endAngle) {
389: pDrawArc(psd, x + originX, y + originY, w, h, startAngle,
390: endAngle);
391: }
392:
393: /** fills an arc. arguments are the same as drawArc. */
394: public void fillArc(int x, int y, int w, int h, int startAngle,
395: int endAngle) {
396: pFillArc(psd, x + originX, y + originY, w, h, startAngle,
397: endAngle);
398: }
399:
400: /** Draws a rounded rectangle. */
401: public void drawRoundRect(int x, int y, int w, int h, int arcWidth,
402: int arcHeight) {
403: pDrawRoundRect(psd, x + originX, y + originY, w, h, arcWidth,
404: arcHeight);
405: }
406:
407: /** Draws a filled rounded rectangle. */
408: public void fillRoundRect(int x, int y, int w, int h, int arcWidth,
409: int arcHeight) {
410: pFillRoundRect(psd, x + originX, y + originY, w, h, arcWidth,
411: arcHeight);
412: }
413:
414: /** Draws the given string. */
415: public void drawString(String string, int x, int y) {
416: if (string == null)
417: return;
418: pDrawString(psd, fontMetrics.nativeFont, string, x + originX, y
419: + originY);
420: }
421:
422: /** Draws the given character array. */
423: public void drawChars(char chars[], int offset, int length, int x,
424: int y) {
425: pDrawChars(psd, fontMetrics.nativeFont, chars, offset, length,
426: x + originX, y + originY);
427: }
428:
429: /**
430: * Gets the current clipping area
431: */
432: public Rectangle getClipBounds() {
433: if (clip != null)
434: return new Rectangle(clip.x - originX, clip.y - originY,
435: clip.width, clip.height);
436: return null;
437: }
438:
439: /** Returns a Shape object representing the MicroWindows clip. */
440:
441: public Shape getClip() {
442: return getClipBounds();
443: }
444:
445: public void constrain(int x, int y, int w, int h) {
446: originX += x;
447: originY += y;
448: Rectangle rect = new Rectangle(originX, originY, w, h);
449: if (constrainedRect != null)
450: constrainedRect = constrainedRect.intersection(rect);
451: else
452: constrainedRect = rect;
453: setupClip();
454: }
455:
456: /** Crops the clipping rectangle for this MicroWindows context. */
457:
458: public void clipRect(int x, int y, int w, int h) {
459: Rectangle rect = new Rectangle(x + originX, y + originY, w, h);
460: if (clip != null)
461: clip = clip.intersection(rect);
462: else
463: clip = rect;
464: setupClip();
465: }
466:
467: /** Sets up the clip for this Graphics. The clip is the result of combining the user clip
468: with the constrainedRect. */
469:
470: private void setupClip() {
471: if (constrainedRect != null) {
472: if (clip != null) {
473: Rectangle intersection = constrainedRect
474: .intersection(clip);
475: pChangeClipRect(psd, intersection.x, intersection.y,
476: intersection.width, intersection.height);
477: } else {
478: pChangeClipRect(psd, constrainedRect.x,
479: constrainedRect.y, constrainedRect.width,
480: constrainedRect.height);
481: }
482: } else {
483: if (clip != null) {
484: pChangeClipRect(psd, clip.x, clip.y, clip.width,
485: clip.height);
486: } else {
487: pRemoveClip(psd);
488: }
489: }
490: }
491:
492: /** Sets the clipping rectangle for this X11Graphics context. */
493: public void setClip(int x, int y, int w, int h) {
494: clip = new Rectangle(x + originX, y + originY, w, h);
495: setupClip();
496: }
497:
498: /** Sets the clip to a Shape (only Rectangle allowed). */
499:
500: public void setClip(Shape clip) {
501: if (clip == null) {
502: this .clip = null;
503: setupClip();
504: } else if (clip instanceof Rectangle) {
505: Rectangle rect = (Rectangle) clip;
506: setClip(rect.x, rect.y, rect.width, rect.height);
507: } else
508: throw new IllegalArgumentException(
509: "setClip(Shape) only supports Rectangle objects");
510: }
511:
512: /**
513: * Draws an image at x,y in nonblocking mode with a callback object.
514: */
515: public boolean drawImage(Image img, int x, int y,
516: ImageObserver observer) {
517: return drawImage(img, x, y, null, observer);
518: }
519:
520: /**
521: * Draws an image at x,y in nonblocking mode with a solid background
522: * color and a callback object.
523: */
524: public boolean drawImage(Image img, int x, int y, Color bg,
525: ImageObserver observer) {
526: MWImage mwimg;
527: if (img == null)
528: throw new NullPointerException("Image can't be null");
529: if (img instanceof BufferedImage)
530: mwimg = getBufferedImagePeer((BufferedImage) img);
531: else
532: mwimg = (MWImage) img;
533: boolean isComplete = mwimg.isComplete();
534: if (!isComplete) {
535: mwimg.addObserver(observer);
536: mwimg.startProduction();
537: isComplete = mwimg.isComplete();
538: }
539: int width = mwimg.getWidth();
540: int height = mwimg.getHeight();
541: if (width > 0 && height > 0) {
542: mwimg.drawImage(psd, x + originX, y + originY, bg);
543: }
544: return isComplete;
545: }
546:
547: /**
548: * Draws an image scaled to x,y,w,h in nonblocking mode with a
549: * callback object.
550: */
551: public boolean drawImage(Image img, int x, int y, int width,
552: int height, ImageObserver observer) {
553: return drawImage(img, x, y, width, height, null, observer);
554: }
555:
556: /**
557: * Draws an image scaled to x,y,w,h in nonblocking mode with a
558: * solid background color and a callback object.
559: */
560: public boolean drawImage(Image img, int x, int y, int width,
561: int height, Color bg, ImageObserver observer) {
562: MWImage mwimg;
563: if (img == null)
564: throw new NullPointerException("Image can't be null");
565: if (img instanceof BufferedImage)
566: mwimg = getBufferedImagePeer((BufferedImage) img);
567: else
568: mwimg = (MWImage) img;
569: boolean isComplete = mwimg.isComplete();
570: if (!isComplete) {
571: mwimg.addObserver(observer);
572: mwimg.startProduction();
573: isComplete = mwimg.isComplete();
574: }
575: int imgWidth = mwimg.getWidth();
576: int imgHeight = mwimg.getHeight();
577: if (imgWidth > 0 && imgHeight > 0) {
578: x += originX;
579: y += originY;
580: mwimg.drawImage(psd, x, y, x + width - 1, y + height - 1,
581: 0, 0, imgWidth - 1, imgHeight - 1, bg);
582: }
583: return isComplete;
584: }
585:
586: /**
587: * Draws a subrectangle of an image scaled to a destination rectangle
588: * in nonblocking mode with a callback object.
589: */
590: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
591: int dy2, int sx1, int sy1, int sx2, int sy2,
592: ImageObserver observer) {
593: return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2,
594: null, observer);
595: }
596:
597: /**
598: * Draws a subrectangle of an image scaled to a destination rectangle in
599: * nonblocking mode with a solid background color and a callback object.
600: */
601: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
602: int dy2, int sx1, int sy1, int sx2, int sy2, Color bg,
603: ImageObserver observer) {
604: MWImage mwimg;
605: if (img == null)
606: throw new NullPointerException("Image can't be null");
607: if (img instanceof BufferedImage)
608: mwimg = getBufferedImagePeer((BufferedImage) img);
609: else
610: mwimg = (MWImage) img;
611: boolean isComplete = mwimg.isComplete();
612: if (!isComplete) {
613: mwimg.addObserver(observer);
614: mwimg.startProduction();
615: isComplete = mwimg.isComplete();
616: }
617: int imgWidth = mwimg.getWidth();
618: int imgHeight = mwimg.getHeight();
619: if (imgWidth > 0 || imgHeight > 0) {
620: mwimg.drawImage(psd, dx1 + originX, dy1 + originY, dx2
621: + originX, dy2 + originY, sx1, sy1, sx2, sy2, bg);
622: }
623: return isComplete;
624: }
625:
626: public String toString() {
627: return getClass().getName() + "[" + originX + "," + originY
628: + "]";
629: }
630: }
|