001: /*
002: * @(#)GdkGraphics.java 1.36 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:
028: package sun.awt.gtk;
029:
030: import java.awt.*;
031: /**
032: * GdkGraphics.java
033: *
034: * @author Nicholas Allen
035: */
036:
037: import java.awt.*;
038: import java.io.*;
039: import java.util.*;
040: import sun.awt.peer.FontPeer;
041: import java.awt.image.ImageObserver;
042: import java.awt.image.BufferedImage;
043: import sun.awt.image.OffScreenImageSource;
044: import sun.awt.image.ImageRepresentation;
045: import sun.awt.AWTFinalizer;
046: import sun.awt.AWTFinalizeable;
047: import sun.awt.ConstrainableGraphics;
048: import sun.awt.FontDescriptor;
049: import sun.awt.PlatformFont;
050: import sun.awt.CharsetString;
051: import java.io.CharConversionException;
052: import sun.io.CharToByteConverter;
053:
054: /**
055: * GdkGraphics is an object that encapsulates a graphics context for a
056: * particular drawing area using the Gdk library.
057: *
058: */
059:
060: class GdkGraphics extends Graphics2D implements ConstrainableGraphics {
061: private static native void initIDs();
062:
063: static {
064: initIDs();
065: }
066: int data;
067: /** The peer that created this graphics. This is needed by clearRect which needs to clear
068: he background with the background color of the heavyweight component that created it. */
069:
070: GComponentPeer peer;
071: Color foreground;
072: Font font;
073: int originX; // TODO: change to float
074: int originY; // TODO: change to float
075: private AlphaComposite composite;
076: /** GTK+ does not support alpha. So alpha is approximated.
077: * The approximation is: if alpha is 0.0 then the colour is transparent,
078: * else the colour is opaque. This flag indicates whether the extra alpha in
079: * the AlphaComposite is not 0.0. The source colour alpha is premultiplied by the
080: * extra alpha, hence an extra alpha of 0.0 will create transparent pixels.
081: */
082: private static final int DRAW_NONE = 0x00;
083: private static final int DRAW_PRIMATIVE = 0x01;
084: private static final int DRAW_BITMAP = 0x02;
085: private static final int DRAW_NORMAL = DRAW_PRIMATIVE | DRAW_BITMAP;
086: private static final int DRAW_CLEAR = 0x04 | DRAW_PRIMATIVE;
087: private int drawType = DRAW_NORMAL;
088: /** The current user clip rectangle or null if no clip has been set. This is stored in the
089: native coordinate system and not the possibly translated Java coordinate system. */
090:
091: private Rectangle clip;
092: /** The rectangle this graphics object has been constrained too. This is stored in the
093: native coordinate system and not the (possibly) translated Java coordinate system.
094: If it is null then this graphics has not been constrained. The constrained rectangle
095: is another layer of clipping independant of the user clip. The actaul clip used is the
096: intersection */
097:
098: private Rectangle constrainedRect;
099: /** The GraphicsConfiguration that this graphics uses. */
100: private GraphicsConfiguration graphicsConfiguration;
101:
102: private static native Graphics createFromComponentNative(
103: GComponentPeer peer);
104:
105: static Graphics createFromComponent(GComponentPeer peer) {
106: Graphics g = createFromComponentNative(peer);
107: g.setFont(peer.target.getFont());
108: if (g instanceof GdkGraphics)
109: ((GdkGraphics) g).setupApproximatedAlpha();
110: return g;
111: }
112:
113: private native void createFromGraphics(GdkGraphics g);
114:
115: private native void createFromImage(ImageRepresentation imageRep);
116:
117: private native void setForegroundNative(Color c);
118:
119: sun.awt.image.Image image;
120:
121: private GdkGraphics(GComponentPeer peer) {
122: this .peer = peer;
123: composite = AlphaComposite.SrcOver;
124: foreground = peer.target.getForeground();
125: if (foreground == null)
126: foreground = SystemColor.windowText;
127: GraphicsEnvironment ge = GraphicsEnvironment
128: .getLocalGraphicsEnvironment();
129: graphicsConfiguration = ge.getDefaultScreenDevice()
130: .getDefaultConfiguration();
131: }
132:
133: private GdkGraphics(GdkGraphics g) {
134: createFromGraphics(g);
135: graphicsConfiguration = g.graphicsConfiguration;
136: peer = g.peer;
137: originX = g.originX;
138: originY = g.originY;
139: clip = g.clip;
140: image = g.image;
141: composite = g.composite;
142: foreground = g.foreground;
143: setFont(g.font);
144: setupApproximatedAlpha();
145: }
146:
147: public GdkGraphics(GdkImage image) {
148: createFromImage(image.getImageRep());
149: composite = AlphaComposite.SrcOver;
150: foreground = Color.white;
151: graphicsConfiguration = image.gc;
152: this .image = image;
153: setupApproximatedAlpha();
154: }
155:
156: /**
157: * Create a new GdkGraphics Object based on this one.
158: */
159: public Graphics create() {
160: return new GdkGraphics(this );
161: }
162:
163: /**
164: * Translate
165: */
166: public void translate(int x, int y) {
167: originX += x;
168: originY += y;
169: }
170:
171: public final native void dispose();
172:
173: //AWTFinalizeable finalnext;
174:
175: public void finalize() {
176: /*if (data != 0) {
177: AWTFinalizer.addFinalizeable(this);
178: }*/
179: dispose();
180: }
181:
182: /*public void doFinalization() {
183: dispose();
184: }
185:
186: public void setNextFinalizeable(AWTFinalizeable o) {
187: finalnext = o;
188: }
189:
190: public AWTFinalizeable getNextFinalizeable() {
191: return finalnext;
192: }*/
193:
194: public void setFont(Font font) {
195: if ((font != null) && (this .font != font)) {
196: this .font = font;
197: }
198: }
199:
200: public Font getFont() {
201: return font;
202: }
203:
204: /**
205: * Gets font metrics for the given font.
206: */
207: public FontMetrics getFontMetrics(Font font) {
208: return (FontMetrics) GFontPeer.getFontPeer(font);
209: }
210:
211: /**
212: * Sets the foreground color.
213: */
214: public void setColor(Color c) {
215: if ((c != null) && (c != foreground)) {
216: if (c instanceof SystemColor) {
217: c = new Color(c.getRGB());
218: }
219: foreground = c;
220: setupApproximatedAlpha();
221: }
222: }
223:
224: public Color getColor() {
225: return foreground;
226: }
227:
228: public Composite getComposite() {
229: return composite;
230: }
231:
232: public void setComposite(Composite comp) {
233: if ((comp != null) && (comp != composite)) {
234: if (!(comp instanceof AlphaComposite))
235: throw new IllegalArgumentException(
236: "Only AlphaComposite is supported");
237: composite = (AlphaComposite) comp;
238: setupApproximatedAlpha();
239: }
240: }
241:
242: private void setupApproximatedAlpha() {
243: int rule = composite.getRule();
244: if (rule == AlphaComposite.CLEAR) {
245: setForegroundNative(Color.black);
246: drawType = DRAW_CLEAR;
247: } else if (rule == AlphaComposite.SRC_OVER) {
248: if (composite.getAlpha() == 0)
249: drawType = DRAW_NONE;
250: else if (foreground.getAlpha() == 0)
251: drawType = DRAW_BITMAP;
252: else {
253: drawType = DRAW_NORMAL;
254: setForegroundNative(foreground);
255: }
256: } else {
257: drawType = DRAW_NORMAL;
258: setForegroundNative(foreground);
259: }
260: }
261:
262: public GraphicsConfiguration getDeviceConfiguration() {
263: return graphicsConfiguration;
264: }
265:
266: /**
267: * Sets the paint mode to overwrite the destination with the
268: * current color. This is the default paint mode.
269: */
270: public native void setPaintMode();
271:
272: /**
273: * Sets the paint mode to alternate between the current color
274: * and the given color.
275: */
276: public native void setXORMode(Color c1);
277:
278: /**
279: * Gets the current clipping area
280: */
281: public Rectangle getClipBounds() {
282: if (clip != null)
283: return new Rectangle(clip.x - originX, clip.y - originY,
284: clip.width, clip.height);
285: return null;
286: }
287:
288: /** Returns a Shape object representing the MicroWindows clip. */
289:
290: public Shape getClip() {
291: return getClipBounds();
292: }
293:
294: public void constrain(int x, int y, int w, int h) {
295: originX += x;
296: originY += y;
297: Rectangle rect = new Rectangle(originX, originY, w, h);
298: if (constrainedRect != null)
299: constrainedRect = constrainedRect.intersection(rect);
300: else
301: constrainedRect = rect;
302: setupClip();
303: }
304:
305: private native void setClipNative(int X, int Y, int W, int H);
306:
307: private native void removeClip();
308:
309: public void clipRect(int x, int y, int w, int h) {
310: Rectangle rect = new Rectangle(x + originX, y + originY, w, h);
311: if (clip != null)
312: clip = clip.intersection(rect);
313: else
314: clip = rect;
315: setupClip();
316: }
317:
318: /** Sets up the clip for this Graphics. The clip is the result of combining the user clip
319: with the constrainedRect. */
320:
321: private void setupClip() {
322: if (constrainedRect != null) {
323: if (clip != null) {
324: Rectangle intersection = constrainedRect
325: .intersection(clip);
326: setClipNative(intersection.x, intersection.y,
327: intersection.width, intersection.height);
328: } else {
329: setClipNative(constrainedRect.x, constrainedRect.y,
330: constrainedRect.width, constrainedRect.height);
331: }
332: } else {
333: if (clip != null) {
334: setClipNative(clip.x, clip.y, clip.width, clip.height);
335: } else {
336: removeClip();
337: }
338: }
339: }
340:
341: /** Sets the clipping rectangle for this X11Graphics context. */
342: public void setClip(int x, int y, int w, int h) {
343: clip = new Rectangle(x + originX, y + originY, w, h);
344: setupClip();
345: }
346:
347: /** Sets the clip to a Shape (only Rectangle allowed). */
348:
349: public void setClip(Shape clip) {
350: if (clip == null) {
351: this .clip = null;
352: setupClip();
353: } else if (clip instanceof Rectangle) {
354: Rectangle rect = (Rectangle) clip;
355: setClip(rect.x, rect.y, rect.width, rect.height);
356: } else
357: throw new IllegalArgumentException(
358: "setClip(Shape) only supports Rectangle objects");
359: }
360:
361: /** Clears the rectangle indicated by x,y,w,h. */
362: public native void clearRect(int x, int y, int w, int h);
363:
364: /** Fills the given rectangle with the foreground color. */
365: public void fillRect(int X, int Y, int W, int H) {
366: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
367: drawRectNative(true, X, Y, W, H);
368: }
369:
370: /** Draws the given rectangle. */
371: public void drawRect(int X, int Y, int W, int H) {
372: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
373: drawRectNative(false, X, Y, W, H);
374: }
375:
376: private native void drawRectNative(boolean fill, int X, int Y,
377: int W, int H);
378:
379: /** Draws the given string. */
380: public void drawString(String string, int x, int y) {
381: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE) {
382: GFontPeer p = GFontPeer.getFontPeer(font);
383: CharsetString[] cs = p.gpf.makeMultiCharsetString(string);
384:
385: for (int i = 0; i < cs.length; i++) {
386: byte[] s = new byte[cs[i].length * 3];
387: int len;
388:
389: try {
390: len = cs[i].fontDescriptor.fontCharset.convertAny(
391: cs[i].charsetChars, cs[i].offset,
392: cs[i].length, s, 0, s.length);
393: } catch (Exception e) {
394: /* FIXME ... */
395: continue;
396: }
397:
398: int gdkfont = p.gpf.getGdkFont(cs[i].fontDescriptor);
399:
400: // drawStringNative(string.getBytes(), x, y);
401: drawStringNative(s, len, gdkfont, x, y);
402: x += p.stringWidthNative(s, len, gdkfont);
403: }
404:
405: }
406: }
407:
408: private native void drawStringNative(byte[] string, int len,
409: int gdkfont, int x, int y);
410:
411: /** Draws the given character array. */
412: public void drawChars(char chars[], int offset, int length, int x,
413: int y) {
414: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
415: drawString(new String(chars, offset, length), x, y);
416: }
417:
418: /** Draws the given byte array. */
419: public void drawBytes(byte data[], int offset, int length, int x,
420: int y) {
421: if (drawType == DRAW_NONE)
422: return;
423:
424: /* FIXME
425: byte[] string = new byte[length];
426: System.arraycopy(data, offset, string, 0, length);
427: drawStringNative(GFontPeer.getFontPeer(font), string, x, y);
428: */
429: }
430:
431: private native void drawLineNative(int x1, int y1, int x2, int y2);
432:
433: /** Draws the given line. */
434: public void drawLine(int x1, int y1, int x2, int y2) {
435: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
436: drawLineNative(x1, y1, x2, y2);
437: }
438:
439: /**
440: * Draws an image at x,y in nonblocking mode with a callback object.
441: */
442: public boolean drawImage(Image img, int x, int y,
443: ImageObserver observer) {
444: GdkDrawableImage gdkimage;
445: if (img instanceof BufferedImage)
446: gdkimage = (GdkDrawableImage) GToolkit
447: .getBufferedImagePeer((BufferedImage) img);
448: else
449: gdkimage = (GdkDrawableImage) img;
450: switch (drawType) {
451: case DRAW_BITMAP:
452: case DRAW_NORMAL:
453: return gdkimage.draw(this , x, y, observer);
454:
455: case DRAW_CLEAR:
456: drawRectNative(true, x, y, gdkimage.getWidth(), gdkimage
457: .getHeight());
458:
459: case DRAW_NONE:
460: default:
461: return gdkimage.isComplete();
462: }
463: }
464:
465: /**
466: * Draws an image scaled to x,y,w,h in nonblocking mode with a
467: * callback object.
468: */
469: public boolean drawImage(Image img, int x, int y, int width,
470: int height, ImageObserver observer) {
471: GdkDrawableImage gdkimage;
472: if (img instanceof BufferedImage)
473: gdkimage = (GdkDrawableImage) GToolkit
474: .getBufferedImagePeer((BufferedImage) img);
475: else
476: gdkimage = (GdkDrawableImage) img;
477: switch (drawType) {
478: case DRAW_BITMAP:
479: case DRAW_NORMAL:
480: return gdkimage.draw(this , x, y, width, height, observer);
481:
482: case DRAW_CLEAR:
483: drawRectNative(true, x, y, width, height);
484:
485: case DRAW_NONE:
486: default:
487: return gdkimage.isComplete();
488: }
489: }
490:
491: /**
492: * Draws an image at x,y in nonblocking mode with a solid background
493: * color and a callback object.
494: */
495: public boolean drawImage(Image img, int x, int y, Color bg,
496: ImageObserver observer) {
497: GdkDrawableImage gdkimage;
498: if (img instanceof BufferedImage)
499: gdkimage = (GdkDrawableImage) GToolkit
500: .getBufferedImagePeer((BufferedImage) img);
501: else
502: gdkimage = (GdkDrawableImage) img;
503: switch (drawType) {
504: case DRAW_BITMAP:
505: case DRAW_NORMAL:
506: return gdkimage.draw(this , x, y, bg, observer);
507:
508: case DRAW_CLEAR:
509: drawRectNative(true, x, y, gdkimage.getWidth(), gdkimage
510: .getHeight());
511:
512: case DRAW_NONE:
513: default:
514: return gdkimage.isComplete();
515: }
516: }
517:
518: /**
519: * Draws an image scaled to x,y,w,h in nonblocking mode with a
520: * solid background color and a callback object.
521: */
522: public boolean drawImage(Image img, int x, int y, int width,
523: int height, Color bg, ImageObserver observer) {
524: GdkDrawableImage gdkimage;
525: if (img instanceof BufferedImage)
526: gdkimage = (GdkDrawableImage) GToolkit
527: .getBufferedImagePeer((BufferedImage) img);
528: else
529: gdkimage = (GdkDrawableImage) img;
530: switch (drawType) {
531: case DRAW_BITMAP:
532: case DRAW_NORMAL:
533: return gdkimage.draw(this , x, y, width, height, bg,
534: observer);
535:
536: case DRAW_CLEAR:
537: drawRectNative(true, x, y, width, height);
538:
539: case DRAW_NONE:
540: default:
541: return gdkimage.isComplete();
542: }
543: }
544:
545: /**
546: * Draws a subrectangle of an image scaled to a destination rectangle
547: * in nonblocking mode with a callback object.
548: */
549: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
550: int dy2, int sx1, int sy1, int sx2, int sy2,
551: ImageObserver observer) {
552: GdkDrawableImage gdkimage;
553: if (img instanceof BufferedImage)
554: gdkimage = (GdkDrawableImage) GToolkit
555: .getBufferedImagePeer((BufferedImage) img);
556: else
557: gdkimage = (GdkDrawableImage) img;
558: switch (drawType) {
559: case DRAW_BITMAP:
560: case DRAW_NORMAL:
561: return gdkimage.draw(this , dx1, dy1, dx2, dy2, sx1, sy1,
562: sx2, sy2, observer);
563:
564: case DRAW_CLEAR: {
565: int w = dx2 - dx1;
566: int h = dy2 - dy1;
567: int x = dx1, y = dy1;
568: if (w < 0) {
569: x = dx2;
570: w *= -1;
571: }
572: if (h < 0) {
573: y = dy2;
574: h *= -1;
575: }
576: drawRectNative(true, x, y, w, h);
577: }
578:
579: case DRAW_NONE:
580: default:
581: return gdkimage.isComplete();
582: }
583: }
584:
585: /**
586: * Draws a subrectangle of an image scaled to a destination rectangle in
587: * nonblocking mode with a solid background color and a callback object.
588: */
589: public boolean drawImage(Image img, int dx1, int dy1, int dx2,
590: int dy2, int sx1, int sy1, int sx2, int sy2, Color bgcolor,
591: ImageObserver observer) {
592: GdkDrawableImage gdkimage;
593: if (img instanceof BufferedImage)
594: gdkimage = (GdkDrawableImage) GToolkit
595: .getBufferedImagePeer((BufferedImage) img);
596: else
597: gdkimage = (GdkDrawableImage) img;
598: switch (drawType) {
599: case DRAW_BITMAP:
600: case DRAW_NORMAL:
601: return gdkimage.draw(this , dx1, dy1, dx2, dy2, sx1, sy1,
602: sx2, sy2, bgcolor, observer);
603:
604: case DRAW_CLEAR: {
605: int w = dx2 - dx1;
606: int h = dy2 - dy1;
607: int x = dx1, y = dy1;
608: if (w < 0) {
609: x = dx2;
610: w *= -1;
611: }
612: if (h < 0) {
613: y = dy2;
614: h *= -1;
615: }
616: drawRectNative(true, x, y, w, h);
617: }
618:
619: case DRAW_NONE:
620: default:
621: return gdkimage.isComplete();
622: }
623: }
624:
625: /**
626: * Copies an area of the canvas that this graphics context paints to.
627: * @param X the x-coordinate of the source.
628: * @param Y the y-coordinate of the source.
629: * @param W the width.
630: * @param H the height.
631: * @param dx the x-coordinate of the destination.
632: * @param dy the y-coordinate of the destination.
633: */
634: public native void copyArea(int X, int Y, int W, int H, int dx,
635: int dy);
636:
637: private native void drawRoundRectNative(int x, int y, int w, int h,
638: int arcWidth, int arcHeight);
639:
640: private native void fillRoundRectNative(int x, int y, int w, int h,
641: int arcWidth, int arcHeight);
642:
643: /** Draws a rounded rectangle. */
644: public void drawRoundRect(int x, int y, int w, int h, int arcWidth,
645: int arcHeight) {
646: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
647: drawRoundRectNative(x, y, w, h, arcWidth, arcHeight);
648: }
649:
650: /** Draws a filled rounded rectangle. */
651: public void fillRoundRect(int x, int y, int w, int h, int arcWidth,
652: int arcHeight) {
653: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
654: fillRoundRectNative(x, y, w, h, arcWidth, arcHeight);
655: }
656:
657: /** Draws a bunch of lines defined by an array of x points and y points */
658: private native void drawPolygonNative(boolean filled,
659: int xPoints[], int yPoints[], int nPoints, boolean close);
660:
661: /** Draws a bunch of lines defined by an array of x points and y points */
662: public void drawPolyline(int xPoints[], int yPoints[], int nPoints) {
663: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
664: drawPolygonNative(false, xPoints, yPoints, nPoints, false);
665: }
666:
667: /** Draws a polygon defined by an array of x points and y points */
668: public void drawPolygon(int xPoints[], int yPoints[], int nPoints) {
669: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
670: drawPolygonNative(false, xPoints, yPoints, nPoints, true);
671: }
672:
673: /** Fills a polygon with the current fill mask */
674: public void fillPolygon(int xPoints[], int yPoints[], int nPoints) {
675: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
676: drawPolygonNative(true, xPoints, yPoints, nPoints, false);
677: }
678:
679: /** Draws an oval to fit in the given rectangle */
680: public void drawOval(int x, int y, int w, int h) {
681: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
682: drawArc(x, y, w, h, 0, 360);
683: }
684:
685: /** Fills an oval to fit in the given rectangle */
686: public void fillOval(int x, int y, int w, int h) {
687: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
688: fillArc(x, y, w, h, 0, 360);
689: }
690:
691: /**
692: * Draws an arc bounded by the given rectangle from startAngle to
693: * endAngle. 0 degrees is a vertical line straight up from the
694: * center of the rectangle. Positive angles indicate clockwise
695: * rotations, negative angle are counter-clockwise.
696: */
697: public void drawArc(int x, int y, int w, int h, int startAngle,
698: int endAngle) {
699: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
700: drawArcNative(x, y, w, h, startAngle, endAngle);
701: }
702:
703: /** fills an arc. arguments are the same as drawArc. */
704: public void fillArc(int x, int y, int w, int h, int startAngle,
705: int endAngle) {
706: if ((drawType & DRAW_PRIMATIVE) == DRAW_PRIMATIVE)
707: fillArcNative(x, y, w, h, startAngle, endAngle);
708: }
709:
710: private native void drawArcNative(int x, int y, int w, int h,
711: int startAngle, int endAngle);
712:
713: private native void fillArcNative(int x, int y, int w, int h,
714: int startAngle, int endAngle);
715:
716: public String toString() {
717: return getClass().getName() + "[" + originX + "," + originY
718: + "]";
719: }
720:
721: /* Outline the given region. */
722: //public native void drawRegion(Region r);
723: /* Fill the given region. */
724: //public native void fillRegion(Region r);
725:
726: public void setStroke(Stroke stroke) {
727: }
728:
729: public Stroke getStroke() {
730: return null;
731: }
732:
733: }
|