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:
97:
115: public abstract class CairoGraphics2D extends Graphics2D
116: {
117: static
118: {
119: System.loadLibrary("gtkpeer");
120: }
121:
122:
127: long nativePointer;
128:
129:
130:
133: Paint paint;
134:
135:
138: Stroke stroke;
139:
140:
143: Color fg, bg;
144:
145:
148: Shape clip;
149:
150:
153: AffineTransform transform;
154:
155:
158: Font font;
159:
160:
163: Composite comp;
164:
165:
168: private RenderingHints hints;
169:
170:
175: private boolean shiftDrawCalls = false;
176:
177:
180: private boolean firstClip = true;
181: private Shape originalClip;
182:
183:
186: private static BasicStroke draw3DRectStroke = new BasicStroke();
187:
188: static ColorModel rgb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF);
189: static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF,
190: 0xFF000000);
191:
192:
195: public CairoGraphics2D()
196: {
197: }
198:
199:
203: public void setup(long cairo_t_pointer)
204: {
205: nativePointer = init(cairo_t_pointer);
206: setRenderingHints(new RenderingHints(getDefaultHints()));
207: font = new Font("SansSerif", Font.PLAIN, 12);
208: setColor(Color.black);
209: setBackground(Color.white);
210: setPaint(Color.black);
211: setStroke(new BasicStroke());
212: setTransform(new AffineTransform());
213: }
214:
215:
218: public void copy(CairoGraphics2D g, long cairo_t_pointer)
219: {
220: nativePointer = init(cairo_t_pointer);
221: paint = g.paint;
222: stroke = g.stroke;
223: setRenderingHints(g.hints);
224:
225: Color foreground;
226:
227: if (g.fg.getAlpha() != -1)
228: foreground = new Color(g.fg.getRed(), g.fg.getGreen(), g.fg.getBlue(),
229: g.fg.getAlpha());
230: else
231: foreground = new Color(g.fg.getRGB());
232:
233: if (g.bg != null)
234: {
235: if (g.bg.getAlpha() != -1)
236: bg = new Color(g.bg.getRed(), g.bg.getGreen(), g.bg.getBlue(),
237: g.bg.getAlpha());
238: else
239: bg = new Color(g.bg.getRGB());
240: }
241:
242: clip = g.getClip();
243:
244: if (g.transform == null)
245: transform = null;
246: else
247: transform = new AffineTransform(g.transform);
248:
249: font = g.font;
250:
251: setColor(foreground);
252: setBackground(bg);
253: setPaint(paint);
254: setStroke(stroke);
255: setTransformImpl(transform);
256: setClip(clip);
257: }
258:
259:
262: public void finalize()
263: {
264: dispose();
265: }
266:
267:
273: public void dispose()
274: {
275: disposeNative(nativePointer);
276: nativePointer = 0;
277: }
278:
279:
283: private native long init(long pointer);
284:
285:
288: public abstract Graphics create();
289:
290: public abstract GraphicsConfiguration getDeviceConfiguration();
291:
292: protected abstract void copyAreaImpl(int x, int y,
293: int width, int height, int dx, int dy);
294:
295:
296: protected abstract Rectangle2D getRealBounds();
297:
298:
299:
300:
303: public native void disposeNative(long pointer);
304:
305:
311: private native void drawPixels(long pointer, int[] pixels, int w, int h,
312: int stride, double[] i2u, double alpha);
313:
314: private native void setGradient(long pointer, double x1, double y1,
315: double x2, double y2,
316: int r1, int g1, int b1, int a1, int r2,
317: int g2, int b2, int a2, boolean cyclic);
318:
319: private native void setTexturePixels(long pointer, int[] pixels, int w,
320: int h, int stride);
321:
322:
325: private native void cairoSetMatrix(long pointer, double[] m);
326:
327:
330: private native void cairoScale(long pointer, double x, double y);
331:
332:
335: private native void cairoSetOperator(long pointer, int cairoOperator);
336:
337:
340: private native void cairoSetRGBAColor(long pointer, double red, double green,
341: double blue, double alpha);
342:
343:
346: private native void cairoSetFillRule(long pointer, int cairoFillRule);
347:
348:
352: private native void cairoSetLine(long pointer, double width, int cap,
353: int join, double miterLimit);
354:
355:
358: private native void cairoSetDash(long pointer, double[] dashes, int ndash,
359: double offset);
360:
361:
364: native void cairoDrawGlyphVector(long pointer, GdkFontPeer font,
365: float x, float y, int n,
366: int[] codes, float[] positions);
367:
368:
369: private native void cairoRelCurveTo(long pointer, double dx1, double dy1,
370: double dx2, double dy2, double dx3,
371: double dy3);
372:
373:
376: private native void cairoRectangle(long pointer, double x, double y,
377: double width, double height);
378:
379:
382: private native void cairoArc(long pointer, double x, double y,
383: double radius, double angle1, double angle2);
384:
385:
388: private native void cairoSave(long pointer);
389: private native void cairoRestore(long pointer);
390:
391:
394: private native void cairoNewPath(long pointer);
395:
396:
399: private native void cairoClosePath(long pointer);
400:
401:
402: private native void cairoMoveTo(long pointer, double x, double y);
403:
404:
405: private native void cairoRelMoveTo(long pointer, double dx, double dy);
406:
407:
408: private native void cairoLineTo(long pointer, double x, double y);
409:
410:
411: private native void cairoRelLineTo(long pointer, double dx, double dy);
412:
413:
414: private native void cairoCurveTo(long pointer, double x1, double y1,
415: double x2, double y2,
416: double x3, double y3);
417:
418:
421: private native void cairoStroke(long pointer);
422:
423:
426: private native void cairoFill(long pointer, double alpha);
427:
428:
431: private native void cairoClip(long pointer);
432:
433:
436: private native void cairoPreserveClip(long pointer);
437:
438:
441: private native void cairoResetClip(long pointer);
442:
443:
446: private native void cairoSurfaceSetFilter(long pointer, int filter);
447:
448:
458: private native void cairoDrawLine(long pointer, double x1, double y1,
459: double x2, double y2);
460:
461:
471: private native void cairoDrawRect(long pointer, double x, double y, double w,
472: double h);
473:
474:
484: private native void cairoFillRect(long pointer, double x, double y, double w,
485: double h);
486:
487:
488:
489:
492: public void setTransform(AffineTransform tx)
493: {
494:
495: updateClip(transform);
496:
497:
498: setTransformImpl(tx);
499:
500:
501: try
502: {
503: updateClip(transform.createInverse());
504: }
505: catch (NoninvertibleTransformException ex)
506: {
507:
508: ex.printStackTrace();
509: }
510:
511: if (clip != null)
512: setClip(clip);
513: }
514:
515: private void setTransformImpl(AffineTransform tx)
516: {
517: transform = tx;
518: if (transform != null)
519: {
520: double[] m = new double[6];
521: transform.getMatrix(m);
522: cairoSetMatrix(nativePointer, m);
523: }
524: }
525:
526: public void transform(AffineTransform tx)
527: {
528: if (transform == null)
529: transform = new AffineTransform(tx);
530: else
531: transform.concatenate(tx);
532:
533: if (clip != null)
534: {
535: try
536: {
537: AffineTransform clipTransform = tx.createInverse();
538: updateClip(clipTransform);
539: }
540: catch (NoninvertibleTransformException ex)
541: {
542:
543: ex.printStackTrace();
544: }
545: }
546:
547: setTransformImpl(transform);
548: }
549:
550: public void rotate(double theta)
551: {
552: transform(AffineTransform.getRotateInstance(theta));
553: }
554:
555: public void rotate(double theta, double x, double y)
556: {
557: transform(AffineTransform.getRotateInstance(theta, x, y));
558: }
559:
560: public void scale(double sx, double sy)
561: {
562: transform(AffineTransform.getScaleInstance(sx, sy));
563: }
564:
565:
569: public void translate(double tx, double ty)
570: {
571: if (transform != null)
572: transform.translate(tx, ty);
573: else
574: transform = AffineTransform.getTranslateInstance(tx, ty);
575:
576: if (clip != null)
577: {
578:
579:
580: if (clip instanceof Rectangle2D)
581: {
582: Rectangle2D r = (Rectangle2D) clip;
583: r.setRect(r.getX() - tx, r.getY() - ty, r.getWidth(),
584: r.getHeight());
585: }
586: else
587: {
588: AffineTransform clipTransform =
589: AffineTransform.getTranslateInstance(-tx, -ty);
590: updateClip(clipTransform);
591: }
592: }
593:
594: setTransformImpl(transform);
595: }
596:
597: public void translate(int x, int y)
598: {
599: translate((double) x, (double) y);
600: }
601:
602: public void shear(double shearX, double shearY)
603: {
604: transform(AffineTransform.getShearInstance(shearX, shearY));
605: }
606:
607:
608:
609: public void clip(Shape s)
610: {
611:
612: if (s == null)
613: {
614:
615:
616:
617:
618: setClip(null);
619: return;
620: }
621:
622:
623: if (clip == null)
624: {
625: clip = getRealBounds();
626: }
627:
628:
629: if (clip instanceof Rectangle2D && s instanceof Rectangle2D)
630: {
631: Rectangle2D clipRect = (Rectangle2D) clip;
632: Rectangle2D r = (Rectangle2D) s;
633: Rectangle2D.intersect(clipRect, r, clipRect);
634: setClip(clipRect);
635: }
636: else
637: {
638: Area current;
639: if (clip instanceof Area)
640: current = (Area) clip;
641: else
642: current = new Area(clip);
643:
644: Area intersect;
645: if (s instanceof Area)
646: intersect = (Area) s;
647: else
648: intersect = new Area(s);
649:
650: current.intersect(intersect);
651: clip = current;
652:
653: setClip(clip);
654: }
655: }
656:
657: public Paint getPaint()
658: {
659: return paint;
660: }
661:
662: public AffineTransform getTransform()
663: {
664: return (AffineTransform) transform.clone();
665: }
666:
667: public void setPaint(Paint p)
668: {
669: if (paint == null)
670: return;
671:
672: paint = p;
673: if (paint instanceof Color)
674: {
675: setColor((Color) paint);
676: }
677: else if (paint instanceof TexturePaint)
678: {
679: TexturePaint tp = (TexturePaint) paint;
680: BufferedImage img = tp.getImage();
681:
682:
683: int width = (int) tp.getAnchorRect().getWidth();
684: int height = (int) tp.getAnchorRect().getHeight();
685:
686: double scaleX = width / (double) img.getWidth();
687: double scaleY = height / (double) img.getHeight();
688:
689: AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0);
690: AffineTransformOp op = new AffineTransformOp(at, getRenderingHints());
691: BufferedImage texture = op.filter(img, null);
692: int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width);
693: setTexturePixels(nativePointer, pixels, width, height, width);
694: }
695: else if (paint instanceof GradientPaint)
696: {
697: GradientPaint gp = (GradientPaint) paint;
698: Point2D p1 = gp.getPoint1();
699: Point2D p2 = gp.getPoint2();
700: Color c1 = gp.getColor1();
701: Color c2 = gp.getColor2();
702: setGradient(nativePointer, p1.getX(), p1.getY(), p2.getX(), p2.getY(),
703: c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha(),
704: c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha(),
705: gp.isCyclic());
706: }
707: else
708: throw new java.lang.UnsupportedOperationException();
709: }
710:
711: public Stroke getStroke()
712: {
713: return stroke;
714: }
715:
716: public void setStroke(Stroke st)
717: {
718: stroke = st;
719: if (stroke instanceof BasicStroke)
720: {
721: BasicStroke bs = (BasicStroke) stroke;
722: cairoSetLine(nativePointer, bs.getLineWidth(), bs.getEndCap(),
723: bs.getLineJoin(), bs.getMiterLimit());
724:
725: float[] dashes = bs.getDashArray();
726: if (dashes != null)
727: {
728: double[] double_dashes = new double[dashes.length];
729: for (int i = 0; i < dashes.length; i++)
730: double_dashes[i] = dashes[i];
731: cairoSetDash(nativePointer, double_dashes, double_dashes.length,
732: (double) bs.getDashPhase());
733: }
734: else
735: cairoSetDash(nativePointer, new double[0], 0, 0.0);
736: }
737: }
738:
739: public void setPaintMode()
740: {
741: setComposite(AlphaComposite.SrcOver);
742: }
743:
744: public void setXORMode(Color c)
745: {
746:
747: }
748:
749: public void setColor(Color c)
750: {
751: if (c == null)
752: c = Color.BLACK;
753:
754: fg = c;
755: paint = c;
756: updateColor();
757: }
758:
759:
762: void updateColor()
763: {
764: if (fg == null)
765: fg = Color.BLACK;
766: cairoSetRGBAColor(nativePointer, fg.getRed() / 255.0,
767: fg.getGreen() / 255.0,fg.getBlue() / 255.0,
768: fg.getAlpha() / 255.0);
769: }
770:
771: public Color getColor()
772: {
773: return fg;
774: }
775:
776: public void clipRect(int x, int y, int width, int height)
777: {
778: if (clip == null)
779: setClip(new Rectangle(x, y, width, height));
780: else if (clip instanceof Rectangle)
781: {
782: computeIntersection(x, y, width, height, (Rectangle) clip);
783: setClip(clip);
784: }
785: else
786: clip(new Rectangle(x, y, width, height));
787: }
788:
789: public Shape getClip()
790: {
791: if (clip == null)
792: return null;
793: else if (clip instanceof Rectangle2D)
794: return clip.getBounds2D();
795: else
796: {
797: GeneralPath p = new GeneralPath();
798: PathIterator pi = clip.getPathIterator(null);
799: p.append(pi, false);
800: return p;
801: }
802: }
803:
804: public Rectangle getClipBounds()
805: {
806: if (clip == null)
807: return null;
808: else
809: return clip.getBounds();
810: }
811:
812: protected Rectangle2D getClipInDevSpace()
813: {
814: Rectangle2D uclip = clip.getBounds2D();
815: if (transform == null)
816: return uclip;
817: else
818: {
819: Point2D pos = transform.transform(new Point2D.Double(uclip.getX(),
820: uclip.getY()),
821: (Point2D) null);
822: Point2D extent = transform.deltaTransform(new Point2D.Double(uclip
823: .getWidth(),
824: uclip
825: .getHeight()),
826: (Point2D) null);
827: return new Rectangle2D.Double(pos.getX(), pos.getY(), extent.getX(),
828: extent.getY());
829: }
830: }
831:
832: public void setClip(int x, int y, int width, int height)
833: {
834: if( width < 0 || height < 0 )
835: return;
836:
837: setClip(new Rectangle2D.Double(x, y, width, height));
838: }
839:
840: public void setClip(Shape s)
841: {
842:
843:
844:
845:
846: if( firstClip )
847: {
848: originalClip = s;
849: firstClip = false;
850: }
851:
852: clip = s;
853: cairoResetClip(nativePointer);
854:
855: if (clip != null)
856: {
857: cairoNewPath(nativePointer);
858: if (clip instanceof Rectangle2D)
859: {
860: Rectangle2D r = (Rectangle2D) clip;
861: cairoRectangle(nativePointer, r.getX(), r.getY(), r.getWidth(),
862: r.getHeight());
863: }
864: else
865: walkPath(clip.getPathIterator(null), false);
866:
867: cairoClip(nativePointer);
868: }
869: }
870:
871: public void setBackground(Color c)
872: {
873: if (c == null)
874: c = Color.WHITE;
875: bg = c;
876: }
877:
878: public Color getBackground()
879: {
880: return bg;
881: }
882:
883:
886: public Composite getComposite()
887: {
888: if (comp == null)
889: return AlphaComposite.SrcOver;
890: else
891: return comp;
892: }
893:
894:
897: public void setComposite(Composite comp)
898: {
899: this.comp = comp;
900:
901: if (comp instanceof AlphaComposite)
902: {
903: AlphaComposite a = (AlphaComposite) comp;
904: cairoSetOperator(nativePointer, a.getRule());
905: }
906: else
907: {
908:
909:
910: SecurityManager sm = System.getSecurityManager();
911: if (sm != null)
912: sm.checkPermission(new AWTPermission("readDisplayPixels"));
913:
914:
915: throw new java.lang.UnsupportedOperationException();
916: }
917: }
918:
919:
920:
921: public void draw(Shape s)
922: {
923: if ((stroke != null && ! (stroke instanceof BasicStroke))
924: || (comp instanceof AlphaComposite && ((AlphaComposite) comp).getAlpha() != 1.0))
925: {
926:
927:
928: fill(stroke.createStrokedShape(s));
929: return;
930: }
931:
932: createPath(s);
933: cairoStroke(nativePointer);
934: }
935:
936: public void fill(Shape s)
937: {
938: createPath(s);
939:
940: double alpha = 1.0;
941: if (comp instanceof AlphaComposite)
942: alpha = ((AlphaComposite) comp).getAlpha();
943: cairoFill(nativePointer, alpha);
944: }
945:
946: private void createPath(Shape s)
947: {
948: cairoNewPath(nativePointer);
949:
950:
951: if (s instanceof Rectangle2D)
952: {
953: Rectangle2D r = (Rectangle2D) s;
954: cairoRectangle(nativePointer, shifted(r.getX(), shiftDrawCalls),
955: shifted(r.getY(), shiftDrawCalls), r.getWidth(),
956: r.getHeight());
957: }
958:
959:
960:
961:
962: else if (s instanceof Ellipse2D)
963: {
964: Ellipse2D e = (Ellipse2D) s;
965:
966: double radius = Math.min(e.getHeight(), e.getWidth()) / 2;
967:
968:
969:
970: double xscale = 1, yscale = 1;
971: if (e.getHeight() != e.getWidth())
972: {
973: cairoSave(nativePointer);
974:
975: if (e.getHeight() < e.getWidth())
976: xscale = e.getWidth() / (radius * 2);
977: else
978: yscale = e.getHeight() / (radius * 2);
979:
980: if (xscale != 1 || yscale != 1)
981: cairoScale(nativePointer, xscale, yscale);
982: }
983:
984: cairoArc(nativePointer,
985: shifted(e.getCenterX() / xscale, shiftDrawCalls),
986: shifted(e.getCenterY() / yscale, shiftDrawCalls), radius, 0,
987: Math.PI * 2);
988:
989: if (xscale != 1 || yscale != 1)
990: cairoRestore(nativePointer);
991: }
992:
993:
994:
995: else
996: walkPath(s.getPathIterator(null), shiftDrawCalls);
997: }
998:
999:
1004:
1005: public void clearRect(int x, int y, int width, int height)
1006: {
1007: if (bg != null)
1008: cairoSetRGBAColor(nativePointer, bg.getRed() / 255.0,
1009: bg.getGreen() / 255.0, bg.getBlue() / 255.0, 1.0);
1010: fillRect(x, y, width, height);
1011: updateColor();
1012: }
1013:
1014: public void draw3DRect(int x, int y, int width, int height, boolean raised)
1015: {
1016: Stroke tmp = stroke;
1017: setStroke(draw3DRectStroke);
1018: super.draw3DRect(x, y, width, height, raised);
1019: setStroke(tmp);
1020: }
1021:
1022: public void drawArc(int x, int y, int width, int height, int startAngle,
1023: int arcAngle)
1024: {
1025: draw(new Arc2D.Double((double) x, (double) y, (double) width,
1026: (double) height, (double) startAngle,
1027: (double) arcAngle, Arc2D.OPEN));
1028: }
1029:
1030: public void drawLine(int x1, int y1, int x2, int y2)
1031: {
1032:
1033:
1034:
1035: if (x1 == x2 && y1 == y2)
1036: cairoFillRect(nativePointer, x1, y1, 1, 1);
1037: else
1038: cairoDrawLine(nativePointer, x1 + 0.5, y1 + 0.5, x2 + 0.5, y2 + 0.5);
1039: }
1040:
1041: public void drawRect(int x, int y, int width, int height)
1042: {
1043: cairoDrawRect(nativePointer, shifted(x, shiftDrawCalls),
1044: shifted(y, shiftDrawCalls), width, height);
1045: }
1046:
1047: public void fillArc(int x, int y, int width, int height, int startAngle,
1048: int arcAngle)
1049: {
1050: fill(new Arc2D.Double((double) x, (double) y, (double) width,
1051: (double) height, (double) startAngle,
1052: (double) arcAngle, Arc2D.OPEN));
1053: }
1054:
1055: public void fillRect(int x, int y, int width, int height)
1056: {
1057: cairoFillRect(nativePointer, x, y, width, height);
1058: }
1059:
1060: public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints)
1061: {
1062: fill(new Polygon(xPoints, yPoints, nPoints));
1063: }
1064:
1065: public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints)
1066: {
1067: draw(new Polygon(xPoints, yPoints, nPoints));
1068: }
1069:
1070: public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints)
1071: {
1072: draw(new Polygon(xPoints, yPoints, nPoints));
1073: }
1074:
1075: public void drawOval(int x, int y, int width, int height)
1076: {
1077: drawArc(x, y, width, height, 0, 360);
1078: }
1079:
1080: public void drawRoundRect(int x, int y, int width, int height, int arcWidth,
1081: int arcHeight)
1082: {
1083: draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
1084: }
1085:
1086: public void fillOval(int x, int y, int width, int height)
1087: {
1088: fillArc(x, y, width, height, 0, 360);
1089: }
1090:
1091: public void fillRoundRect(int x, int y, int width, int height, int arcWidth,
1092: int arcHeight)
1093: {
1094: fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight));
1095: }
1096:
1097:
1101: public void copyArea(int ox, int oy, int owidth, int oheight,
1102: int odx, int ody)
1103: {
1104: Point2D pos = transform.transform(new Point2D.Double(ox, oy),
1105: (Point2D) null);
1106: Point2D dim = transform.transform(new Point2D.Double(ox + owidth,
1107: oy + oheight),
1108: (Point2D) null);
1109: Point2D p2 = transform.transform(new Point2D.Double(ox + odx, oy + ody),
1110: (Point2D) null);
1111: int x = (int)pos.getX();
1112: int y = (int)pos.getY();
1113: int width = (int)(dim.getX() - pos.getX());
1114: int height = (int)(dim.getY() - pos.getY());
1115: int dx = (int)(p2.getX() - pos.getX());
1116: int dy = (int)(p2.getY() - pos.getY());
1117:
1118: Rectangle2D r = getRealBounds();
1119:
1120: if( width < 0 || height < 0 )
1121: return;
1122:
1123: if( x + dx > r.getWidth() || y + dy > r.getHeight() )
1124: return;
1125:
1126: if( x + dx + width < r.getX() || y + dy + height < r.getY() )
1127: return;
1128:
1129:
1130: if( x + dx < r.getX() )
1131: {
1132: width = x + dx + width;
1133: x = (int)r.getX() - dx;
1134: }
1135:
1136: if( y + dy < r.getY() )
1137: {
1138: height = y + dy + height;
1139: y = (int)r.getY() - dy;
1140: }
1141:
1142: if( x + dx + width >= r.getWidth() )
1143: width = (int)r.getWidth() - dx - x;
1144:
1145: if( y + dy + height >= r.getHeight() )
1146: height = (int)r.getHeight() - dy - y;
1147:
1148: copyAreaImpl(x, y, width, height, dx, dy);
1149: }
1150:
1151:
1152:
1153:
1156: public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
1157: {
1158: hints.put(hintKey, hintValue);
1159:
1160: if (hintKey.equals(RenderingHints.KEY_INTERPOLATION)
1161: || hintKey.equals(RenderingHints.KEY_ALPHA_INTERPOLATION))
1162: {
1163: if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
1164: cairoSurfaceSetFilter(nativePointer, 0);
1165:
1166: else if (hintValue.equals(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
1167: cairoSurfaceSetFilter(nativePointer, 1);
1168:
1169: else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
1170: cairoSurfaceSetFilter(nativePointer, 2);
1171:
1172: else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
1173: cairoSurfaceSetFilter(nativePointer, 3);
1174:
1175: else if (hintValue.equals(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
1176: cairoSurfaceSetFilter(nativePointer, 4);
1177: }
1178:
1179: shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
1180: || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
1181: }
1182:
1183: public Object getRenderingHint(RenderingHints.Key hintKey)
1184: {
1185: return hints.get(hintKey);
1186: }
1187:
1188: public void setRenderingHints(Map hints)
1189: {
1190: this.hints = new RenderingHints(getDefaultHints());
1191: this.hints.add(new RenderingHints(hints));
1192:
1193: if (hints.containsKey(RenderingHints.KEY_INTERPOLATION))
1194: {
1195: if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR))
1196: cairoSurfaceSetFilter(nativePointer, 0);
1197:
1198: else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR))
1199: cairoSurfaceSetFilter(nativePointer, 1);
1200: }
1201:
1202: if (hints.containsKey(RenderingHints.KEY_ALPHA_INTERPOLATION))
1203: {
1204: if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED))
1205: cairoSurfaceSetFilter(nativePointer, 2);
1206:
1207: else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY))
1208: cairoSurfaceSetFilter(nativePointer, 3);
1209:
1210: else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT))
1211: cairoSurfaceSetFilter(nativePointer, 4);
1212: }
1213:
1214: shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE)
1215: || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT);
1216: }
1217:
1218: public void addRenderingHints(Map hints)
1219: {
1220: this.hints.add(new RenderingHints(hints));
1221: }
1222:
1223: public RenderingHints getRenderingHints()
1224: {
1225: return hints;
1226: }
1227:
1228:
1229:
1230: protected boolean drawImage(Image img, AffineTransform xform,
1231: Color bgcolor, ImageObserver obs)
1232: {
1233: if (img == null)
1234: return false;
1235:
1236: if (xform == null)
1237: xform = new AffineTransform();
1238:
1239:
1240:
1241:
1242:
1243:
1244:
1245:
1246: AffineTransform invertedXform;
1247:
1248: try
1249: {
1250: invertedXform = xform.createInverse();
1251: }
1252: catch (NoninvertibleTransformException e)
1253: {
1254: throw new ImagingOpException("Unable to invert transform "
1255: + xform.toString());
1256: }
1257:
1258:
1259:
1260:
1261:
1262:
1263: if( !(img instanceof BufferedImage) )
1264: {
1265: ImageProducer source = img.getSource();
1266: if (source == null)
1267: return false;
1268: img = Toolkit.getDefaultToolkit().createImage(source);
1269: }
1270:
1271: BufferedImage b = (BufferedImage) img;
1272: DataBuffer db;
1273: double[] i2u = new double[6];
1274: int width = b.getWidth();
1275: int height = b.getHeight();
1276:
1277:
1278:
1279:
1280: if( BufferedImageGraphics.bufferedImages.get( b ) != null )
1281: db = (DataBuffer)BufferedImageGraphics.bufferedImages.get( b );
1282: else
1283: db = b.getRaster().getDataBuffer();
1284:
1285: invertedXform.getMatrix(i2u);
1286:
1287: double alpha = 1.0;
1288: if (comp instanceof AlphaComposite)
1289: alpha = ((AlphaComposite) comp).getAlpha();
1290:
1291: if(db instanceof CairoSurface)
1292: {
1293: ((CairoSurface)db).drawSurface(nativePointer, i2u, alpha);
1294: updateColor();
1295: return true;
1296: }
1297:
1298: if( bgcolor != null )
1299: {
1300:
1301:
1302: Paint oldPaint = paint;
1303: AffineTransform oldTransform = transform;
1304: setPaint( bgcolor );
1305: setTransform( invertedXform );
1306: fillRect(0, 0, width, height);
1307: setTransform( oldTransform );
1308: setPaint( oldPaint );
1309: }
1310:
1311: int[] pixels = b.getRGB(0, 0, width, height, null, 0, width);
1312:
1313: drawPixels(nativePointer, pixels, width, height, width, i2u, alpha);
1314:
1315:
1316: updateColor();
1317: return true;
1318: }
1319:
1320: public void drawRenderedImage(RenderedImage image, AffineTransform xform)
1321: {
1322: drawRaster(image.getColorModel(), image.getData(), xform, null);
1323: }
1324:
1325: public void drawRenderableImage(RenderableImage image, AffineTransform xform)
1326: {
1327: drawRenderedImage(image.createRendering(new RenderContext(xform)), xform);
1328: }
1329:
1330: public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs)
1331: {
1332: return drawImage(img, xform, null, obs);
1333: }
1334:
1335: public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y)
1336: {
1337: Image filtered = image;
1338: if (op != null)
1339: filtered = op.filter(image, null);
1340: drawImage(filtered, new AffineTransform(1f, 0f, 0f, 1f, x, y), null, null);
1341: }
1342:
1343: public boolean drawImage(Image img, int x, int y, ImageObserver observer)
1344: {
1345: return drawImage(img, new AffineTransform(1f, 0f, 0f, 1f, x, y), null,
1346: observer);
1347: }
1348:
1349: public boolean drawImage(Image img, int x, int y, Color bgcolor,
1350: ImageObserver observer)
1351: {
1352: return drawImage(img, x, y, img.getWidth(observer),
1353: img.getHeight(observer), bgcolor, observer);
1354: }
1355:
1356: public boolean drawImage(Image img, int x, int y, int width, int height,
1357: Color bgcolor, ImageObserver observer)
1358: {
1359: double scaleX = width / (double) img.getWidth(observer);
1360: double scaleY = height / (double) img.getHeight(observer);
1361: if( scaleX == 0 || scaleY == 0 )
1362: return true;
1363:
1364: return drawImage(img, new AffineTransform(scaleX, 0f, 0f, scaleY, x, y),
1365: bgcolor, observer);
1366: }
1367:
1368: public boolean drawImage(Image img, int x, int y, int width, int height,
1369: ImageObserver observer)
1370: {
1371: return drawImage(img, x, y, width, height, null, observer);
1372: }
1373:
1374: public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1375: int sx1, int sy1, int sx2, int sy2, Color bgcolor,
1376: ImageObserver observer)
1377: {
1378: if (img == null)
1379: return false;
1380:
1381: int sourceWidth = sx2 - sx1;
1382: int sourceHeight = sy2 - sy1;
1383:
1384: int destWidth = dx2 - dx1;
1385: int destHeight = dy2 - dy1;
1386:
1387: if(destWidth == 0 || destHeight == 0 || sourceWidth == 0 ||
1388: sourceHeight == 0)
1389: return true;
1390:
1391: double scaleX = destWidth / (double) sourceWidth;
1392: double scaleY = destHeight / (double) sourceHeight;
1393:
1394:
1395:
1396: Shape oldClip = getClip();
1397: int cx, cy, cw, ch;
1398: if( dx1 < dx2 )
1399: { cx = dx1; cw = dx2 - dx1; }
1400: else
1401: { cx = dx2; cw = dx1 - dx2; }
1402: if( dy1 < dy2 )
1403: { cy = dy1; ch = dy2 - dy1; }
1404: else
1405: { cy = dy2; ch = dy1 - dy2; }
1406:
1407: clipRect( cx, cy, cw, ch );
1408:
1409: AffineTransform tx = new AffineTransform();
1410: tx.translate( dx1 - sx1*scaleX, dy1 - sy1*scaleY );
1411: tx.scale( scaleX, scaleY );
1412:
1413: boolean retval = drawImage(img, tx, bgcolor, observer);
1414: setClip( oldClip );
1415: return retval;
1416: }
1417:
1418: public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
1419: int sx1, int sy1, int sx2, int sy2,
1420: ImageObserver observer)
1421: {
1422: return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer);
1423: }
1424:
1425:
1426:
1427: public void drawString(String str, float x, float y)
1428: {
1429: if (str == null || str.length() == 0)
1430: return;
1431: (new TextLayout( str, getFont(), getFontRenderContext() )).
1432: draw(this, x, y);
1433: }
1434:
1435: public void drawString(String str, int x, int y)
1436: {
1437: drawString (str, (float) x, (float) y);
1438: }
1439:
1440: public void drawString(AttributedCharacterIterator ci, int x, int y)
1441: {
1442: drawString (ci, (float) x, (float) y);
1443: }
1444:
1445: public void drawGlyphVector(GlyphVector gv, float x, float y)
1446: {
1447: double alpha = 1.0;
1448:
1449: if( gv.getNumGlyphs() <= 0 )
1450: return;
1451:
1452: if (comp instanceof AlphaComposite)
1453: alpha = ((AlphaComposite) comp).getAlpha();
1454: if (gv instanceof FreetypeGlyphVector && alpha == 1.0)
1455: {
1456: int n = gv.getNumGlyphs ();
1457: int[] codes = gv.getGlyphCodes (0, n, null);
1458: float[] positions = gv.getGlyphPositions (0, n, null);
1459:
1460: setFont (gv.getFont ());
1461: synchronized( this.font )
1462: {
1463: cairoDrawGlyphVector(nativePointer, (GdkFontPeer)getFont().getPeer(),
1464: x, y, n, codes, positions);
1465: }
1466: }
1467: else
1468: {
1469: translate(x, y);
1470: fill(gv.getOutline());
1471: translate(-x, -y);
1472: }
1473: }
1474:
1475: public void drawString(AttributedCharacterIterator ci, float x, float y)
1476: {
1477: GlyphVector gv = getFont().createGlyphVector(getFontRenderContext(), ci);
1478: drawGlyphVector(gv, x, y);
1479: }
1480:
1481:
1485: public FontRenderContext getFontRenderContext()
1486: {
1487: return new FontRenderContext(transform, true, true);
1488: }
1489:
1490:
1491:
1492:
1493:
1494: public FontMetrics getFontMetrics()
1495: {
1496: return getFontMetrics(getFont());
1497: }
1498:
1499: public FontMetrics getFontMetrics(Font f)
1500: {
1501:
1502:
1503: return Toolkit.getDefaultToolkit().getFontMetrics(f);
1504: }
1505:
1506: public void setFont(Font f)
1507: {
1508:
1509:
1510: if (f == null)
1511: return;
1512:
1513: if (f.getPeer() instanceof GdkFontPeer)
1514: font = f;
1515: else
1516: font =
1517: ((ClasspathToolkit)(Toolkit.getDefaultToolkit()))
1518: .getFont(f.getName(), f.getAttributes());
1519: }
1520:
1521: public Font getFont()
1522: {
1523: if (font == null)
1524: return new Font("SansSerif", Font.PLAIN, 12);
1525: return font;
1526: }
1527:
1528:
1529:
1530: public boolean hit(Rectangle rect, Shape s, boolean onStroke)
1531: {
1532: if( onStroke )
1533: {
1534: Shape stroked = stroke.createStrokedShape( s );
1535: return stroked.intersects( (double)rect.x, (double)rect.y,
1536: (double)rect.width, (double)rect.height );
1537: }
1538: return s.intersects( (double)rect.x, (double)rect.y,
1539: (double)rect.width, (double)rect.height );
1540: }
1541:
1542: public String toString()
1543: {
1544: return (getClass().getName()
1545: + "[font=" + getFont().toString()
1546: + ",color=" + fg.toString()
1547: + "]");
1548: }
1549:
1550:
1551:
1552:
1559: private boolean drawRaster(ColorModel cm, Raster r,
1560: AffineTransform imageToUser, Color bgcolor)
1561: {
1562: if (r == null)
1563: return false;
1564:
1565: SampleModel sm = r.getSampleModel();
1566: DataBuffer db = r.getDataBuffer();
1567:
1568: if (db == null || sm == null)
1569: return false;
1570:
1571: if (cm == null)
1572: cm = ColorModel.getRGBdefault();
1573:
1574: double[] i2u = new double[6];
1575: if (imageToUser != null)
1576: imageToUser.getMatrix(i2u);
1577: else
1578: {
1579: i2u[0] = 1;
1580: i2u[1] = 0;
1581: i2u[2] = 0;
1582: i2u[3] = 1;
1583: i2u[4] = 0;
1584: i2u[5] = 0;
1585: }
1586:
1587: int[] pixels = findSimpleIntegerArray(cm, r);
1588:
1589: if (pixels == null)
1590: {
1591:
1592:
1593:
1594:
1595: if (sm instanceof MultiPixelPackedSampleModel)
1596: {
1597: pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels);
1598: for (int i = 0; i < pixels.length; i++)
1599: pixels[i] = cm.getRGB(pixels[i]);
1600: }
1601: else
1602: {
1603: pixels = new int[r.getWidth() * r.getHeight()];
1604: for (int i = 0; i < pixels.length; i++)
1605: pixels[i] = cm.getRGB(db.getElem(i));
1606: }
1607: }
1608:
1609:
1610:
1611:
1612: if (cm.hasAlpha())
1613: {
1614: if (bgcolor != null && cm.hasAlpha())
1615: for (int i = 0; i < pixels.length; i++)
1616: {
1617: if (cm.getAlpha(pixels[i]) == 0)
1618: pixels[i] = bgcolor.getRGB();
1619: }
1620: }
1621: else
1622: for (int i = 0; i < pixels.length; i++)
1623: pixels[i] |= 0xFF000000;
1624:
1625: double alpha = 1.0;
1626: if (comp instanceof AlphaComposite)
1627: alpha = ((AlphaComposite) comp).getAlpha();
1628: drawPixels(nativePointer, pixels, r.getWidth(), r.getHeight(),
1629: r.getWidth(), i2u, alpha);
1630:
1631:
1632: updateColor();
1633:
1634: return true;
1635: }
1636:
1637:
1640: private double shifted(double coord, boolean doShift)
1641: {
1642: if (doShift)
1643: return Math.floor(coord) + 0.5;
1644: else
1645: return coord;
1646: }
1647:
1648:
1651: private void walkPath(PathIterator p, boolean doShift)
1652: {
1653: double x = 0;
1654: double y = 0;
1655: double[] coords = new double[6];
1656:
1657: cairoSetFillRule(nativePointer, p.getWindingRule());
1658: for (; ! p.isDone(); p.next())
1659: {
1660: int seg = p.currentSegment(coords);
1661: switch (seg)
1662: {
1663: case PathIterator.SEG_MOVETO:
1664: x = shifted(coords[0], doShift);
1665: y = shifted(coords[1], doShift);
1666: cairoMoveTo(nativePointer, x, y);
1667: break;
1668: case PathIterator.SEG_LINETO:
1669: x = shifted(coords[0], doShift);
1670: y = shifted(coords[1], doShift);
1671: cairoLineTo(nativePointer, x, y);
1672: break;
1673: case PathIterator.SEG_QUADTO:
1674:
1675:
1676: double x1 = x + (2.0 / 3.0) * (shifted(coords[0], doShift) - x);
1677: double y1 = y + (2.0 / 3.0) * (shifted(coords[1], doShift) - y);
1678:
1679: double x2 = x1 + (1.0 / 3.0) * (shifted(coords[2], doShift) - x);
1680: double y2 = y1 + (1.0 / 3.0) * (shifted(coords[3], doShift) - y);
1681:
1682: x = shifted(coords[2], doShift);
1683: y = shifted(coords[3], doShift);
1684: cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y);
1685: break;
1686: case PathIterator.SEG_CUBICTO:
1687: x = shifted(coords[4], doShift);
1688: y = shifted(coords[5], doShift);
1689: cairoCurveTo(nativePointer, shifted(coords[0], doShift),
1690: shifted(coords[1], doShift),
1691: shifted(coords[2], doShift),
1692: shifted(coords[3], doShift), x, y);
1693: break;
1694: case PathIterator.SEG_CLOSE:
1695: cairoClosePath(nativePointer);
1696: break;
1697: }
1698: }
1699: }
1700:
1701:
1704: private Map getDefaultHints()
1705: {
1706: HashMap defaultHints = new HashMap();
1707:
1708: defaultHints.put(RenderingHints.KEY_TEXT_ANTIALIASING,
1709: RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT);
1710:
1711: defaultHints.put(RenderingHints.KEY_STROKE_CONTROL,
1712: RenderingHints.VALUE_STROKE_DEFAULT);
1713:
1714: defaultHints.put(RenderingHints.KEY_FRACTIONALMETRICS,
1715: RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
1716:
1717: defaultHints.put(RenderingHints.KEY_ANTIALIASING,
1718: RenderingHints.VALUE_ANTIALIAS_OFF);
1719:
1720: defaultHints.put(RenderingHints.KEY_RENDERING,
1721: RenderingHints.VALUE_RENDER_DEFAULT);
1722:
1723: return defaultHints;
1724: }
1725:
1726:
1729: public static int[] findSimpleIntegerArray (ColorModel cm, Raster raster)
1730: {
1731: if (cm == null || raster == null)
1732: return null;
1733:
1734: if (! cm.getColorSpace().isCS_sRGB())
1735: return null;
1736:
1737: if (! (cm instanceof DirectColorModel))
1738: return null;
1739:
1740: DirectColorModel dcm = (DirectColorModel) cm;
1741:
1742: if (dcm.getRedMask() != 0x00FF0000 || dcm.getGreenMask() != 0x0000FF00
1743: || dcm.getBlueMask() != 0x000000FF)
1744: return null;
1745:
1746: if (! (raster instanceof WritableRaster))
1747: return null;
1748:
1749: if (raster.getSampleModel().getDataType() != DataBuffer.TYPE_INT)
1750: return null;
1751:
1752: if (! (raster.getDataBuffer() instanceof DataBufferInt))
1753: return null;
1754:
1755: DataBufferInt db = (DataBufferInt) raster.getDataBuffer();
1756:
1757: if (db.getNumBanks() != 1)
1758: return null;
1759:
1760:
1761:
1762:
1763:
1764:
1765: return db.getData();
1766: }
1767:
1768:
1778: private void updateClip(AffineTransform t)
1779: {
1780: if (clip == null)
1781: return;
1782:
1783: if (! (clip instanceof GeneralPath))
1784: clip = new GeneralPath(clip);
1785:
1786: GeneralPath p = (GeneralPath) clip;
1787: p.transform(t);
1788: }
1789:
1790: private static Rectangle computeIntersection(int x, int y, int w, int h,
1791: Rectangle rect)
1792: {
1793: int x2 = (int) rect.x;
1794: int y2 = (int) rect.y;
1795: int w2 = (int) rect.width;
1796: int h2 = (int) rect.height;
1797:
1798: int dx = (x > x2) ? x : x2;
1799: int dy = (y > y2) ? y : y2;
1800: int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx);
1801: int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy);
1802:
1803: if (dw >= 0 && dh >= 0)
1804: rect.setBounds(dx, dy, dw, dh);
1805: else
1806: rect.setBounds(0, 0, 0, 0);
1807:
1808: return rect;
1809: }
1810: }