1:
37:
38:
39: package ;
40:
41: import ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83: import ;
84: import ;
85: import ;
86: import ;
87: import ;
88: import ;
89: import ;
90: import ;
91: import ;
92: import ;
93: import ;
94: import ;
95: import ;
96: import ;
97: import ;
98: import ;
99: import ;
100:
101:
119: public abstract class CairoGraphics2D extends Graphics2D
120: {
121: static
122: {
123: System.loadLibrary("gtkpeer");
124: }
125:
126:
131: long nativePointer;
132:
133:
134:
137: Paint paint;
138: boolean customPaint;
139:
140:
143: Stroke stroke;
144:
145:
148: Color fg, bg;
149:
150:
153: Shape clip;
154:
155:
158: AffineTransform transform;
159:
160:
163: Font font;
164:
165:
168: Composite comp;
169: CompositeContext compCtx;
170:
171:
174: private RenderingHints hints;
175:
176:
179: private boolean antialias = false;
180: private boolean ignoreAA = false;
181:
182:
187: protected boolean shiftDrawCalls = false;
188:
189:
192: private boolean firstClip = true;
193: private Shape originalClip;
194:
195:
198: private static BasicStroke draw3DRectStroke = new BasicStroke();
199:
200: static ColorModel rgb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF);
201: static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF,
202: 0xFF000000);
203:
204:
208: public static final int INTERPOLATION_NEAREST = 0,
209: INTERPOLATION_BILINEAR = 1,
210: INTERPOLATION_BICUBIC = 5,
211: ALPHA_INTERPOLATION_SPEED = 2,
212: ALPHA_INTERPOLATION_QUALITY = 3,
213: ALPHA_INTERPOLATION_DEFAULT = 4;
214:
215:
216:
219: public CairoGraphics2D()
220: {
221: }
222:
223:
227: public void setup(long cairo_t_pointer)
228: {
229: nativePointer = init(cairo_t_pointer);
230: setRenderingHints(new RenderingHints(getDefaultHints()));
231: setFont(new Font("SansSerif", Font.PLAIN, 12));
232: setColor(Color.black);
233: setBackground(Color.white);
234: setPaint(Color.black);
235: setStroke(new BasicStroke());
236: setTransform(new AffineTransform());
237: cairoSetAntialias(nativePointer, antialias);
238: }
239:
240:
243: public void copy(CairoGraphics2D g, long cairo_t_pointer)
244: {
245: nativePointer = init(cairo_t_pointer);
246: paint = g.paint;
247: stroke = g.stroke;
248: setRenderingHints(g.hints);
249:
250: Color foreground;
251:
252: if (g.fg.getAlpha() != -1)
253: foreground = new Color(g.fg.getRed(), g.fg.getGreen(), g.fg.getBlue(),
254: g.fg.getAlpha());
255: else
256: foreground = new Color(g.fg.getRGB());
257:
258: if (g.bg != null)
259: {
260: if (g.bg.getAlpha() != -1)
261: bg = new Color(g.bg.getRed(), g.bg.getGreen(), g.bg.getBlue(),
262: g.bg.getAlpha());
263: else
264: bg = new Color(g.bg.getRGB());
265: }
266:
267: firstClip = g.firstClip;
268: originalClip = g.originalClip;
269: clip = g.getClip();
270:
271: if (g.transform == null)
272: transform = null;
273: else
274: transform = new AffineTransform(g.transform);
275:
276: setFont(g.font);
277: setColor(foreground);
278: setBackground(bg);
279: setPaint(paint);
280: setStroke(stroke);
281: setTransformImpl(transform);
282: setClip(clip);
283: setComposite(comp);
284:
285: antialias = !g.antialias;
286: setAntialias(g.antialias);
287: }
288:
289:
292: public void finalize()
293: {
294: dispose();
295: }
296:
297:
303: public void dispose()
304: {
305: disposeNative(nativePointer);
306: nativePointer = 0;
307: if (compCtx != null)
308: compCtx.dispose();
309: }
310:
311:
315: protected native long init(long pointer);
316:
317:
320: public abstract Graphics create();
321:
322: public abstract GraphicsConfiguration getDeviceConfiguration();
323:
324: protected abstract void copyAreaImpl(int x, int y, int width, int height,
325: int dx, int dy);
326:
327:
328:
333: protected abstract Rectangle2D getRealBounds();
334:
335:
336:
337:
340: public native void disposeNative(long pointer);
341:
342:
348: protected native void drawPixels(long pointer, int[] pixels, int w, int h,
349: int stride, double[] i2u, double alpha,
350: int interpolation);
351:
352: protected native void setGradient(long pointer, double x1, double y1,
353: double x2, double y2,
354: int r1, int g1, int b1, int a1, int r2,
355: int g2, int b2, int a2, boolean cyclic);
356:
357: protected native void setPaintPixels(long pointer, int[] pixels, int w,
358: int h, int stride, boolean repeat,
359: int x, int y);
360:
361:
364: protected native void cairoSetMatrix(long pointer, double[] m);
365:
366:
369: protected native void cairoScale(long pointer, double x, double y);
370:
371:
374: protected native void cairoSetOperator(long pointer, int cairoOperator);
375:
376:
379: protected native void cairoSetRGBAColor(long pointer, double red, double green,
380: double blue, double alpha);
381:
382:
385: protected native void cairoSetFillRule(long pointer, int cairoFillRule);
386:
387:
391: protected native void cairoSetLine(long pointer, double width, int cap,
392: int join, double miterLimit);
393:
394:
397: protected native void cairoSetDash(long pointer, double[] dashes, int ndash,
398: double offset);
399:
400:
403: protected native void cairoDrawGlyphVector(long pointer, GdkFontPeer font,
404: float x, float y, int n,
405: int[] codes, float[] positions, long[] fontset);
406:
407:
410: protected native void cairoSetFont(long pointer, GdkFontPeer font);
411:
412:
415: protected native void cairoRectangle(long pointer, double x, double y,
416: double width, double height);
417:
418:
421: protected native void cairoArc(long pointer, double x, double y,
422: double radius, double angle1, double angle2);
423:
424:
427: protected native void cairoSave(long pointer);
428: protected native void cairoRestore(long pointer);
429:
430:
433: protected native void cairoNewPath(long pointer);
434:
435:
438: protected native void cairoClosePath(long pointer);
439:
440:
441: protected native void cairoMoveTo(long pointer, double x, double y);
442:
443:
444: protected native void cairoLineTo(long pointer, double x, double y);
445:
446:
447: protected native void cairoCurveTo(long pointer, double x1, double y1,
448: double x2, double y2,
449: double x3, double y3);
450:
451:
454: protected native void cairoStroke(long pointer);
455:
456:
459: protected native void cairoFill(long pointer, double alpha);
460:
461:
464: protected native void cairoClip(long pointer);
465:
466:
469: protected native void cairoResetClip(long pointer);
470:
471:
474: protected native void cairoSetAntialias(long pointer, boolean aa);
475:
476:
477:
478:
481: public void setTransform(AffineTransform tx)
482: {
483:
484: updateClip(transform);
485:
486:
487: setTransformImpl(tx);
488:
489:
490: try
491: {
492: updateClip(transform.createInverse());
493: }
494: catch (NoninvertibleTransformException ex)
495: {
496:
497: ex.printStackTrace();
498: }
499:
500: if (clip != null)
501: setClip(clip);
502: }
503:
504: private void setTransformImpl(AffineTransform tx)
505: {
506: transform = tx;
507: if (transform != null)
508: {
509: double[] m = new double[6];
510: transform.getMatrix(m);
511: cairoSetMatrix(nativePointer, m);
512: }
513: }
514:
515: public void transform(AffineTransform tx)
516: {
517: if (transform == null)
518: transform = new AffineTransform(tx);
519: else
520: transform.concatenate(tx);
521:
522: if (clip != null)
523: {
524: try
525: {
526: AffineTransform clipTransform = tx.createInverse();
527: updateClip(clipTransform);
528: }
529: catch (NoninvertibleTransformException ex)
530: {
531:
532: ex.printStackTrace();
533: }
534: }
535:
536: setTransformImpl(transform);
537: }
538:
539: public void rotate(double theta)
540: {
541: transform(AffineTransform.getRotateInstance(theta));
542: }
543:
544: public void rotate(double theta, double x, double y)
545: {
546: transform(AffineTransform.getRotateInstance(theta, x, y));
547: }
548:
549: public void scale(double sx, double sy)
550: {
551: transform(AffineTransform.getScaleInstance(sx, sy));
552: }
553:
554:
558: public void translate(double tx, double ty)
559: {
560: if (transform != null)
561: transform.translate(tx, ty);
562: else
563: transform = AffineTransform.getTranslateInstance(tx, ty);
564:
565: if (clip != null)
566: {
567:
568:
569: if (clip instanceof Rectangle2D)
570: {
571: Rectangle2D r = (Rectangle2D) clip;
572: r.setRect(r.getX() - tx, r.getY() - ty, r.getWidth(),
573: r.getHeight());
574: }
575: else
576: {
577: AffineTransform clipTransform =
578: AffineTransform.getTranslateInstance(-tx, -ty);
579: updateClip(clipTransform);
580: }
581: }
582:
583: setTransformImpl(transform);
584: }
585:
586: public void translate(int x, int y)
587: {
588: translate((double) x, (double) y);
589: }
590:
591: public void shear(double shearX, double shearY)
592: {
593: transform(AffineTransform.getShearInstance(shearX, shearY));
594: }
595:
596:
597:
598: public void clip(Shape s)
599: {
600:
601: if (s == null)
602: {
603:
604:
605:
606:
607: setClip(null);
608: return;
609: }
610:
611:
612: if (clip == null)
613: {
614: clip = getRealBounds();
615: }
616:
617:
618: if (clip instanceof Rectangle2D && s instanceof Rectangle2D)
619: {
620: Rectangle2D clipRect = (Rectangle2D) clip;
621: Rectangle2D r = (Rectangle2D) s;
622: Rectangle2D.intersect(clipRect, r, clipRect);
623: setClip(clipRect);
624: }
625: else
626: {
627: Area current;
628: if (clip instanceof Area)
629: current = (Area) clip;
630: else
631: current = new Area(clip);
632:
633: Area intersect;
634: if (s instanceof Area)
635: intersect = (Area) s;
636: else
637: intersect = new Area(s);
638:
639: current.intersect(intersect);
640: clip = current;
641:
642: setClip(clip);
643: }
644: }
645:
646: public Paint getPaint()
647: {
648: return paint;
649: }
650:
651: public AffineTransform getTransform()
652: {
653: return (AffineTransform) transform.clone();
654: }
655:
656: public void setPaint(Paint p)
657: {
658: if (p == null)
659: return;
660:
661: paint = p;
662: if (paint instanceof Color)
663: {
664: setColor((Color) paint);
665: customPaint = false;
666: }
667:
668: else if (paint instanceof TexturePaint)
669: {
670: TexturePaint tp = (TexturePaint) paint;
671: BufferedImage img = tp.getImage();
672:
673:
674: int width = (int) tp.getAnchorRect().getWidth();
675: int height = (int) tp.getAnchorRect().getHeight();
676:
677: double scaleX = width / (double) img.getWidth();
678: double scaleY = height / (double) img.getHeight();
679:
680: AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0);
681: AffineTransformOp op = new AffineTransformOp(at, getRenderingHints());
682: BufferedImage texture = op.filter(img, null);
683: int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width);
684: setPaintPixels(nativePointer, pixels, width, height, width, true, 0, 0);
685: customPaint = false;
686: }
687:
688: else if (paint instanceof GradientPaint)
689: {
690: GradientPaint gp = (GradientPaint) paint;
691: Point2D p1 = gp.getPoint1();
692: Point2D p2 = gp.getPoint2();
693: Color c1 = gp.getColor1();
694: Color c2 = gp.getColor2();
695: setGradient(nativePointer, p1.getX(), p1.getY(), p2.getX(), p2.getY(),
696: c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha(),
697: c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha(),
698: gp.isCyclic());
699: customPaint = false;
700: }
701: else
702: {
703: customPaint = true;
704: }
705: }
706:
707:
712: protected void setCustomPaint(Rectangle bounds)
713: {
714: if (paint instanceof Color || paint instanceof TexturePaint
715: || paint instanceof GradientPaint)
716: return;
717:
718: int userX = bounds.x;
719: int userY = bounds.y;
720: int userWidth = bounds.width;
721: int userHeight = bounds.height;
722:
723:
724: Rectangle2D bounds2D = getTransformedBounds(bounds, transform);
725: int deviceX = (int)bounds2D.getX();
726: int deviceY = (int)bounds2D.getY();
727: int deviceWidth = (int)Math.ceil(bounds2D.getWidth());
728: int deviceHeight = (int)Math.ceil(bounds2D.getHeight());
729:
730:
731: PaintContext pc = paint.createContext(CairoSurface.cairoColorModel,
732: new Rectangle(deviceX, deviceY,
733: deviceWidth,
734: deviceHeight),
735: bounds,
736: transform, hints);
737:
738: Raster raster = pc.getRaster(deviceX, deviceY, deviceWidth,
739: deviceHeight);
740:
741:
742:
743: AffineTransform oldTx = new AffineTransform(transform);
744: setTransformImpl(new AffineTransform());
745:
746:
747:
748: if (pc.getColorModel().equals(CairoSurface.cairoColorModel)
749: && raster.getSampleModel().getTransferType() == DataBuffer.TYPE_INT)
750: {
751:
752:
753: setPaintPixels(nativePointer,
754: (int[])raster.getDataElements(0, 0, deviceWidth,
755: deviceHeight, null),
756: deviceWidth, deviceHeight, deviceWidth, false,
757: deviceX, deviceY);
758: }
759:
760: else if (pc.getColorModel().equals(CairoSurface.cairoCM_opaque)
761: && raster.getSampleModel().getTransferType() == DataBuffer.TYPE_INT)
762: {
763:
764:
765: int[] pixels = (int[])raster.getDataElements(0, 0, deviceWidth,
766: deviceHeight, null);
767:
768: for (int i = 0; i < pixels.length; i++)
769: pixels[i] = 0xff000000 | (pixels[i] & 0x00ffffff);
770:
771: setPaintPixels(nativePointer, pixels, deviceWidth, deviceHeight,
772: deviceWidth, false, deviceX, deviceY);
773: }
774:
775: else
776: {
777:
778:
779: WritableRaster wr = Raster.createWritableRaster(raster.getSampleModel(),
780: new Point(raster.getMinX(),
781: raster.getMinY()));
782: wr.setRect(raster);
783:
784: BufferedImage img2 = new BufferedImage(pc.getColorModel(), wr,
785: pc.getColorModel().isAlphaPremultiplied(),
786: null);
787:
788: setPaintPixels(nativePointer,
789: img2.getRGB(0, 0, deviceWidth, deviceHeight, null, 0,
790: deviceWidth),
791: deviceWidth, deviceHeight, deviceWidth, false,
792: deviceX, deviceY);
793: }
794:
795:
796: setTransformImpl(oldTx);
797: }
798:
799: public Stroke getStroke()
800: {
801: return stroke;
802: }
803:
804: public void setStroke(Stroke st)
805: {
806: stroke = st;
807: if (stroke instanceof BasicStroke)
808: {
809: BasicStroke bs = (BasicStroke) stroke;
810: cairoSetLine(nativePointer, bs.getLineWidth(), bs.getEndCap(),
811: bs.getLineJoin(), bs.getMiterLimit());
812:
813: float[] dashes = bs.getDashArray();
814: if (dashes != null)
815: {
816: double[] double_dashes = new double[dashes.length];
817: for (int i = 0; i < dashes.length; i++)
818: double_dashes[i] = dashes[i];
819:
820: cairoSetDash(nativePointer, double_dashes, double_dashes.length,
821: (double) bs.getDashPhase());
822: }
823: else
824: cairoSetDash(nativePointer, new double[0], 0, 0.0);
825: }
826: }
827:
828:
834: protected Rectangle findStrokedBounds(Shape s)
835: {
836: Rectangle r = s.getBounds();
837:
838: if (stroke instanceof BasicStroke)
839: {
840: int strokeWidth = (int)Math.ceil(((BasicStroke)stroke).getLineWidth());
841: r.x -= strokeWidth / 2;
842: r.y -= strokeWidth / 2;
843: r.height += strokeWidth;
844: r.width += strokeWidth;
845: }
846: else
847: {
848: Shape s2 = stroke.createStrokedShape(s);
849: r = s2.getBounds();
850: }
851:
852: return r;
853: }
854:
855: public void setPaintMode()
856: {
857: setComposite(AlphaComposite.SrcOver);
858: }
859:
860: public void setXORMode(Color c)
861: {
862:
863: }
864:
865: public void setColor(Color c)
866: {
867: if (c == null)
868: c = Color.BLACK;
869:
870: fg = c;
871: paint = c;
872: updateColor();
873: }
874:
875:
878: void updateColor()
879: {
880: if (fg == null)
881: fg = Color.BLACK;
882:
883: cairoSetRGBAColor(nativePointer, fg.getRed() / 255.0,
884: fg.getGreen() / 255.0,fg.getBlue() / 255.0,
885: fg.getAlpha() / 255.0);
886: }
887:
888: public Color getColor()
889: {
890: return fg;
891: }
892:
893: public void clipRect(int x, int y, int width, int height)
894: {
895: if (clip == null)
896: setClip(new Rectangle(x, y, width, height));
897: else if (clip instanceof Rectangle)
898: {
899: computeIntersection(x, y, width, height, (Rectangle) clip);
900: setClip(clip);
901: }
902: else
903: clip(new Rectangle(x, y, width, height));
904: }
905:
906: public Shape getClip()
907: {
908: if (clip == null)
909: return null;
910: else if (clip instanceof Rectangle2D)
911: return clip.getBounds2D();
912: else
913: {
914: GeneralPath p = new GeneralPath();
915: PathIterator pi = clip.getPathIterator(null);
916: p.append(pi, false);
917: return p;
918: }
919: }
920:
921: public Rectangle getClipBounds()
922: {
923: if (clip == null)
924: return null;
925: else
926: return clip.getBounds();
927: }
928:
929: protected Rectangle2D getClipInDevSpace()
930: {
931: Rectangle2D uclip = clip.getBounds2D();
932: if (transform == null)
933: return uclip;
934: else
935: return getTransformedBounds(clip.getBounds2D(), transform);
936: }
937:
938: public void setClip(int x, int y, int width, int height)
939: {
940: if( width < 0 || height < 0 )
941: return;
942:
943: setClip(new Rectangle2D.Double(x, y, width, height));
944: }
945:
946: public void setClip(Shape s)
947: {
948:
949:
950:
951:
952: if( firstClip )
953: {
954: originalClip = s;
955: firstClip = false;
956: }
957:
958: clip = s;
959: cairoResetClip(nativePointer);
960:
961: if (clip != null)
962: {
963: cairoNewPath(nativePointer);
964: if (clip instanceof Rectangle2D)
965: {
966: Rectangle2D r = (Rectangle2D) clip;
967: cairoRectangle(nativePointer, r.getX(), r.getY(), r.getWidth(),
968: r.getHeight());
969: }
970: else
971: walkPath(clip.getPathIterator(null), false);
972:
973: cairoClip(nativePointer);
974: }
975: }
976:
977: public void setBackground(Color c)
978: {
979: if (c == null)
980: c = Color.WHITE;
981: bg = c;
982: }
983:
984: public Color getBackground()
985: {
986: return bg;
987: }
988:
989:
992: public Composite getComposite()
993: {
994: if (comp == null)
995: return AlphaComposite.SrcOver;
996: else
997: return comp;
998: }
999:
1000:
1003: public void setComposite(Composite comp)
1004: {
1005: if (this.comp == comp)
1006: return;
1007:
1008: this.comp = comp;
1009: if (compCtx != null)
1010: compCtx.dispose();
1011: compCtx = null;
1012:
1013: if (comp instanceof AlphaComposite)
1014: {
1015: AlphaComposite a = (AlphaComposite) comp;
1016: cairoSetOperator(nativePointer, a.getRule());
1017: }
1018:
1019: else
1020: {
1021: cairoSetOperator(nativePointer, AlphaComposite.SRC_OVER);
1022:
1023: if (comp != null)
1024: {
1025:
1026:
1027: SecurityManager sm = System.getSecurityManager();
1028: if (sm != null)
1029: sm.checkPermission(new AWTPermission("readDisplayPixels"));
1030:
1031: compCtx = comp.createContext(getBufferCM(), getNativeCM(), hints);
1032: }
1033: }
1034: }
1035:
1036:
1042: protected abstract ColorModel getNativeCM();
1043:
1044:
1050: protected ColorModel getBufferCM()
1051: {
1052:
1053: return getNativeCM();
1054: }
1055:
1056:
1057:
1058: public void draw(Shape s)
1059: {
1060: if ((stroke != null && ! (stroke instanceof BasicStroke))
1061: || (comp instanceof AlphaComposite && ((AlphaComposite) comp).getAlpha() != 1.0))
1062: {
1063:
1064:
1065: fill(stroke.createStrokedShape(s));
1066: return;
1067: }
1068:
1069: if (customPaint)
1070: {
1071: Rectangle r = findStrokedBounds(s);
1072: setCustomPaint(r);
1073: }
1074:
1075: setAntialias(!hints.get(RenderingHints.KEY_ANTIALIASING)
1076: .equals(RenderingHints.VALUE_ANTIALIAS_OFF));
1077: createPath(s, true);
1078: cairoStroke(nativePointer);
1079: }
1080:
1081: public void fill(Shape s)
1082: {
1083: createPath(s, false);
1084:
1085: if (customPaint)
1086: setCustomPaint(s.getBounds());
1087:
1088: setAntialias(!hints.get(RenderingHints.KEY_ANTIALIASING)
1089: .equals(RenderingHints.VALUE_ANTIALIAS_OFF));
1090: double alpha = 1.0;
1091: if (comp instanceof AlphaComposite)
1092: alpha = ((AlphaComposite) comp).getAlpha();
1093: cairoFill(nativePointer, alpha);
1094: }
1095:
1096: private void createPath(Shape s, boolean isDraw)
1097: {
1098: cairoNewPath(nativePointer);
1099:
1100:
1101: if (s instanceof Rectangle2D)
1102: {
1103: Rectangle2D r = (Rectangle2D) s;
1104:
1105:
1106:
1107:
1108: double x = shiftX(r.getX(),shiftDrawCalls && isDraw);
1109: double y = shiftY(r.getY(), shiftDrawCalls && isDraw);
1110: double w = Math.round(r.getWidth());
1111: double h = Math.round(r.getHeight());
1112: cairoRectangle(nativePointer, x, y, w, h);
1113: }
1114:
1115:
1116: else if (s instanceof Line2D)
1117: {
1118: Line2D l = (Line2D) s;
1119: cairoMoveTo(nativePointer, shiftX(l.getX1(), shiftDrawCalls && isDraw),
1120: shiftY(l.getY1(), shiftDrawCalls && isDraw));
1121: cairoLineTo(nativePointer, shiftX(l.getX2(), shiftDrawCalls && isDraw),
1122: shiftY(l.getY2(), shiftDrawCalls && isDraw));
1123: }
1124:
1125:
1126:
1127:
1128: else if (s instanceof Ellipse2D)
1129: {
1130: Ellipse2D e = (Ellipse2D) s;
1131:
1132: double radius = Math.min(e.getHeight(), e.getWidth()) / 2;
1133:
1134:
1135:
1136: double xscale = 1, yscale = 1;
1137: if (e.getHeight() != e.getWidth())
1138: {
1139: cairoSave(nativePointer);
1140:
1141: if (e.getHeight() < e.getWidth())
1142: xscale = e.getWidth() / (radius * 2);
1143: else
1144: yscale = e.getHeight() / (radius * 2);
1145:
1146: if (xscale != 1 || yscale != 1)
1147: cairoScale(nativePointer, xscale, yscale);
1148: }
1149:
1150: cairoArc(nativePointer,
1151: shiftX(e.getCenterX() / xscale, shiftDrawCalls && isDraw),
1152: shiftY(e.getCenterY() / yscale, shiftDrawCalls && isDraw),
1153: radius, 0, Math.PI * 2);
1154:
1155: if (xscale != 1 || yscale != 1)
1156: cairoRestore(nativePointer);
1157: }
1158:
1159:
1160:
1161: else
1162: walkPath(s.getPathIterator(null), shiftDrawCalls && isDraw);
1163: }
1164:
1165:
1170:
1171: public void clearRect(int x, int y, int width, int height)
1172: {
1173: if (bg != null)
1174: cairoSetRGBAColor(nativePointer, bg.getRed() / 255.0,
1175: bg.getGreen() / 255.0, bg.getBlue() / 255.0,
1176: bg.getAlpha() / 255.0);
1177:
1178: Composite oldcomp = comp;
1179: setComposite(AlphaComposite.Src);
1180: fillRect(x, y, width, height);
1181:
1182: setComposite(oldcomp);
1183: updateColor();
1184: }
1185:
1186: public void draw3DRect(int x, int y, int width, int height, boolean raised)
1187: {
1188: Stroke tmp = stroke;
1189: setStroke(draw3DRectStroke);
1190: super.draw3DRect(x, y, width, height, raised);
1191: setStroke(tmp);
1192: }
1193:
1194: public void drawArc(int x, int y, int width, int height, int startAngle,
1195: int arcAngle)
1196: {
1197: draw(new Arc2D.Double((double) x, (double) y, (double) width,
1198: (double) height, (double) startAngle,
1199: (double) arcAngle, Arc2D.OPEN));
1200: }
1201:
1202: public void drawLine(int x1, int y1, int x2, int y2)
1203: {
1204:
1205:
1206:
1207: if (x1 == x2 && y1 == y2)
1208: fill(new Rectangle(x1, y1, 1, 1));
1209: else
1210: draw(new Line2D.Double(x1, y1, x2, y2));
1211: }
1212:
1213: public void drawRect(int x, int y, int width, int height)
1214: {
1215: draw(new Rectangle(x, y, width, height));
1216: }
1217:
1218: public void fillArc(int x, int y, int width, int height, int startAngle,
1219: int arcAngle)
1220: {
1221: fill(new Arc2D.Double((double) x, (double) y, (double) width,
1222: (double) height, (double) startAngle,
1223: (double) arcAngle, Arc2D.PIE));
1224: }
1225:
1226: public void fillRect(int x, int y, int width, int height)
1227: {
1228: fill (new Rectangle(x, y, width, height));
1229: }
1230:
1231: public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
1232: {
1233: fill(new Polygon(xPoints, yPoints, nPoints));
1234: }
1235:
1236: public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
1237: {
1238: draw(new Polygon(xPoints, yPoints, nPoints));
1239: }
1240:
1241: public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
1242: {
1243: draw(new Polygon(xPoints, yPoints, nPoints));
1244: }
1245:
1246: public void drawOval(int x, int y, int width, int height)
1247: {
1248: drawArc(x, y, width, height, 0, 360);
1249: }
1250:
1251: public void drawRoundRect(int x, int y, int width, int height, int arcWidth,
1252: int arcHeight)
1253: {
1254: draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
1255: }
1256:
1257: public void fillOval(int x, int y, int width, int height)
1258: {
1259: fillArc(x, y, width, height, 0, 360);
1260: }
1261:
1262: public void fillRoundRect(int x, int y, int width, int height, int arcWidth,
1263: int arcHeight)
1264: {
1265: fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
1266: }
1267:
1268:
1272: public void copyArea(int ox, int oy, int owidth, int oheight,
1273: int odx, int ody)
1274: {
1275:
1276:
1277: Point2D pos = transform.transform(new Point2D.Double(ox, oy),
1278: (Point2D) null);
1279: Point2D dim = transform.transform(new Point2D.Double(ox + owidth,
1280: oy + oheight),
1281: (Point2D) null);
1282: Point2D p2 = transform.transform(new Point2D.Double(ox + odx, oy + ody),
1283: (Point2D) null);
1284: int x = (int)pos.getX();
1285: int y = (int)pos.getY();
1286: int width = (int)(dim.getX() - pos.getX());
1287: int height = (int)(dim.getY() - pos.getY());
1288: int dx = (int)(p2.getX() - pos.getX());
1289: int dy = (int)(p2.getY() - pos.getY());
1290:
1291: Rectangle2D r = getRealBounds();
1292:
1293: if( width <= 0 || height <= 0 )
1294: return;
1295:
1296: if( x + dx > r.getWidth() || y + dy > r.getHeight() )
1297: return;
1298:
1299: if( x + dx + width < r.getX() || y + dy + height < r.getY() )
1300: return;
1301:
1302:
1303: if( x + dx < r.getX() )
1304: {
1305: width = x + dx + width;
1306: x = (int)r.getX() - dx;
1307: }
1308:
1309: if( y + dy < r.getY() )
1310: {
1311: height = y + dy + height;
1312: y = (int)r.getY() - dy;
1313: }
1314:
1315: if( x + dx + width >= r.getWidth() )
1316: width = (int)r.getWidth() - dx - x;
1317:
1318: if( y + dy + height >= r.getHeight() )
1319: height = (int)r.getHeight() - dy - y;
1320:
1321: copyAreaImpl(x, y, width, height, dx, dy);
1322: }
1323:
1324:
1325:
1326: public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
1327: {
1328: hints.put(hintKey, hintValue);
1329:
1330: shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
1331: || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
1332: }
1333:
1334: public Object getRenderingHint(RenderingHints.Key hintKey)
1335: {
1336: return hints.get(hintKey);
1337: }
1338:
1339: public void setRenderingHints(Map<?,?> hints)
1340: {
1341: this.hints = new RenderingHints(getDefaultHints());
1342: this.hints.putAll(hints);
1343:
1344: shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
1345: || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
1346:
1347: if (compCtx != null)
1348: {
1349: compCtx.dispose();
1350: compCtx = comp.createContext(getNativeCM(), getNativeCM(), this.hints);
1351: }
1352: }
1353:
1354: public void addRenderingHints(Map hints)
1355: {
1356: this.hints.putAll(hints);
1357: }
1358:
1359: public RenderingHints getRenderingHints()
1360: {
1361: return hints;
1362: }
1363:
1364: private int getInterpolation()
1365: {
1366: if (this.hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
1367: return INTERPOLATION_NEAREST;
1368:
1369: else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
1370: return INTERPOLATION_BILINEAR;
1371:
1372: else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BICUBIC))
1373: return INTERPOLATION_BICUBIC;
1374:
1375: else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
1376: return ALPHA_INTERPOLATION_SPEED;
1377:
1378: else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
1379: return ALPHA_INTERPOLATION_QUALITY;
1380:
1381: else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
1382: return ALPHA_INTERPOLATION_DEFAULT;
1383:
1384:
1385: return INTERPOLATION_BILINEAR;
1386: }
1387:
1388:
1394: private void setAntialias(boolean needAA)
1395: {
1396: if (ignoreAA)
1397: return;
1398:
1399: if (needAA != antialias)
1400: {
1401: antialias = !antialias;
1402: cairoSetAntialias(nativePointer, antialias);
1403: }
1404: }
1405:
1406:
1407:
1408: protected boolean drawImage(Image img, AffineTransform xform,
1409: Color bgcolor, ImageObserver obs)
1410: {
1411: if (img == null)
1412: return false;
1413:
1414: if (xform == null)
1415: xform = new AffineTransform();
1416:
1417:
1418:
1419:
1420:
1421:
1422:
1423:
1424: AffineTransform invertedXform;
1425:
1426: try
1427: {
1428: invertedXform = xform.createInverse();
1429: }
1430: catch (NoninvertibleTransformException e)
1431: {
1432: throw new ImagingOpException("Unable to invert transform "
1433: + xform.toString());
1434: }
1435:
1436:
1437:
1438:
1439:
1440: img = AsyncImage.realImage(img, obs);
1441: if( !(img instanceof BufferedImage) )
1442: {
1443: ImageProducer source = img.getSource();
1444: if (source == null)
1445: return false;
1446: img = Toolkit.getDefaultToolkit().createImage(source);
1447: }
1448:
1449: BufferedImage b = (BufferedImage) img;
1450: Raster raster;
1451: double[] i2u = new double[6];
1452: int width = b.getWidth();
1453: int height = b.getHeight();
1454:
1455:
1456:
1457:
1458: if( BufferedImageGraphics.bufferedImages.get( b ) != null )
1459: raster = BufferedImageGraphics.bufferedImages.get( b );
1460: else
1461: raster = b.getRaster();
1462:
1463: invertedXform.getMatrix(i2u);
1464:
1465: double alpha = 1.0;
1466: if (comp instanceof AlphaComposite)
1467: alpha = ((AlphaComposite) comp).getAlpha();
1468:
1469: if(raster instanceof CairoSurface
1470: && ((CairoSurface)raster).sharedBuffer == true)
1471: {
1472: drawCairoSurface((CairoSurface)raster, xform, alpha, getInterpolation());
1473: updateColor();
1474: return true;
1475: }
1476:
1477: if( bgcolor != null )
1478: {
1479: Color oldColor = bg;
1480: setBackground(bgcolor);
1481:
1482: Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height);
1483: bounds = getTransformedBounds(bounds, xform);
1484:
1485: clearRect((int)bounds.getX(), (int)bounds.getY(),
1486: (int)bounds.getWidth(), (int)bounds.getHeight());
1487:
1488: setBackground(oldColor);
1489: }
1490:
1491: int[] pixels = b.getRGB(0, 0, width, height, null, 0, width);
1492:
1493:
1494:
1495:
1496: cairoSave(nativePointer);
1497: Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height);
1498: bounds = getTransformedBounds(bounds, xform);
1499: cairoRectangle(nativePointer, bounds.getX(), bounds.getY(),
1500: bounds.getWidth(), bounds.getHeight());
1501: cairoClip(nativePointer);
1502:
1503: drawPixels(nativePointer, pixels, width, height, width, i2u, alpha,
1504: getInterpolation());
1505:
1506: cairoRestore(nativePointer);
1507:
1508:
1509: updateColor();
1510: return true;
1511: }
1512:
1513: public void drawRenderedImage(RenderedImage image, AffineTransform xform)
1514: {
1515: drawRaster(image.getColorModel(), image.getData(), xform, null);
1516: }
1517:
1518: public void drawRenderableImage(RenderableImage image, AffineTransform xform)
1519: {
1520: drawRenderedImage(image.createRendering(new RenderContext(xform)), xform);
1521: }
1522:
1523: public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs)
1524: {
1525: return drawImage(img, xform, null, obs);
1526: }
1527:
1528: public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y)
1529: {
1530: Image filtered = image;
1531: if (op != null)
1532: filtered = op.filter(image, null);
1533: drawImage(filtered, new AffineTransform(1f, 0f, 0f, 1f, x, y), null, null);
1534: }
1535:
1536: public boolean drawImage(Image img, int x, int y, ImageObserver observer)
1537: {
1538: return drawImage(img, new AffineTransform(1f, 0f, 0f, 1f, x, y), null,
1539: observer);
1540: }
1541:
1542: public boolean drawImage(Image img, int x, int y, Color bgcolor,
1543: ImageObserver observer)
1544: {
1545: return drawImage(img, x, y, img.getWidth(observer),
1546: img.getHeight(observer), bgcolor, observer);
1547: }
1548:
1549: public boolean drawImage(Image img, int x, int y, int width, int height,
1550: Color bgcolor, ImageObserver observer)
1551: {
1552: double scaleX = width / (double) img.getWidth(observer);
1553: double scaleY = height / (double) img.getHeight(observer);
1554: if( scaleX == 0 || scaleY == 0 )
1555: return true;
1556:
1557: return drawImage(img, new AffineTransform(scaleX, 0f, 0f, scaleY, x, y),
1558: bgcolor, observer);
1559: }
1560:
1561: public boolean drawImage(Image img, int x, int y, int width, int height,
1562: ImageObserver observer)
1563: {
1564: return drawImage(img, x, y, width, height, null, observer);
1565: }
1566:
1567: public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1568: int sx1, int sy1, int sx2, int sy2, Color bgcolor,
1569: ImageObserver observer)
1570: {
1571: if (img == null)
1572: return false;
1573:
1574: int sourceWidth = sx2 - sx1;
1575: int sourceHeight = sy2 - sy1;
1576:
1577: int destWidth = dx2 - dx1;
1578: int destHeight = dy2 - dy1;
1579:
1580: if(destWidth == 0 || destHeight == 0 || sourceWidth == 0 ||
1581: sourceHeight == 0)
1582: return true;
1583:
1584: double scaleX = destWidth / (double) sourceWidth;
1585: double scaleY = destHeight / (double) sourceHeight;
1586:
1587:
1588:
1589: Shape oldClip = getClip();
1590: int cx, cy, cw, ch;
1591: if( dx1 < dx2 )
1592: { cx = dx1; cw = dx2 - dx1; }
1593: else
1594: { cx = dx2; cw = dx1 - dx2; }
1595: if( dy1 < dy2 )
1596: { cy = dy1; ch = dy2 - dy1; }
1597: else
1598: { cy = dy2; ch = dy1 - dy2; }
1599:
1600: clipRect( cx, cy, cw, ch );
1601:
1602: AffineTransform tx = new AffineTransform();
1603: tx.translate( dx1 - sx1*scaleX, dy1 - sy1*scaleY );
1604: tx.scale( scaleX, scaleY );
1605:
1606: boolean retval = drawImage(img, tx, bgcolor, observer);
1607: setClip( oldClip );
1608: return retval;
1609: }
1610:
1611: public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1612: int sx1, int sy1, int sx2, int sy2,
1613: ImageObserver observer)
1614: {
1615: return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer);
1616: }
1617:
1618:
1626: protected void drawCairoSurface(CairoSurface surface, AffineTransform tx,
1627: double alpha, int interpolation)
1628: {
1629:
1630:
1631: if (surface.getSampleModelTranslateX() != 0
1632: || surface.getSampleModelTranslateY() != 0)
1633: {
1634: Point2D origin = new Point2D.Double(0, 0);
1635: Point2D offset = new Point2D.Double(surface.getSampleModelTranslateX(),
1636: surface.getSampleModelTranslateY());
1637:
1638: tx.transform(origin, origin);
1639: tx.transform(offset, offset);
1640:
1641: tx.translate(offset.getX() - origin.getX(),
1642: offset.getY() - origin.getY());
1643: }
1644:
1645:
1646: Rectangle bounds = new Rectangle(-surface.getSampleModelTranslateX(),
1647: -surface.getSampleModelTranslateY(),
1648: surface.width, surface.height);
1649:
1650:
1651:
1652:
1653:
1654: Shape newBounds = tx.createTransformedShape(bounds);
1655: cairoSave(nativePointer);
1656: walkPath(newBounds.getPathIterator(null), false);
1657: cairoClip(nativePointer);
1658:
1659:
1660: try
1661: {
1662: double[] i2u = new double[6];
1663: tx.createInverse().getMatrix(i2u);
1664: surface.nativeDrawSurface(surface.surfacePointer, nativePointer, i2u,
1665: alpha, interpolation);
1666: }
1667: catch (NoninvertibleTransformException ex)
1668: {
1669:
1670: ;
1671: }
1672:
1673:
1674: cairoRestore(nativePointer);
1675: }
1676:
1677:
1678:
1679:
1680: public void drawString(String str, float x, float y)
1681: {
1682: if (str == null || str.length() == 0)
1683: return;
1684: GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer();
1685: TextLayout tl = (TextLayout) fontPeer.textLayoutCache.get(str);
1686: if (tl == null)
1687: {
1688: tl = new TextLayout( str, getFont(), getFontRenderContext() );
1689: fontPeer.textLayoutCache.put(str, tl);
1690: }
1691:
1692:
1693:
1694: setAntialias(!hints.get(RenderingHints.KEY_TEXT_ANTIALIASING)
1695: .equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF));
1696: ignoreAA = true;
1697:
1698: tl.draw(this, x, y);
1699: ignoreAA = false;
1700: }
1701:
1702: public void drawString(String str, int x, int y)
1703: {
1704: drawString (str, (float) x, (float) y);
1705: }
1706:
1707: public void drawString(AttributedCharacterIterator ci, int x, int y)
1708: {
1709: drawString (ci, (float) x, (float) y);
1710: }
1711:
1712: public void drawGlyphVector(GlyphVector gv, float x, float y)
1713: {
1714: double alpha = 1.0;
1715:
1716: if( gv.getNumGlyphs() <= 0 )
1717: return;
1718:
1719: if (customPaint)
1720: setCustomPaint(gv.getOutline().getBounds());
1721:
1722: if (comp instanceof AlphaComposite)
1723: alpha = ((AlphaComposite) comp).getAlpha();
1724:
1725: setAntialias(!hints.get(RenderingHints.KEY_TEXT_ANTIALIASING)
1726: .equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF));
1727: ignoreAA = true;
1728:
1729: if (gv instanceof FreetypeGlyphVector && alpha == 1.0
1730: && !((FreetypeGlyphVector)gv).hasTransforms())
1731: {
1732: int n = gv.getNumGlyphs ();
1733: int[] codes = gv.getGlyphCodes (0, n, null);
1734: long[] fontset = ((FreetypeGlyphVector)gv).getGlyphFonts (0, n, null);
1735: float[] positions = gv.getGlyphPositions (0, n, null);
1736:
1737: setFont (gv.getFont ());
1738: GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer();
1739: synchronized (fontPeer)
1740: {
1741: cairoDrawGlyphVector(nativePointer, fontPeer,
1742: x, y, n, codes, positions, fontset);
1743: }
1744: }
1745: else
1746: {
1747: translate(x, y);
1748: fill(gv.getOutline());
1749: translate(-x, -y);
1750: }
1751:
1752: ignoreAA = false;
1753: }
1754:
1755: public void drawString(AttributedCharacterIterator ci, float x, float y)
1756: {
1757: GlyphVector gv = getFont().createGlyphVector(getFontRenderContext(), ci);
1758: drawGlyphVector(gv, x, y);
1759: }
1760:
1761:
1765: public FontRenderContext getFontRenderContext()
1766: {
1767: return new FontRenderContext(transform, true, true);
1768: }
1769:
1770:
1771:
1772:
1773:
1774: public FontMetrics getFontMetrics()
1775: {
1776: return getFontMetrics(getFont());
1777: }
1778:
1779: public FontMetrics getFontMetrics(Font f)
1780: {
1781: return ((GdkFontPeer) f.getPeer()).getFontMetrics(f);
1782: }
1783:
1784: public void setFont(Font f)
1785: {
1786:
1787:
1788: if (f == null)
1789: return;
1790:
1791: if (f.getPeer() instanceof GdkFontPeer)
1792: font = f;
1793: else
1794: font =
1795: ((ClasspathToolkit)(Toolkit.getDefaultToolkit()))
1796: .getFont(f.getName(), f.getAttributes());
1797:
1798: GdkFontPeer fontpeer = (GdkFontPeer) getFont().getPeer();
1799: synchronized (fontpeer)
1800: {
1801: cairoSetFont(nativePointer, fontpeer);
1802: }
1803: }
1804:
1805: public Font getFont()
1806: {
1807: if (font == null)
1808: return new Font("SansSerif", Font.PLAIN, 12);
1809: return font;
1810: }
1811:
1812:
1813:
1814: public boolean hit(Rectangle rect, Shape s, boolean onStroke)
1815: {
1816: if( onStroke )
1817: {
1818: Shape stroked = stroke.createStrokedShape( s );
1819: return stroked.intersects( (double)rect.x, (double)rect.y,
1820: (double)rect.width, (double)rect.height );
1821: }
1822: return s.intersects( (double)rect.x, (double)rect.y,
1823: (double)rect.width, (double)rect.height );
1824: }
1825:
1826: public String toString()
1827: {
1828: return (getClass().getName()
1829: + "[font=" + getFont().toString()
1830: + ",color=" + fg.toString()
1831: + "]");
1832: }
1833:
1834:
1835:
1836:
1843: private boolean drawRaster(ColorModel cm, Raster r,
1844: AffineTransform imageToUser, Color bgcolor)
1845: {
1846: if (r == null)
1847: return false;
1848:
1849: SampleModel sm = r.getSampleModel();
1850: DataBuffer db = r.getDataBuffer();
1851:
1852: if (db == null || sm == null)
1853: return false;
1854:
1855: if (cm == null)
1856: cm = ColorModel.getRGBdefault();
1857:
1858: double[] i2u = new double[6];
1859: if (imageToUser != null)
1860: imageToUser.getMatrix(i2u);
1861: else
1862: {
1863: i2u[0] = 1;
1864: i2u[1] = 0;
1865: i2u[2] = 0;
1866: i2u[3] = 1;
1867: i2u[4] = 0;
1868: i2u[5] = 0;
1869: }
1870:
1871: int[] pixels = findSimpleIntegerArray(cm, r);
1872:
1873: if (pixels == null)
1874: {
1875:
1876:
1877:
1878:
1879: if (sm instanceof MultiPixelPackedSampleModel)
1880: {
1881: pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels);
1882: for (int i = 0; i < pixels.length; i++)
1883: pixels[i] = cm.getRGB(pixels[i]);
1884: }
1885: else
1886: {
1887: pixels = new int[r.getWidth() * r.getHeight()];
1888: for (int i = 0; i < pixels.length; i++)
1889: pixels[i] = cm.getRGB(db.getElem(i));
1890: }
1891: }
1892:
1893:
1894:
1895:
1896: if (cm.hasAlpha())
1897: {
1898: if (bgcolor != null && cm.hasAlpha())
1899: for (int i = 0; i < pixels.length; i++)
1900: {
1901: if (cm.getAlpha(pixels[i]) == 0)
1902: pixels[i] = bgcolor.getRGB();
1903: }
1904: }
1905: else
1906: for (int i = 0; i < pixels.length; i++)
1907: pixels[i] |= 0xFF000000;
1908:
1909: double alpha = 1.0;
1910: if (comp instanceof AlphaComposite)
1911: alpha = ((AlphaComposite) comp).getAlpha();
1912:
1913: drawPixels(nativePointer, pixels, r.getWidth(), r.getHeight(),
1914: r.getWidth(), i2u, alpha, getInterpolation());
1915:
1916:
1917: updateColor();
1918:
1919: return true;
1920: }
1921:
1922:
1925: private double shiftX(double coord, boolean doShift)
1926: {
1927: if (doShift)
1928: {
1929: double shift = 0.5;
1930: if (!transform.isIdentity())
1931: shift /= transform.getScaleX();
1932: return (coord + shift);
1933: }
1934: else
1935: return coord;
1936: }
1937:
1938:
1941: private double shiftY(double coord, boolean doShift)
1942: {
1943: if (doShift)
1944: {
1945: double shift = 0.5;
1946: if (!transform.isIdentity())
1947: shift /= transform.getScaleY();
1948: return (coord + shift);
1949: }
1950: else
1951: return coord;
1952: }
1953:
1954:
1957: private void walkPath(PathIterator p, boolean doShift)
1958: {
1959: double x = 0;
1960: double y = 0;
1961: double[] coords = new double[6];
1962:
1963: cairoSetFillRule(nativePointer, p.getWindingRule());
1964: for (; ! p.isDone(); p.next())
1965: {
1966: int seg = p.currentSegment(coords);
1967: switch (seg)
1968: {
1969: case PathIterator.SEG_MOVETO:
1970: x = shiftX(coords[0], doShift);
1971: y = shiftY(coords[1], doShift);
1972: cairoMoveTo(nativePointer, x, y);
1973: break;
1974: case PathIterator.SEG_LINETO:
1975: x = shiftX(coords[0], doShift);
1976: y = shiftY(coords[1], doShift);
1977: cairoLineTo(nativePointer, x, y);
1978: break;
1979: case PathIterator.SEG_QUADTO:
1980:
1981:
1982: double x1 = x + (2.0 / 3.0) * (shiftX(coords[0], doShift) - x);
1983: double y1 = y + (2.0 / 3.0) * (shiftY(coords[1], doShift) - y);
1984:
1985: double x2 = x1 + (1.0 / 3.0) * (shiftX(coords[2], doShift) - x);
1986: double y2 = y1 + (1.0 / 3.0) * (shiftY(coords[3], doShift) - y);
1987:
1988: x = shiftX(coords[2], doShift);
1989: y = shiftY(coords[3], doShift);
1990: cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y);
1991: break;
1992: case PathIterator.SEG_CUBICTO:
1993: x = shiftX(coords[4], doShift);
1994: y = shiftY(coords[5], doShift);
1995: cairoCurveTo(nativePointer, shiftX(coords[0], doShift),
1996: shiftY(coords[1], doShift),
1997: shiftX(coords[2], doShift),
1998: shiftY(coords[3], doShift), x, y);
1999: break;
2000: case PathIterator.SEG_CLOSE:
2001: cairoClosePath(nativePointer);
2002: break;
2003: }
2004: }
2005: }
2006:
2007:
2010: private Map<RenderingHints.Key, Object> getDefaultHints()
2011: {
2012: HashMap<RenderingHints.Key, Object> defaultHints =
2013: new HashMap<RenderingHints.Key, Object>();
2014:
2015: defaultHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
2016: RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
2017:
2018: defaultHints.put(RenderingHints.KEY_STROKE_CONTROL,
2019: RenderingHints.VALUE_STROKE_DEFAULT);
2020:
2021: defaultHints.put(RenderingHints.KEY_FRACTIONALMETRICS,
2022: RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
2023:
2024: defaultHints.put(RenderingHints.KEY_ANTIALIASING,
2025: RenderingHints.VALUE_ANTIALIAS_OFF);
2026:
2027: defaultHints.put(RenderingHints.KEY_RENDERING,
2028: RenderingHints.VALUE_RENDER_DEFAULT);
2029:
2030: return defaultHints;
2031: }
2032:
2033:
2036: public static int[] findSimpleIntegerArray (ColorModel cm, Raster raster)
2037: {
2038: if (cm == null || raster == null)
2039: return null;
2040:
2041: if (! cm.getColorSpace().isCS_sRGB())
2042: return null;
2043:
2044: if (! (cm instanceof DirectColorModel))
2045: return null;
2046:
2047: DirectColorModel dcm = (DirectColorModel) cm;
2048:
2049: if (dcm.getRedMask() != 0x00FF0000 || dcm.getGreenMask() != 0x0000FF00
2050: || dcm.getBlueMask() != 0x000000FF)
2051: return null;
2052:
2053: if (! (raster instanceof WritableRaster))
2054: return null;
2055:
2056: if (raster.getSampleModel().getDataType() != DataBuffer.TYPE_INT)
2057: return null;
2058:
2059: if (! (raster.getDataBuffer() instanceof DataBufferInt))
2060: return null;
2061:
2062: DataBufferInt db = (DataBufferInt) raster.getDataBuffer();
2063:
2064: if (db.getNumBanks() != 1)
2065: return null;
2066:
2067:
2068:
2069:
2070:
2071:
2072: return db.getData();
2073: }
2074:
2075:
2085: private void updateClip(AffineTransform t)
2086: {
2087: if (clip == null)
2088: return;
2089:
2090:
2091:
2092: double[] matrix = new double[4];
2093: t.getMatrix(matrix);
2094: if (clip instanceof Rectangle2D && matrix[1] == 0 && matrix[2] == 0)
2095: {
2096: Rectangle2D rect = (Rectangle2D)clip;
2097: double[] origin = new double[] {rect.getX(), rect.getY()};
2098: double[] dimensions = new double[] {rect.getWidth(), rect.getHeight()};
2099: t.transform(origin, 0, origin, 0, 1);
2100: t.deltaTransform(dimensions, 0, dimensions, 0, 1);
2101: rect.setRect(origin[0], origin[1], dimensions[0], dimensions[1]);
2102: }
2103: else
2104: {
2105: if (! (clip instanceof GeneralPath))
2106: clip = new GeneralPath(clip);
2107:
2108: GeneralPath p = (GeneralPath) clip;
2109: p.transform(t);
2110: }
2111: }
2112:
2113: private static Rectangle computeIntersection(int x, int y, int w, int h,
2114: Rectangle rect)
2115: {
2116: int x2 = (int) rect.x;
2117: int y2 = (int) rect.y;
2118: int w2 = (int) rect.width;
2119: int h2 = (int) rect.height;
2120:
2121: int dx = (x > x2) ? x : x2;
2122: int dy = (y > y2) ? y : y2;
2123: int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx);
2124: int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy);
2125:
2126: if (dw >= 0 && dh >= 0)
2127: rect.setBounds(dx, dy, dw, dh);
2128: else
2129: rect.setBounds(0, 0, 0, 0);
2130:
2131: return rect;
2132: }
2133:
2134: static Rectangle2D getTransformedBounds(Rectangle2D bounds, AffineTransform tx)
2135: {
2136: double x1 = bounds.getX();
2137: double x2 = bounds.getX() + bounds.getWidth();
2138: double x3 = x1;
2139: double x4 = x2;
2140: double y1 = bounds.getY();
2141: double y2 = y1;
2142: double y3 = bounds.getY() + bounds.getHeight();
2143: double y4 = y3;
2144:
2145: double[] points = new double[] {x1, y1, x2, y2, x3, y3, x4, y4};
2146: tx.transform(points, 0, points, 0, 4);
2147:
2148: double minX = points[0];
2149: double maxX = minX;
2150: double minY = points[1];
2151: double maxY = minY;
2152: for (int i = 0; i < 8; i++)
2153: {
2154: if (points[i] < minX)
2155: minX = points[i];
2156: if (points[i] > maxX)
2157: maxX = points[i];
2158: i++;
2159:
2160: if (points[i] < minY)
2161: minY = points[i];
2162: if (points[i] > maxY)
2163: maxY = points[i];
2164: }
2165:
2166: return new Rectangle2D.Double(minX, minY, (maxX - minX), (maxY - minY));
2167: }