mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			942 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			942 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Java
		
	
	
	
/* ComponentGraphics.java --
 | 
						|
   Copyright (C) 2006  Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package gnu.java.awt.peer.gtk;
 | 
						|
 | 
						|
import gnu.classpath.Pointer;
 | 
						|
 | 
						|
import java.awt.AlphaComposite;
 | 
						|
import java.awt.Color;
 | 
						|
import java.awt.Graphics;
 | 
						|
import java.awt.Graphics2D;
 | 
						|
import java.awt.GraphicsConfiguration;
 | 
						|
import java.awt.Image;
 | 
						|
import java.awt.Point;
 | 
						|
import java.awt.Rectangle;
 | 
						|
import java.awt.Shape;
 | 
						|
import java.awt.Toolkit;
 | 
						|
import java.awt.font.GlyphVector;
 | 
						|
import java.awt.geom.AffineTransform;
 | 
						|
import java.awt.geom.Point2D;
 | 
						|
import java.awt.geom.Rectangle2D;
 | 
						|
import java.awt.image.BufferedImage;
 | 
						|
import java.awt.image.ColorModel;
 | 
						|
import java.awt.image.ImageObserver;
 | 
						|
import java.awt.image.ImageProducer;
 | 
						|
import java.awt.image.Raster;
 | 
						|
import java.awt.image.RenderedImage;
 | 
						|
import java.awt.image.WritableRaster;
 | 
						|
import java.util.Hashtable;
 | 
						|
 | 
						|
/**
 | 
						|
 * ComponentGraphics - context for drawing directly to a component,
 | 
						|
 * as this is an X drawable, it requires that we use GTK locks.
 | 
						|
 *
 | 
						|
 * This context draws directly to the drawable and requires xrender.
 | 
						|
 */
 | 
						|
