1 /* ComponentGraphics.java --
2    Copyright (C) 2006  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package gnu.java.awt.peer.gtk;
40 
41 import gnu.classpath.Pointer;
42 
43 import java.awt.AlphaComposite;
44 import java.awt.Color;
45 import java.awt.Graphics;
46 import java.awt.Graphics2D;
47 import java.awt.GraphicsConfiguration;
48 import java.awt.Image;
49 import java.awt.Point;
50 import java.awt.Rectangle;
51 import java.awt.Shape;
52 import java.awt.Toolkit;
53 import java.awt.font.GlyphVector;
54 import java.awt.geom.AffineTransform;
55 import java.awt.geom.Point2D;
56 import java.awt.geom.Rectangle2D;
57 import java.awt.image.BufferedImage;
58 import java.awt.image.ColorModel;
59 import java.awt.image.ImageObserver;
60 import java.awt.image.ImageProducer;
61 import java.awt.image.Raster;
62 import java.awt.image.RenderedImage;
63 import java.awt.image.WritableRaster;
64 import java.util.Hashtable;
65 
66 /**
67  * ComponentGraphics - context for drawing directly to a component,
68  * as this is an X drawable, it requires that we use GTK locks.
69  *
70  * This context draws directly to the drawable and requires xrender.
71  */
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 
ComponentGraphics()83   ComponentGraphics()
84   {
85   }
86 
ComponentGraphics(GtkComponentPeer component)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 
ComponentGraphics(ComponentGraphics cg)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   /**
110    * Creates a cairo_t for the component surface and return it.
111    */
initState(GtkComponentPeer component)112   private native long initState(GtkComponentPeer component);
113 
114   /**
115    * Obtain and hold a GDK lock, which is required for all drawing operations
116    * in this graphics context (since it is backed by an X surface).
117    *
118    * This method causes the GDK locking behaviour to be re-entrant.  No race
119    * conditions are caused since a ThreadLocal is used and each thread has its
120    * own lock counter.
121    */
lock()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   /**
135    * Release the re-entrant GDK lock.
136    */
unlock()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   /**
154    * Creates a cairo_t for a volatile image
155    */
initFromVolatile( long pixmapPtr)156   protected native long initFromVolatile( long pixmapPtr);
157 
158   /**
159    * Grab lock
160    */
start_gdk_drawing()161   private native void start_gdk_drawing();
162 
163   /**
164    * Release lock
165    */
end_gdk_drawing()166   private native void end_gdk_drawing();
167 
168   /**
169    * Query if the system has the XRender extension.
170    */
hasXRender()171   public static native boolean hasXRender();
172 
173   /**
174    * This is a utility method (used by GtkComponentPeer) for grabbing the
175    * image of a component.
176    */
nativeGrab(GtkComponentPeer component)177   private static native Pointer nativeGrab(GtkComponentPeer component);
178 
copyAreaNative(GtkComponentPeer component, int x, int y, int width, int height, int dx, int dy)179   private native void copyAreaNative(GtkComponentPeer component, int x, int y,
180                                      int width, int height, int dx, int dy);
181 
drawVolatile(GtkComponentPeer component, long vimg, int x, int y, int width, int height, int cx, int cy, int cw, int ch)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   /**
188    * Not really related (moveme?). Utility method used by GtkComponent.
189    */
grab( GtkComponentPeer component )190   public static GtkImage grab( GtkComponentPeer component )
191   {
192     return new GtkImage( nativeGrab( component ) );
193   }
194 
195   /**
196    * Returns a Graphics2D object for a component, either an instance of this
197    * class (if xrender is supported), or a context which copies.
198    */
getComponentGraphics(GtkComponentPeer component)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 
getDeviceConfiguration()208   public GraphicsConfiguration getDeviceConfiguration()
209   {
210     return component.getGraphicsConfiguration();
211   }
212 
create()213   public Graphics create()
214   {
215     return new ComponentGraphics(this);
216   }
217 
getRealBounds()218   protected Rectangle2D getRealBounds()
219   {
220     return component.awtComponent.getBounds();
221   }
222 
copyAreaImpl(int x, int y, int width, int height, int dx, int dy)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   /**
229    * Overloaded methods that do actual drawing need to enter the gdk threads
230    * and also do certain things before and after.
231    */
draw(Shape s)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 
fill(Shape s)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 
drawRenderedImage(RenderedImage image, AffineTransform xform)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 
drawImage(Image img, AffineTransform xform, Color bgcolor, ImageObserver obs)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         // Get buffered image of source
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         // Find translated bounds
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         // Create buffer and draw image
315         createBuffer();
316 
317         Graphics2D g2d = (Graphics2D)buffer.getGraphics();
318         g2d.setRenderingHints(this.getRenderingHints());
319         g2d.drawImage(img, xform, obs);
320 
321         // Perform compositing
322         rv = drawComposite(new Rectangle2D.Double(origin.getX(),
323                                                     origin.getY(),
324                                                     pt.getX(), pt.getY()),
325                            obs);
326       }
327     return rv;
328   }
329 
drawGlyphVector(GlyphVector gv, float x, float y)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 
drawImage(Image img, int x, int y, ImageObserver observer)351   public boolean drawImage(Image img, int x, int y, ImageObserver observer)
352   {
353     // If it is a GtkVolatileImage with an "easy" transform then
354     // draw directly. Always pass a BufferedImage to super to avoid
355     // deadlock (see Note in CairoGraphics.drawImage()).
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 
drawImage(Image img, int x, int y, int width, int height, ImageObserver observer)394   public boolean drawImage(Image img, int x, int y, int width, int height,
395                            ImageObserver observer)
396   {
397     // If it is a GtkVolatileImage with an "easy" transform then
398     // draw directly. Always pass a BufferedImage to super to avoid
399     // deadlock (see Note in CairoGraphics.drawImage()).
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 
drawComposite(Rectangle2D bounds, ImageObserver observer)441   private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
442   {
443     // Clip source to visible areas that need updating
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     // Get destination clip to bounds
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     // Get current image on the component
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     // Perform actual composite operation
481     compCtx.compose(buffer2.getRaster(), cBuffer.getRaster(),
482                     cBuffer.getRaster());
483 
484     // This MUST call directly into the "action" method in CairoGraphics2D,
485     // not one of the wrappers, to ensure that the composite isn't processed
486     // more than once!
487     boolean rv = super.drawImage(cBuffer,
488                                  AffineTransform.getTranslateInstance(bounds.getX(),
489                                                                       bounds.getY()),
490                                  null, null);
491     return rv;
492   }
493 
createBuffer()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 
getNativeCM()528   protected ColorModel getNativeCM()
529   {
530     return GtkVolatileImage.gdkColorModel;
531   }
532 
533   /* --- START OVERRIDDEN NATIVE METHODS ----
534    * All native methods in CairoGraphics2D should be overridden here and
535    * enclosed in locks, since the cairo surface is backed by an X surface
536    * in this graphics context and the X surface requires external locking.
537    *
538    * We lock everything "just in case", since it's difficult to know which
539    * calls are and aren't thread-safe.  Overriding and locking the native
540    * methods allows superclass code in CairoGraphics2D to execute properly,
541    * without the need to override every single method.
542    *
543    * CAVEAT: if native code obtains a lock (using gdk_threads_enter(), not the
544    * lock() method provided here) and then calls back into Java and one of these
545    * methods ends up being called, we will deadlock.  The lock is only reentrant
546    * when called via our lock() method.
547    */
548 
549   /* These methods are already locked in the superclass CairoGraphics2D
550    * so they do not need to be overridden:
551    *
552    * public void disposeNative
553    *
554    * protected void cairoDrawGlyphVector
555    *
556    * protected void cairoSetFont
557    */
558 
559   @Override
init(long pointer)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
drawPixels(long pointer, int[] pixels, int w, int h, int stride, double[] i2u, double alpha, int interpolation)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
setGradient(long pointer, double x1, double y1, double x2, double y2, int r1, int g1, int b1, int a1, int r2, int g2, int b2, int a2, boolean cyclic)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
setPaintPixels(long pointer, int[] pixels, int w, int h, int stride, boolean repeat, int x, int y)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
cairoSetMatrix(long pointer, double[] m)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
cairoScale(long pointer, double x, double y)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
cairoSetOperator(long pointer, int cairoOperator)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
cairoSetRGBAColor(long pointer, double red, double green, double blue, double alpha)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
cairoSetFillRule(long pointer, int cairoFillRule)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
cairoSetLine(long pointer, double width, int cap, int join, double miterLimit)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
cairoSetDash(long pointer, double[] dashes, int ndash, double offset)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
cairoRectangle(long pointer, double x, double y, double width, double height)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
cairoArc(long pointer, double x, double y, double radius, double angle1, double angle2)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
cairoSave(long pointer)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
cairoRestore(long pointer)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
cairoNewPath(long pointer)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
cairoClosePath(long pointer)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
cairoMoveTo(long pointer, double x, double y)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
cairoLineTo(long pointer, double x, double y)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
cairoCurveTo(long pointer, double x1, double y1, double x2, double y2, double x3, double y3)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
cairoStroke(long pointer)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
cairoFill(long pointer, double alpha)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
cairoClip(long pointer)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
cairoResetClip(long pointer)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
cairoSetAntialias(long pointer, boolean aa)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
drawCairoSurface(CairoSurface surface, AffineTransform tx, double alpha, int interpolation)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 }
942