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:
66:
72: public class ComponentGraphics extends CairoGraphics2D
73: {
74: private static final boolean hasXRenderExtension = hasXRender();
75:
76: private GtkComponentPeer component;
77: protected long cairo_t;
78: private BufferedImage buffer, componentBuffer;
79:
80: private static ThreadLocal<Integer> hasLock = new ThreadLocal<Integer>();
81: private static Integer ONE = Integer.valueOf(1);
82:
83: ComponentGraphics()
84: {
85: }
86:
87: private ComponentGraphics(GtkComponentPeer component)
88: {
89: this.component = component;
90: cairo_t = initState(component);
91: setup( cairo_t );
92: Rectangle bounds = component.awtComponent.getBounds();
93: setClip( new Rectangle( 0, 0, bounds.width, bounds.height) );
94: setBackground(component.awtComponent.getBackground());
95: setColor(component.awtComponent.getForeground());
96: }
97:
98: private ComponentGraphics(ComponentGraphics cg)
99: {
100: component = cg.component;
101: cairo_t = initState(component);
102: copy( cg, cairo_t );
103: Rectangle bounds = component.awtComponent.getBounds();
104: setClip( new Rectangle( 0, 0, bounds.width, bounds.height) );
105: setBackground(component.awtComponent.getBackground());
106: setColor(component.awtComponent.getForeground());
107: }
108:
109:
112: private native long initState(GtkComponentPeer component);
113:
114:
122: private void lock()
123: {
124: Integer i = hasLock.get();
125: if (i == null)
126: {
127: start_gdk_drawing();
128: hasLock.set(ONE);
129: }
130: else
131: hasLock.set(Integer.valueOf(i.intValue() + 1));
132: }
133:
134:
137: private void unlock()
138: {
139: Integer i = hasLock.get();
140: if (i == null)
141: throw new IllegalStateException();
142: if (i == ONE)
143: {
144: hasLock.set(null);
145: end_gdk_drawing();
146: }
147: else if (i.intValue() == 2)
148: hasLock.set(ONE);
149: else
150: hasLock.set(Integer.valueOf(i.intValue() - 1));
151: }
152:
153:
156: protected native long initFromVolatile( long pixmapPtr);
157:
158:
161: private native void start_gdk_drawing();
162:
163:
166: private native void end_gdk_drawing();
167:
168:
171: public static native boolean hasXRender();
172:
173:
177: private static native Pointer nativeGrab(GtkComponentPeer component);
178:
179: private native void copyAreaNative(GtkComponentPeer component, int x, int y,
180: int width, int height, int dx, int dy);
181:
182: private native void drawVolatile(GtkComponentPeer component,
183: long vimg, int x, int y,
184: int width, int height, int cx, int cy,
185: int cw, int ch);
186:
187:
190: public static GtkImage grab( GtkComponentPeer component )
191: {
192: return new GtkImage( nativeGrab( component ) );
193: }
194:
195:
199: public static Graphics2D getComponentGraphics(GtkComponentPeer component)
200: {
201: if( hasXRenderExtension )
202: return new ComponentGraphics(component);
203:
204: Rectangle r = component.awtComponent.getBounds();
205: return new ComponentGraphicsCopy(r.width, r.height, component);
206: }
207:
208: public GraphicsConfiguration getDeviceConfiguration()
209: {
210: return component.getGraphicsConfiguration();
211: }
212:
213: public Graphics create()
214: {
215: return new ComponentGraphics(this);
216: }
217:
218: protected Rectangle2D getRealBounds()
219: {
220: return component.awtComponent.getBounds();
221: }
222:
223: public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy)
224: {
225: copyAreaNative(component, x, y, width, height, dx, dy);
226: }
227:
228:
232: public void draw(Shape s)
233: {
234: if (comp == null || comp instanceof AlphaComposite)
235: super.draw(s);
236:
237: else
238: {
239: createBuffer();
240:
241: Graphics2D g2d = (Graphics2D)buffer.getGraphics();
242: g2d.setStroke(this.getStroke());
243: g2d.setColor(this.getColor());
244: g2d.draw(s);
245:
246: drawComposite(s.getBounds2D(), null);
247: }
248: }
249:
250: public void fill(Shape s)
251: {
252: if (comp == null || comp instanceof AlphaComposite)
253: super.fill(s);
254:
255: else
256: {
257: createBuffer();
258:
259: Graphics2D g2d = (Graphics2D)buffer.getGraphics();
260: g2d.setPaint(this.getPaint());
261: g2d.setColor(this.getColor());
262: g2d.fill(s);
263:
264: drawComposite(s.getBounds2D(), null);
265: }
266: }
267:
268: public void drawRenderedImage(RenderedImage image, AffineTransform xform)
269: {
270: if (comp == null || comp instanceof AlphaComposite)
271: super.drawRenderedImage(image, xform);
272:
273: else
274: {
275: createBuffer();
276:
277: Graphics2D g2d = (Graphics2D)buffer.getGraphics();
278: g2d.setRenderingHints(this.getRenderingHints());
279: g2d.drawRenderedImage(image, xform);
280:
281: drawComposite(buffer.getRaster().getBounds(), null);
282: }
283: }
284:
285: protected boolean drawImage(Image img, AffineTransform xform,
286: Color bgcolor, ImageObserver obs)
287: {
288: boolean rv;
289: if (comp == null || comp instanceof AlphaComposite)
290: rv = super.drawImage(img, xform, bgcolor, obs);
291:
292: else
293: {
294:
295: if( !(img instanceof BufferedImage) )
296: {
297: ImageProducer source = img.getSource();
298: if (source == null)
299: return false;
300: img = Toolkit.getDefaultToolkit().createImage(source);
301: }
302: BufferedImage bImg = (BufferedImage) img;
303:
304:
305: Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
306: Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(),
307: bImg.getHeight() + bImg.getMinY());
308: if (xform != null)
309: {
310: origin = xform.transform(origin, origin);
311: pt = xform.transform(pt, pt);
312: }
313:
314:
315: createBuffer();
316:
317: Graphics2D g2d = (Graphics2D)buffer.getGraphics();
318: g2d.setRenderingHints(this.getRenderingHints());
319: g2d.drawImage(img, xform, obs);
320:
321:
322: rv = drawComposite(new Rectangle2D.Double(origin.getX(),
323: origin.getY(),
324: pt.getX(), pt.getY()),
325: obs);
326: }
327: return rv;
328: }
329:
330: public void drawGlyphVector(GlyphVector gv, float x, float y)
331: {
332: if (comp == null || comp instanceof AlphaComposite)
333: super.drawGlyphVector(gv, x, y);
334:
335: else
336: {
337: createBuffer();
338:
339: Graphics2D g2d = (Graphics2D)buffer.getGraphics();
340: g2d.setPaint(this.getPaint());
341: g2d.setStroke(this.getStroke());
342: g2d.drawGlyphVector(gv, x, y);
343:
344: Rectangle2D bounds = gv.getLogicalBounds();
345: bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
346: bounds.getWidth(), bounds.getHeight());
347: drawComposite(bounds, null);
348: }
349: }
350:
351: public boolean drawImage(Image img, int x, int y, ImageObserver observer)
352: {
353:
354:
355:
356: if (img instanceof GtkVolatileImage)
357: {
358: GtkVolatileImage vimg = (GtkVolatileImage) img;
359: int type = transform.getType();
360: if ((type == AffineTransform.TYPE_IDENTITY
361: || type == AffineTransform.TYPE_TRANSLATION)
362: && (clip == null || clip instanceof Rectangle2D))
363: {
364: Rectangle2D r = (Rectangle2D) clip;
365: if (r == null)
366: r = getRealBounds();
367: x += transform.getTranslateX();
368: y += transform.getTranslateY();
369: drawVolatile(component, vimg.nativePointer,
370: x, y, vimg.width, vimg.height,
371: (int) (r.getX() + transform.getTranslateX()),
372: (int) (r.getY() + transform.getTranslateY()),
373: (int) r.getWidth(),
374: (int) r.getHeight());
375: return true;
376: }
377: else
378: return super.drawImage(vimg.getSnapshot(), x, y, observer);
379: }
380:
381: BufferedImage bimg;
382: if (img instanceof BufferedImage)
383: bimg = (BufferedImage) img;
384: else
385: {
386: ImageProducer source = img.getSource();
387: if (source == null)
388: return false;
389: bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source);
390: }
391: return super.drawImage(bimg, x, y, observer);
392: }
393:
394: public boolean drawImage(Image img, int x, int y, int width, int height,
395: ImageObserver observer)
396: {
397:
398:
399:
400: if (img instanceof GtkVolatileImage
401: && (clip == null || clip instanceof Rectangle2D))
402: {
403: GtkVolatileImage vimg = (GtkVolatileImage) img;
404: int type = transform.getType();
405: if ((type == AffineTransform.TYPE_IDENTITY
406: || type == AffineTransform.TYPE_TRANSLATION)
407: && (clip == null || clip instanceof Rectangle2D))
408: {
409: Rectangle2D r = (Rectangle2D) clip;
410: if (r == null)
411: r = getRealBounds();
412: x += transform.getTranslateX();
413: y += transform.getTranslateY();
414: drawVolatile(component, vimg.nativePointer,
415: x, y, width, height,
416: (int) (r.getX() + transform.getTranslateX()),
417: (int) (r.getY() + transform.getTranslateY()),
418: (int) r.getWidth(),
419: (int) r.getHeight());
420: return true;
421: }
422: else
423: return super.drawImage(vimg.getSnapshot(), x, y,
424: width, height, observer);
425: }
426:
427: BufferedImage bimg;
428: img = AsyncImage.realImage(img, observer);
429: if (img instanceof BufferedImage)
430: bimg = (BufferedImage) img;
431: else
432: {
433: ImageProducer source = img.getSource();
434: if (source == null)
435: return false;
436: bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source);
437: }
438: return super.drawImage(bimg, x, y, width, height, observer);
439: }
440:
441: private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
442: {
443:
444: Rectangle2D clip = this.getClipBounds();
445: Rectangle2D.intersect(bounds, clip, bounds);
446: clip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
447: buffer.getWidth(), buffer.getHeight());
448: Rectangle2D.intersect(bounds, clip, bounds);
449:
450: BufferedImage buffer2 = buffer;
451: if (!bounds.equals(buffer2.getRaster().getBounds()))
452: buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
453: (int)bounds.getWidth(),
454: (int)bounds.getHeight());
455:
456:
457: double[] points = new double[] {bounds.getX(), bounds.getY(),
458: bounds.getMaxX(), bounds.getMaxY()};
459: transform.transform(points, 0, points, 0, 2);
460:
461: Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1],
462: points[2] - points[0],
463: points[3] - points[1]);
464:
465: Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds);
466:
467:
468: GtkImage img = grab(component);
469: Graphics gr = componentBuffer.createGraphics();
470: gr.drawImage(img, 0, 0, null);
471: gr.dispose();
472:
473: BufferedImage cBuffer = componentBuffer;
474: if (!deviceBounds.equals(cBuffer.getRaster().getBounds()))
475: cBuffer = cBuffer.getSubimage((int)deviceBounds.getX(),
476: (int)deviceBounds.getY(),
477: (int)deviceBounds.getWidth(),
478: (int)deviceBounds.getHeight());
479:
480:
481: compCtx.compose(buffer2.getRaster(), cBuffer.getRaster(),
482: cBuffer.getRaster());
483:
484:
485:
486:
487: boolean rv = super.drawImage(cBuffer,
488: AffineTransform.getTranslateInstance(bounds.getX(),
489: bounds.getY()),
490: null, null);
491: return rv;
492: }
493:
494: private void createBuffer()
495: {
496: if (buffer == null)
497: {
498: WritableRaster rst;
499: rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(),
500: component.awtComponent.getHeight()),
501: new Point(0,0));
502:
503: buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
504: GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
505: new Hashtable());
506: }
507: else
508: {
509: Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
510:
511: g2d.setBackground(new Color(0,0,0,0));
512: g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
513: }
514:
515: if (componentBuffer == null)
516: {
517: WritableRaster rst;
518: rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(),
519: component.awtComponent.getHeight()),
520: new Point(0,0));
521:
522: componentBuffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
523: GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
524: new Hashtable());
525: }
526: }
527:
528: protected ColorModel getNativeCM()
529: {
530: return GtkVolatileImage.gdkColorModel;
531: }
532:
533:
548:
549:
558:
559: @Override
560: protected long init(long pointer)
561: {
562: long ret;
563:
564: try
565: {
566: lock();
567: ret = super.init(pointer);
568: }
569: finally
570: {
571: unlock();
572: }
573:
574: return ret;
575: }
576:
577: @Override
578: protected void drawPixels(long pointer, int[] pixels, int w, int h,
579: int stride, double[] i2u, double alpha,
580: int interpolation)
581: {
582: try
583: {
584: lock();
585: super.drawPixels(pointer, pixels, w, h, stride, i2u, alpha,
586: interpolation);
587: }
588: finally
589: {
590: unlock();
591: }
592: }
593:
594: @Override
595: protected void setGradient(long pointer, double x1, double y1,
596: double x2, double y2,
597: int r1, int g1, int b1, int a1,
598: int r2, int g2, int b2, int a2, boolean cyclic)
599: {
600: try
601: {
602: lock();
603: super.setGradient(pointer, x1, y1, x2, y2, r1, g1, b1, a1, r2, g2, b2, a2,
604: cyclic);
605: }
606: finally
607: {
608: unlock();
609: }
610: }
611:
612: @Override
613: protected void setPaintPixels(long pointer, int[] pixels, int w, int h,
614: int stride, boolean repeat, int x, int y)
615: {
616: try
617: {
618: lock();
619: super.setPaintPixels(pointer, pixels, w, h, stride, repeat, x, y);
620: }
621: finally
622: {
623: unlock();
624: }
625: }
626:
627: @Override
628: protected void cairoSetMatrix(long pointer, double[] m)
629: {
630: try
631: {
632: lock();
633: super.cairoSetMatrix(pointer, m);
634: }
635: finally
636: {
637: unlock();
638: }
639: }
640:
641: @Override
642: protected void cairoScale(long pointer, double x, double y)
643: {
644: try
645: {
646: lock();
647: super.cairoScale(pointer, x, y);
648: }
649: finally
650: {
651: unlock();
652: }
653: }
654:
655: @Override
656: protected void cairoSetOperator(long pointer, int cairoOperator)
657: {
658: try
659: {
660: lock();
661: super.cairoSetOperator(pointer, cairoOperator);
662: }
663: finally
664: {
665: unlock();
666: }
667: }
668:
669: @Override
670: protected void cairoSetRGBAColor(long pointer, double red, double green,
671: double blue, double alpha)
672: {
673: try
674: {
675: lock();
676: super.cairoSetRGBAColor(pointer, red, green, blue, alpha);
677: }
678: finally
679: {
680: unlock();
681: }
682: }
683:
684: @Override
685: protected void cairoSetFillRule(long pointer, int cairoFillRule)
686: {
687: try
688: {
689: lock();
690: super.cairoSetFillRule(pointer, cairoFillRule);
691: }
692: finally
693: {
694: unlock();
695: }
696: }
697:
698: @Override
699: protected void cairoSetLine(long pointer, double width, int cap, int join,
700: double miterLimit)
701: {
702: try
703: {
704: lock();
705: super.cairoSetLine(pointer, width, cap, join, miterLimit);
706: }
707: finally
708: {
709: unlock();
710: }
711: }
712:
713: @Override
714: protected void cairoSetDash(long pointer, double[] dashes, int ndash,
715: double offset)
716: {
717: try
718: {
719: lock();
720: super.cairoSetDash(pointer, dashes, ndash, offset);
721: }
722: finally
723: {
724: unlock();
725: }
726: }
727:
728: @Override
729: protected void cairoRectangle(long pointer, double x, double y,
730: double width, double height)
731: {
732: try
733: {
734: lock();
735: super.cairoRectangle(pointer, x, y, width, height);
736: }
737: finally
738: {
739: unlock();
740: }
741: }
742:
743: @Override
744: protected void cairoArc(long pointer, double x, double y,
745: double radius, double angle1, double angle2)
746: {
747: try
748: {
749: lock();
750: super.cairoArc(pointer, x, y, radius, angle1, angle2);
751: }
752: finally
753: {
754: unlock();
755: }
756: }
757:
758: @Override
759: protected void cairoSave(long pointer)
760: {
761: try
762: {
763: lock();
764: super.cairoSave(pointer);
765: }
766: finally
767: {
768: unlock();
769: }
770: }
771:
772: @Override
773: protected void cairoRestore(long pointer)
774: {
775: try
776: {
777: lock();
778: super.cairoRestore(pointer);
779: }
780: finally
781: {
782: unlock();
783: }
784: }
785:
786: @Override
787: protected void cairoNewPath(long pointer)
788: {
789: try
790: {
791: lock();
792: super.cairoNewPath(pointer);
793: }
794: finally
795: {
796: unlock();
797: }
798: }
799:
800: @Override
801: protected void cairoClosePath(long pointer)
802: {
803: try
804: {
805: lock();
806: super.cairoClosePath(pointer);
807: }
808: finally
809: {
810: unlock();
811: }
812: }
813:
814: @Override
815: protected void cairoMoveTo(long pointer, double x, double y)
816: {
817: try
818: {
819: lock();
820: super.cairoMoveTo(pointer, x, y);
821: }
822: finally
823: {
824: unlock();
825: }
826: }
827:
828: @Override
829: protected void cairoLineTo(long pointer, double x, double y)
830: {
831: try
832: {
833: lock();
834: super.cairoLineTo(pointer, x, y);
835: }
836: finally
837: {
838: unlock();
839: }
840: }
841:
842: @Override
843: protected void cairoCurveTo(long pointer, double x1, double y1, double x2,
844: double y2, double x3, double y3)
845: {
846: try
847: {
848: lock();
849: super.cairoCurveTo(pointer, x1, y1, x2, y2, x3, y3);
850: }
851: finally
852: {
853: unlock();
854: }
855: }
856:
857: @Override
858: protected void cairoStroke(long pointer)
859: {
860: try
861: {
862: lock();
863: super.cairoStroke(pointer);
864: }
865: finally
866: {
867: unlock();
868: }
869: }
870:
871: @Override
872: protected void cairoFill(long pointer, double alpha)
873: {
874: try
875: {
876: lock();
877: super.cairoFill(pointer, alpha);
878: }
879: finally
880: {
881: unlock();
882: }
883: }
884:
885: @Override
886: protected void cairoClip(long pointer)
887: {
888: try
889: {
890: lock();
891: super.cairoClip(pointer);
892: }
893: finally
894: {
895: unlock();
896: }
897: }
898:
899: @Override
900: protected void cairoResetClip(long pointer)
901: {
902: try
903: {
904: lock();
905: super.cairoResetClip(pointer);
906: }
907: finally
908: {
909: unlock();
910: }
911: }
912:
913: @Override
914: protected void cairoSetAntialias(long pointer, boolean aa)
915: {
916: try
917: {
918: lock();
919: super.cairoSetAntialias(pointer, aa);
920: }
921: finally
922: {
923: unlock();
924: }
925: }
926:
927: @Override
928: protected void drawCairoSurface(CairoSurface surface, AffineTransform tx,
929: double alpha, int interpolation)
930: {
931: try
932: {
933: lock();
934: super.drawCairoSurface(surface, tx, alpha, interpolation);
935: }
936: finally
937: {
938: unlock();
939: }
940: }
941: }