public class ComponentGraphics extends CairoGraphics2D
 | 
						|
{
 | 
						|
  private static final boolean hasXRenderExtension = hasXRender();
 | 
						|
 | 
						|
  private GtkComponentPeer component;
 | 
						|
  protected long cairo_t;
 | 
						|
  private BufferedImage buffer, componentBuffer;
 | 
						|
 | 
						|
  private static ThreadLocal<Integer> hasLock = new ThreadLocal<Integer>();
 | 
						|
  private static Integer ONE = Integer.valueOf(1);
 | 
						|
 | 
						|
  ComponentGraphics()
 | 
						|
  {
 | 
						|
  }
 | 
						|
 | 
						|
  private ComponentGraphics(GtkComponentPeer component)
 | 
						|
  {
 | 
						|
    this.component = component;
 | 
						|
    cairo_t = initState(component);
 | 
						|
    setup( cairo_t );
 | 
						|
    Rectangle bounds = component.awtComponent.getBounds();
 | 
						|
    setClip( new Rectangle( 0, 0, bounds.width, bounds.height) );
 | 
						|
    setBackground(component.awtComponent.getBackground());
 | 
						|
    setColor(component.awtComponent.getForeground());
 | 
						|
  }
 | 
						|
 | 
						|
  private ComponentGraphics(ComponentGraphics cg)
 | 
						|
  {
 | 
						|
    component = cg.component;
 | 
						|
    cairo_t = initState(component);
 | 
						|
    copy( cg, cairo_t );
 | 
						|
    Rectangle bounds = component.awtComponent.getBounds();
 | 
						|
    setClip( new Rectangle( 0, 0, bounds.width, bounds.height) );
 | 
						|
    setBackground(component.awtComponent.getBackground());
 | 
						|
    setColor(component.awtComponent.getForeground());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a cairo_t for the component surface and return it.
 | 
						|
   */
 | 
						|
  private native long initState(GtkComponentPeer component);
 | 
						|
 | 
						|
  /**
 | 
						|
   * Obtain and hold a GDK lock, which is required for all drawing operations
 | 
						|
   * in this graphics context (since it is backed by an X surface).
 | 
						|
   *
 | 
						|
   * This method causes the GDK locking behaviour to be re-entrant.  No race
 | 
						|
   * conditions are caused since a ThreadLocal is used and each thread has its
 | 
						|
   * own lock counter.
 | 
						|
   */
 | 
						|
  private void lock()
 | 
						|
  {
 | 
						|
    Integer i = hasLock.get();
 | 
						|
    if (i == null)
 | 
						|
      {
 | 
						|
        start_gdk_drawing();
 | 
						|
        hasLock.set(ONE);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      hasLock.set(Integer.valueOf(i.intValue() + 1));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Release the re-entrant GDK lock.
 | 
						|
   */
 | 
						|
  private void unlock()
 | 
						|
  {
 | 
						|
    Integer i = hasLock.get();
 | 
						|
    if (i == null)
 | 
						|
      throw new IllegalStateException();
 | 
						|
    if (i == ONE)
 | 
						|
      {
 | 
						|
        hasLock.set(null);
 | 
						|
        end_gdk_drawing();
 | 
						|
      }
 | 
						|
    else if (i.intValue() == 2)
 | 
						|
      hasLock.set(ONE);
 | 
						|
    else
 | 
						|
      hasLock.set(Integer.valueOf(i.intValue() - 1));
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a cairo_t for a volatile image
 | 
						|
   */
 | 
						|
  protected native long initFromVolatile( long pixmapPtr);
 | 
						|
 | 
						|
  /**
 | 
						|
   * Grab lock
 | 
						|
   */
 | 
						|
  private native void start_gdk_drawing();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Release lock
 | 
						|
   */
 | 
						|
  private native void end_gdk_drawing();
 | 
						|
 | 
						|
  /**
 | 
						|
   * Query if the system has the XRender extension.
 | 
						|
   */
 | 
						|
  public static native boolean hasXRender();
 | 
						|
 | 
						|
  /**
 | 
						|
   * This is a utility method (used by GtkComponentPeer) for grabbing the
 | 
						|
   * image of a component.
 | 
						|
   */
 | 
						|
  private static native Pointer nativeGrab(GtkComponentPeer component);
 | 
						|
 | 
						|
  private native void copyAreaNative(GtkComponentPeer component, int x, int y,
 | 
						|
                                     int width, int height, int dx, int dy);
 | 
						|
 | 
						|
  private native void drawVolatile(GtkComponentPeer component,
 | 
						|
                                   long vimg, int x, int y,
 | 
						|
                                   int width, int height, int cx, int cy,
 | 
						|
                                   int cw, int ch);
 | 
						|
 | 
						|
  /**
 | 
						|
   * Not really related (moveme?). Utility method used by GtkComponent.
 | 
						|
   */
 | 
						|
  public static GtkImage grab( GtkComponentPeer component )
 | 
						|
  {
 | 
						|
    return new GtkImage( nativeGrab( component ) );
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns a Graphics2D object for a component, either an instance of this
 | 
						|
   * class (if xrender is supported), or a context which copies.
 | 
						|
   */
 | 
						|
  public static Graphics2D getComponentGraphics(GtkComponentPeer component)
 | 
						|
  {
 | 
						|
    if( hasXRenderExtension )
 | 
						|
      return new ComponentGraphics(component);
 | 
						|
 | 
						|
    Rectangle r = component.awtComponent.getBounds();
 | 
						|
    return new ComponentGraphicsCopy(r.width, r.height, component);
 | 
						|
  }
 | 
						|
 | 
						|
  public GraphicsConfiguration getDeviceConfiguration()
 | 
						|
  {
 | 
						|
    return component.getGraphicsConfiguration();
 | 
						|
  }
 | 
						|
 | 
						|
  public Graphics create()
 | 
						|
  {
 | 
						|
    return new ComponentGraphics(this);
 | 
						|
  }
 | 
						|
 | 
						|
  protected Rectangle2D getRealBounds()
 | 
						|
  {
 | 
						|
    return component.awtComponent.getBounds();
 | 
						|
  }
 | 
						|
 | 
						|
  public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy)
 | 
						|
  {
 | 
						|
    copyAreaNative(component, x, y, width, height, dx, dy);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Overloaded methods that do actual drawing need to enter the gdk threads
 | 
						|
   * and also do certain things before and after.
 | 
						|
   */
 | 
						|
  public void draw(Shape s)
 | 
						|
  {
 | 
						|
    if (comp == null || comp instanceof AlphaComposite)
 | 
						|
      super.draw(s);
 | 
						|
 | 
						|
    else
 | 
						|
      {
 | 
						|
        createBuffer();
 | 
						|
 | 
						|
        Graphics2D g2d = (Graphics2D)buffer.getGraphics();
 | 
						|
        g2d.setStroke(this.getStroke());
 | 
						|
        g2d.setColor(this.getColor());
 | 
						|
        g2d.draw(s);
 | 
						|
 | 
						|
        drawComposite(s.getBounds2D(), null);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public void fill(Shape s)
 | 
						|
  {
 | 
						|
    if (comp == null || comp instanceof AlphaComposite)
 | 
						|
      super.fill(s);
 | 
						|
 | 
						|
    else
 | 
						|
      {
 | 
						|
        createBuffer();
 | 
						|
 | 
						|
        Graphics2D g2d = (Graphics2D)buffer.getGraphics();
 | 
						|
        g2d.setPaint(this.getPaint());
 | 
						|
        g2d.setColor(this.getColor());
 | 
						|
        g2d.fill(s);
 | 
						|
 | 
						|
        drawComposite(s.getBounds2D(), null);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public void drawRenderedImage(RenderedImage image, AffineTransform xform)
 | 
						|
  {
 | 
						|
    if (comp == null || comp instanceof AlphaComposite)
 | 
						|
      super.drawRenderedImage(image, xform);
 | 
						|
 | 
						|
    else
 | 
						|
      {
 | 
						|
        createBuffer();
 | 
						|
 | 
						|
        Graphics2D g2d = (Graphics2D)buffer.getGraphics();
 | 
						|
        g2d.setRenderingHints(this.getRenderingHints());
 | 
						|
        g2d.drawRenderedImage(image, xform);
 | 
						|
 | 
						|
        drawComposite(buffer.getRaster().getBounds(), null);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  protected boolean drawImage(Image img, AffineTransform xform,
 | 
						|
                              Color bgcolor, ImageObserver obs)
 | 
						|
  {
 | 
						|
    boolean rv;
 | 
						|
    if (comp == null || comp instanceof AlphaComposite)
 | 
						|
      rv = super.drawImage(img, xform, bgcolor, obs);
 | 
						|
 | 
						|
    else
 | 
						|
      {
 | 
						|
        // Get buffered image of source
 | 
						|
        if( !(img instanceof BufferedImage) )
 | 
						|
          {
 | 
						|
            ImageProducer source = img.getSource();
 | 
						|
            if (source == null)
 | 
						|
              return false;
 | 
						|
            img = Toolkit.getDefaultToolkit().createImage(source);
 | 
						|
          }
 | 
						|
        BufferedImage bImg = (BufferedImage) img;
 | 
						|
 | 
						|
        // Find translated bounds
 | 
						|
        Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY());
 | 
						|
        Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(),
 | 
						|
                                        bImg.getHeight() + bImg.getMinY());
 | 
						|
        if (xform != null)
 | 
						|
          {
 | 
						|
            origin = xform.transform(origin, origin);
 | 
						|
            pt = xform.transform(pt, pt);
 | 
						|
          }
 | 
						|
 | 
						|
        // Create buffer and draw image
 | 
						|
        createBuffer();
 | 
						|
 | 
						|
        Graphics2D g2d = (Graphics2D)buffer.getGraphics();
 | 
						|
        g2d.setRenderingHints(this.getRenderingHints());
 | 
						|
        g2d.drawImage(img, xform, obs);
 | 
						|
 | 
						|
        // Perform compositing
 | 
						|
        rv = drawComposite(new Rectangle2D.Double(origin.getX(),
 | 
						|
                                                    origin.getY(),
 | 
						|
                                                    pt.getX(), pt.getY()),
 | 
						|
                           obs);
 | 
						|
      }
 | 
						|
    return rv;
 | 
						|
  }
 | 
						|
 | 
						|
  public void drawGlyphVector(GlyphVector gv, float x, float y)
 | 
						|
  {
 | 
						|
    if (comp == null || comp instanceof AlphaComposite)
 | 
						|
      super.drawGlyphVector(gv, x, y);
 | 
						|
 | 
						|
    else
 | 
						|
      {
 | 
						|
        createBuffer();
 | 
						|
 | 
						|
        Graphics2D g2d = (Graphics2D)buffer.getGraphics();
 | 
						|
        g2d.setPaint(this.getPaint());
 | 
						|
        g2d.setStroke(this.getStroke());
 | 
						|
        g2d.drawGlyphVector(gv, x, y);
 | 
						|
 | 
						|
        Rectangle2D bounds = gv.getLogicalBounds();
 | 
						|
        bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(),
 | 
						|
                                        bounds.getWidth(), bounds.getHeight());
 | 
						|
        drawComposite(bounds, null);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean drawImage(Image img, int x, int y, ImageObserver observer)
 | 
						|
  {
 | 
						|
    // If it is a GtkVolatileImage with an "easy" transform then
 | 
						|
    // draw directly. Always pass a BufferedImage to super to avoid
 | 
						|
    // deadlock (see Note in CairoGraphics.drawImage()).
 | 
						|
    if (img instanceof GtkVolatileImage)
 | 
						|
      {
 | 
						|
        GtkVolatileImage vimg = (GtkVolatileImage) img;
 | 
						|
        int type = transform.getType();
 | 
						|
        if ((type == AffineTransform.TYPE_IDENTITY
 | 
						|
             || type == AffineTransform.TYPE_TRANSLATION)
 | 
						|
             && (clip == null || clip instanceof Rectangle2D))
 | 
						|
          {
 | 
						|
            Rectangle2D r = (Rectangle2D) clip;
 | 
						|
            if (r == null)
 | 
						|
              r = getRealBounds();
 | 
						|
            x += transform.getTranslateX();
 | 
						|
            y += transform.getTranslateY();
 | 
						|
            drawVolatile(component, vimg.nativePointer,
 | 
						|
                         x, y, vimg.width, vimg.height,
 | 
						|
                         (int) (r.getX() + transform.getTranslateX()),
 | 
						|
                         (int) (r.getY() + transform.getTranslateY()),
 | 
						|
                         (int) r.getWidth(),
 | 
						|
                         (int) r.getHeight());
 | 
						|
            return true;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          return super.drawImage(vimg.getSnapshot(), x, y, observer);
 | 
						|
      }
 | 
						|
 | 
						|
    BufferedImage bimg;
 | 
						|
    if (img instanceof BufferedImage)
 | 
						|
      bimg = (BufferedImage) img;
 | 
						|
    else
 | 
						|
      {
 | 
						|
        ImageProducer source = img.getSource();
 | 
						|
        if (source == null)
 | 
						|
          return false;
 | 
						|
        bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source);
 | 
						|
      }
 | 
						|
    return super.drawImage(bimg, x, y, observer);
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean drawImage(Image img, int x, int y, int width, int height,
 | 
						|
                           ImageObserver observer)
 | 
						|
  {
 | 
						|
    // If it is a GtkVolatileImage with an "easy" transform then
 | 
						|
    // draw directly. Always pass a BufferedImage to super to avoid
 | 
						|
    // deadlock (see Note in CairoGraphics.drawImage()).
 | 
						|
    if (img instanceof GtkVolatileImage
 | 
						|
        && (clip == null || clip instanceof Rectangle2D))
 | 
						|
      {
 | 
						|
        GtkVolatileImage vimg = (GtkVolatileImage) img;
 | 
						|
        int type = transform.getType();
 | 
						|
        if ((type == AffineTransform.TYPE_IDENTITY
 | 
						|
             || type == AffineTransform.TYPE_TRANSLATION)
 | 
						|
             && (clip == null || clip instanceof Rectangle2D))
 | 
						|
          {
 | 
						|
            Rectangle2D r = (Rectangle2D) clip;
 | 
						|
            if (r == null)
 | 
						|
              r = getRealBounds();
 | 
						|
            x += transform.getTranslateX();
 | 
						|
            y += transform.getTranslateY();
 | 
						|
            drawVolatile(component, vimg.nativePointer,
 | 
						|
                         x, y, width, height,
 | 
						|
                         (int) (r.getX() + transform.getTranslateX()),
 | 
						|
                         (int) (r.getY() + transform.getTranslateY()),
 | 
						|
                         (int) r.getWidth(),
 | 
						|
                         (int) r.getHeight());
 | 
						|
            return true;
 | 
						|
          }
 | 
						|
        else
 | 
						|
          return super.drawImage(vimg.getSnapshot(), x, y,
 | 
						|
                                 width, height, observer);
 | 
						|
      }
 | 
						|
 | 
						|
    BufferedImage bimg;
 | 
						|
    img = AsyncImage.realImage(img, observer);
 | 
						|
    if (img instanceof BufferedImage)
 | 
						|
      bimg = (BufferedImage) img;
 | 
						|
    else
 | 
						|
      {
 | 
						|
        ImageProducer source = img.getSource();
 | 
						|
        if (source == null)
 | 
						|
          return false;
 | 
						|
        bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source);
 | 
						|
      }
 | 
						|
    return super.drawImage(bimg, x, y, width, height, observer);
 | 
						|
  }
 | 
						|
 | 
						|
  private boolean drawComposite(Rectangle2D bounds, ImageObserver observer)
 | 
						|
  {
 | 
						|
    // Clip source to visible areas that need updating
 | 
						|
    Rectangle2D clip = this.getClipBounds();
 | 
						|
    Rectangle2D.intersect(bounds, clip, bounds);
 | 
						|
    clip = new Rectangle(buffer.getMinX(), buffer.getMinY(),
 | 
						|
                         buffer.getWidth(), buffer.getHeight());
 | 
						|
    Rectangle2D.intersect(bounds, clip, bounds);
 | 
						|
 | 
						|
    BufferedImage buffer2 = buffer;
 | 
						|
    if (!bounds.equals(buffer2.getRaster().getBounds()))
 | 
						|
      buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(),
 | 
						|
                                    (int)bounds.getWidth(),
 | 
						|
                                    (int)bounds.getHeight());
 | 
						|
 | 
						|
    // Get destination clip to bounds
 | 
						|
    double[] points = new double[] {bounds.getX(), bounds.getY(),
 | 
						|
                                    bounds.getMaxX(), bounds.getMaxY()};
 | 
						|
    transform.transform(points, 0, points, 0, 2);
 | 
						|
 | 
						|
    Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1],
 | 
						|
                                                      points[2] - points[0],
 | 
						|
                                                      points[3] - points[1]);
 | 
						|
 | 
						|
    Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds);
 | 
						|
 | 
						|
    // Get current image on the component
 | 
						|
    GtkImage img = grab(component);
 | 
						|
    Graphics gr = componentBuffer.createGraphics();
 | 
						|
    gr.drawImage(img, 0, 0, null);
 | 
						|
    gr.dispose();
 | 
						|
 | 
						|
    BufferedImage cBuffer = componentBuffer;
 | 
						|
    if (!deviceBounds.equals(cBuffer.getRaster().getBounds()))
 | 
						|
      cBuffer = cBuffer.getSubimage((int)deviceBounds.getX(),
 | 
						|
                                    (int)deviceBounds.getY(),
 | 
						|
                                    (int)deviceBounds.getWidth(),
 | 
						|
                                    (int)deviceBounds.getHeight());
 | 
						|
 | 
						|
    // Perform actual composite operation
 | 
						|
    compCtx.compose(buffer2.getRaster(), cBuffer.getRaster(),
 | 
						|
                    cBuffer.getRaster());
 | 
						|
 | 
						|
    // This MUST call directly into the "action" method in CairoGraphics2D,
 | 
						|
    // not one of the wrappers, to ensure that the composite isn't processed
 | 
						|
    // more than once!
 | 
						|
    boolean rv = super.drawImage(cBuffer,
 | 
						|
                                 AffineTransform.getTranslateInstance(bounds.getX(),
 | 
						|
                                                                      bounds.getY()),
 | 
						|
                                 null, null);
 | 
						|
    return rv;
 | 
						|
  }
 | 
						|
 | 
						|
  private void createBuffer()
 | 
						|
  {
 | 
						|
    if (buffer == null)
 | 
						|
      {
 | 
						|
        WritableRaster rst;
 | 
						|
        rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(),
 | 
						|
                                                                                component.awtComponent.getHeight()),
 | 
						|
                                          new Point(0,0));
 | 
						|
 | 
						|
        buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
 | 
						|
                                   GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
 | 
						|
                                   new Hashtable());
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
        Graphics2D g2d = ((Graphics2D)buffer.getGraphics());
 | 
						|
 | 
						|
        g2d.setBackground(new Color(0,0,0,0));
 | 
						|
        g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight());
 | 
						|
      }
 | 
						|
 | 
						|
    if (componentBuffer == null)
 | 
						|
      {
 | 
						|
        WritableRaster rst;
 | 
						|
        rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(),
 | 
						|
                                                                                component.awtComponent.getHeight()),
 | 
						|
                                          new Point(0,0));
 | 
						|
 | 
						|
        componentBuffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst,
 | 
						|
                                            GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(),
 | 
						|
                                            new Hashtable());
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  protected ColorModel getNativeCM()
 | 
						|
  {
 | 
						|
    return GtkVolatileImage.gdkColorModel;
 | 
						|
  }
 | 
						|
 | 
						|
  /* --- START OVERRIDDEN NATIVE METHODS ----
 | 
						|
   * All native methods in CairoGraphics2D should be overridden here and
 | 
						|
   * enclosed in locks, since the cairo surface is backed by an X surface
 | 
						|
   * in this graphics context and the X surface requires external locking.
 | 
						|
   *
 | 
						|
   * We lock everything "just in case", since it's difficult to know which
 | 
						|
   * calls are and aren't thread-safe.  Overriding and locking the native
 | 
						|
   * methods allows superclass code in CairoGraphics2D to execute properly,
 | 
						|
   * without the need to override every single method.
 | 
						|
   *
 | 
						|
   * CAVEAT: if native code obtains a lock (using gdk_threads_enter(), not the
 | 
						|
   * lock() method provided here) and then calls back into Java and one of these
 | 
						|
   * methods ends up being called, we will deadlock.  The lock is only reentrant
 | 
						|
   * when called via our lock() method.
 | 
						|
   */
 | 
						|
 | 
						|
  /* These methods are already locked in the superclass CairoGraphics2D
 | 
						|
   * so they do not need to be overridden:
 | 
						|
   *
 | 
						|
   * public void disposeNative
 | 
						|
   *
 | 
						|
   * protected void cairoDrawGlyphVector
 | 
						|
   *
 | 
						|
   * protected void cairoSetFont
 | 
						|
   */
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected long init(long pointer)
 | 
						|
  {
 | 
						|
    long ret;
 | 
						|
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      ret = super.init(pointer);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void drawPixels(long pointer, int[] pixels, int w, int h,
 | 
						|
                            int stride, double[] i2u, double alpha,
 | 
						|
                            int interpolation)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.drawPixels(pointer, pixels, w, h, stride, i2u, alpha,
 | 
						|
                       interpolation);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void 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)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.setGradient(pointer, x1, y1, x2, y2, r1, g1, b1, a1, r2, g2, b2, a2,
 | 
						|
                        cyclic);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void setPaintPixels(long pointer, int[] pixels, int w, int h,
 | 
						|
                                int stride, boolean repeat, int x, int y)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.setPaintPixels(pointer, pixels, w, h, stride, repeat, x, y);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoSetMatrix(long pointer, double[] m)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoSetMatrix(pointer, m);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoScale(long pointer, double x, double y)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoScale(pointer, x, y);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoSetOperator(long pointer, int cairoOperator)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoSetOperator(pointer, cairoOperator);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoSetRGBAColor(long pointer, double red, double green,
 | 
						|
                                   double blue, double alpha)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoSetRGBAColor(pointer, red, green, blue, alpha);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoSetFillRule(long pointer, int cairoFillRule)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoSetFillRule(pointer, cairoFillRule);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoSetLine(long pointer, double width, int cap, int join,
 | 
						|
                              double miterLimit)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoSetLine(pointer, width, cap, join, miterLimit);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoSetDash(long pointer, double[] dashes, int ndash,
 | 
						|
                              double offset)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoSetDash(pointer, dashes, ndash, offset);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoRectangle(long pointer, double x, double y,
 | 
						|
                                double width, double height)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoRectangle(pointer, x, y, width, height);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoArc(long pointer, double x, double y,
 | 
						|
                          double radius, double angle1, double angle2)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoArc(pointer, x, y, radius, angle1, angle2);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoSave(long pointer)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoSave(pointer);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoRestore(long pointer)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoRestore(pointer);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoNewPath(long pointer)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoNewPath(pointer);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoClosePath(long pointer)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoClosePath(pointer);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoMoveTo(long pointer, double x, double y)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoMoveTo(pointer, x, y);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoLineTo(long pointer, double x, double y)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoLineTo(pointer, x, y);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoCurveTo(long pointer, double x1, double y1, double x2,
 | 
						|
                              double y2, double x3, double y3)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoCurveTo(pointer, x1, y1, x2, y2, x3, y3);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoStroke(long pointer)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoStroke(pointer);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoFill(long pointer, double alpha)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoFill(pointer, alpha);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoClip(long pointer)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoClip(pointer);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoResetClip(long pointer)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoResetClip(pointer);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void cairoSetAntialias(long pointer, boolean aa)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.cairoSetAntialias(pointer, aa);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  @Override
 | 
						|
  protected void drawCairoSurface(CairoSurface surface, AffineTransform tx,
 | 
						|
                                  double alpha, int interpolation)
 | 
						|
  {
 | 
						|
    try
 | 
						|
    {
 | 
						|
      lock();
 | 
						|
      super.drawCairoSurface(surface, tx, alpha, interpolation);
 | 
						|
    }
 | 
						|
    finally
 | 
						|
    {
 | 
						|
      unlock();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |