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