From: Graydon Hoare Date: Wed, 17 Sep 2003 20:03:02 +0000 (+0000) Subject: GdkGraphics2D.java, [...]: New files. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1fe2d5fb0998455d5faec36e62a8919ad16c939f;p=gcc.git GdkGraphics2D.java, [...]: New files. 2003-09-17 Graydon Hoare * gnu/java/awt/peer/gtk/GdkGraphics2D.java, gnu/java/awt/peer/gtk/GdkPixbufDecoder.java, jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c, jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c: New files. From-SVN: r71475 --- diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 6c208a493cc..9b98128111b 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,11 @@ +2003-09-17 Graydon Hoare + + * gnu/java/awt/peer/gtk/GdkGraphics2D.java, + gnu/java/awt/peer/gtk/GdkPixbufDecoder.java, + jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c, + jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c: + New files. + 2003-09-16 Graydon Hoare * java/awt/BufferedImage.java (setData): Support non-component diff --git a/libjava/gnu/java/awt/peer/gtk/GdkGraphics2D.java b/libjava/gnu/java/awt/peer/gtk/GdkGraphics2D.java new file mode 100644 index 00000000000..11c0371bd08 --- /dev/null +++ b/libjava/gnu/java/awt/peer/gtk/GdkGraphics2D.java @@ -0,0 +1,1146 @@ +/* GdkGraphics2D.java + Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA +02111-1307 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 java.awt.*; +import java.awt.geom.*; +import java.awt.font.*; +import java.awt.color.*; +import java.awt.image.*; +import java.awt.image.renderable.*; + +import java.text.AttributedCharacterIterator; +import java.util.Map; +import java.lang.Integer; +import gnu.classpath.Configuration; + +public class GdkGraphics2D extends Graphics2D +{ + + ////////////////////////////////////// + ////// State Management Methods ////// + ////////////////////////////////////// + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("gtkpeer"); + } + initStaticState (); + } + native static void initStaticState (); + private final int native_state = GtkGenericPeer.getUniqueInteger(); + + private Paint paint; + private Stroke stroke; + private Color fg; + private Color bg; + private Shape clip; + private AffineTransform transform; + private GtkComponentPeer component; + private GdkFont font; + + native private int[] initState (GtkComponentPeer component); + native private void initState (int width, int height); + native private void copyState (GdkGraphics2D g); + native public void dispose (); + + public void finalize () + { + dispose(); + } + + public Graphics create () + { + return new GdkGraphics2D (this); + } + + public Graphics create (int x, int y, int width, int height) + { + return new GdkGraphics2D (width, height); + } + + GdkGraphics2D (GdkGraphics2D g) + { + paint = g.paint; + stroke = g.stroke; + + if (g.fg.getAlpha() != -1) + fg = new Color (g.fg.getRed (), g.fg.getGreen (), + g.fg.getBlue (), g.fg.getAlpha ()); + else + fg = new Color (g.fg.getRGB ()); + + if (g.bg.getAlpha() != -1) + bg = new Color(g.bg.getRed (), g.bg.getGreen (), + g.bg.getBlue (), g.bg.getAlpha ()); + else + bg = new Color (g.bg.getRGB ()); + + if (g.clip == null) + clip = null; + else + clip = new Rectangle (g.getClipBounds ()); + + if (g.transform == null) + transform = null; + else + transform = new AffineTransform (g.transform); + + component = g.component; + copyState (g); + + setColor (fg); + setClip (clip); + setTransform (transform); + } + + GdkGraphics2D (int width, int height) + { + initState (width, height); + bg = Color.black; + fg = Color.black; + transform = new AffineTransform (); + } + + GdkGraphics2D (GtkComponentPeer component) + { + this.component = component; + int rgb[] = initState (component); + fg = new Color (rgb[0], rgb[1], rgb[2]); + bg = new Color (rgb[3], rgb[4], rgb[5]); + transform = new AffineTransform (); + } + + + //////////////////////////////////// + ////// Native Drawing Methods ////// + //////////////////////////////////// + + // GDK drawing methods + private native void gdkDrawDrawable (GdkGraphics2D other, int x, int y); + + // drawing utility methods + private native void drawPixels (int pixels[], int w, int h, int stride); + private native void setTexturePixels (int pixels[], int w, int h, int stride); + private native void setGradient (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); + + // simple passthroughs to cairo + private native void cairoSave (); + private native void cairoRestore (); + private native void cairoSetMatrix (double m00, double m10, + double m01, double m11, + double m02, double m12); + private native void cairoSetOperator (int cairoOperator); + private native void cairoSetRGBColor (double red, double green, double blue); + private native void cairoSetAlpha (double alpha); + private native void cairoSetFillRule (int cairoFillRule); + private native void cairoSetLineWidth (double width); + private native void cairoSetLineCap (int cairoLineCap); + private native void cairoSetLineJoin (int cairoLineJoin); + private native void cairoSetDash (double dashes[], int ndash, double offset); + private native void cairoSetMiterLimit (double limit); + private native void cairoTranslate (double tx, double ty); + private native void cairoScale (double sx, double sy); + private native void cairoRotate (double angle); + private native void cairoNewPath (); + private native void cairoMoveTo (double x, double y); + private native void cairoLineTo (double x, double y); + private native void cairoCurveTo (double x1, double y1, + double x2, double y2, + double x3, double y3); + private native void cairoRelMoveTo (double dx, double dy); + private native void cairoRelLineTo (double dx, double dy); + private native void cairoRelCurveTo (double dx1, double dy1, + double dx2, double dy2, + double dx3, double dy3); + private native void cairoRectangle (double x, double y, + double width, double height); + private native void cairoClosePath (); + private native void cairoStroke (); + private native void cairoFill (); + private native void cairoClip (); + + + ///////////////////////////////////////////// + ////// General Drawing Support Methods ////// + ///////////////////////////////////////////// + + double x; + double y; + private void setPos (double nx, double ny) + { + x = nx; + y = ny; + } + + private void walkPath(PathIterator p) + { + double coords[] = new double[6]; + + cairoSetFillRule (p.getWindingRule ()); + for ( ; ! p.isDone (); p.next()) + { + int seg = p.currentSegment (coords); + switch(seg) + { + + case PathIterator.SEG_MOVETO: + setPos(coords[0], coords[1]); + cairoMoveTo (coords[0], coords[1]); + break; + + case PathIterator.SEG_LINETO: + setPos(coords[0], coords[1]); + cairoLineTo (coords[0], coords[1]); + break; + + case PathIterator.SEG_QUADTO: + + // splitting a quadratic bezier into a cubic: + // see: http://pfaedit.sourceforge.net/bezier.html + + double x1 = x + (2.0/3.0) * (coords[0] - x); + double y1 = y + (2.0/3.0) * (coords[1] - y); + + double x2 = x1 + (1.0/3.0) * (coords[2] - x); + double y2 = y1 + (1.0/3.0) * (coords[3] - y); + + setPos(coords[2], coords[3]); + cairoCurveTo (x1, y1, + x2, y2, + coords[2], coords[3]); + break; + + case PathIterator.SEG_CUBICTO: + setPos(coords[4], coords[5]); + cairoCurveTo (coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5]); + break; + + case PathIterator.SEG_CLOSE: + cairoClosePath (); + break; + } + } + } + + + ////////////////////////////////////////////////// + ////// Implementation of Graphics2D Methods ////// + ////////////////////////////////////////////////// + + public void draw (Shape s) + { + + if (stroke != null && + !(stroke instanceof BasicStroke)) + { + fill (stroke.createStrokedShape (s)); + return; + } + + cairoSave (); + cairoNewPath (); + if (s instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D)s; + cairoRectangle (r.getX (), r.getY (), r.getWidth (), r.getHeight ()); + } + else + walkPath (s.getPathIterator (null)); + cairoStroke (); + cairoRestore (); + } + + public void fill(Shape s) + { + cairoSave(); + cairoNewPath (); + if (s instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D)s; + cairoRectangle (r.getX (), r.getY (), r.getWidth (), r.getHeight ()); + } + else + walkPath (s.getPathIterator (null)); + cairoFill (); + cairoRestore (); + } + + public void clip (Shape s) + { + clip = s; + cairoNewPath (); + if (s instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D)s; + cairoRectangle (r.getX (), r.getY (), + r.getWidth (), r.getHeight ()); + } + else + walkPath (s.getPathIterator (null)); + cairoClosePath (); + cairoClip (); + } + + public Paint getPaint () + { + return paint; + } + + public AffineTransform getTransform () + { + return transform; + } + + public void setPaint (Paint p) + { + paint = p; + if (paint instanceof Color) + { + setColor ((Color) paint); + } + else if (paint instanceof TexturePaint) + { + TexturePaint tp = (TexturePaint) paint; + BufferedImage img = tp.getImage (); + int pixels[] = img.getRGB(0, 0, img.getWidth (), + img.getHeight (), null, + 0, img.getWidth ()); + setTexturePixels (pixels, img.getWidth (), + img.getHeight (), img.getWidth ()); + } + else if (paint instanceof GradientPaint) + { + GradientPaint gp = (GradientPaint) paint; + Point2D p1 = gp.getPoint1 (); + Point2D p2 = gp.getPoint2 (); + Color c1 = gp.getColor1 (); + Color c2 = gp.getColor2 (); + setGradient (p1.getX (), p1.getY (), + p2.getX (), p2.getY (), + c1.getRed (), c1.getGreen (), + c1.getBlue (), c1.getAlpha (), + c2.getRed (), c2.getGreen (), + c2.getBlue (), c2.getAlpha (), + gp.isCyclic ()); + } + else + throw new java.lang.UnsupportedOperationException (); + } + + public void setTransform (AffineTransform tx) + { + transform = tx; + if (transform != null) + { + double m[] = new double[6]; + transform.getMatrix (m); + cairoSetMatrix (m[0], m[1], m[2], m[3], m[4], m[5]); + } + } + + public void transform (AffineTransform tx) + { + if (transform == null) + transform = new AffineTransform (tx); + else + transform.concatenate (tx); + setTransform (transform); + } + + public void rotate(double theta) + { + if (transform != null) + transform.rotate (theta); + cairoRotate (theta); + } + + public void rotate(double theta, double x, double y) + { + if (transform != null) + transform.rotate (theta, x, y); + cairoTranslate (x, y); + cairoRotate (theta); + cairoTranslate (-x, -y); + } + + public void scale(double sx, double sy) + { + if (transform != null) + transform.scale (sx, sy); + cairoScale (sx, sy); + } + + public void translate (double tx, double ty) + { + if (transform != null) + transform.translate (tx, ty); + cairoTranslate (tx, ty); + } + + public void translate (int x, int y) + { + translate ((double) x, (double) y); + } + + public Stroke getStroke() + { + return stroke; + } + + public void setStroke (Stroke st) + { + stroke = st; + if (stroke instanceof BasicStroke) + { + BasicStroke bs = (BasicStroke) stroke; + cairoSetLineCap (bs.getEndCap()); + cairoSetLineWidth (bs.getLineWidth()); + cairoSetLineJoin (bs.getLineJoin()); + cairoSetMiterLimit (bs.getMiterLimit()); + float dashes[] = bs.getDashArray(); + if (dashes != null) + { + double double_dashes[] = new double[dashes.length]; + for (int i = 0; i < dashes.length; i++) + double_dashes[i] = dashes[i]; + cairoSetDash (double_dashes, double_dashes.length, + (double) bs.getDashPhase ()); + } + } + } + + + //////////////////////////////////////////////// + ////// Implementation of Graphics Methods ////// + //////////////////////////////////////////////// + + public void setPaintMode () + { + setComposite (java.awt.AlphaComposite.Xor); + } + + public void setXORMode (Color c) + { + setComposite (new BitwiseXorComposite (c)); + } + + public void setColor (Color c) + { + fg = c; + cairoSetRGBColor (fg.getRed() / 255.0, + fg.getGreen() / 255.0, + fg.getBlue() / 255.0); + cairoSetAlpha ((fg.getAlpha() & 255) / 255.0); + } + + public Color getColor () + { + return fg; + } + + public void clipRect (int x, int y, int width, int height) + { + // this is *slightly* different than all the other clip functions: it + // intersects the clip area with the new clip rectangle. obviously. of + // course, since Shape doesn't *have* any way of intersecting with a + // rectangle, we will promote the current clipping region to its + // bounding rectangle and then intersect with that. + if (clip == null) + { + cairoNewPath (); + cairoRectangle (x, y, width, height); + cairoClosePath (); + cairoClip (); + clip = new Rectangle (x, y, width, height); + } + else + { + clip (clip.getBounds ().intersection + (new Rectangle (x, y, width, height))); + } + } + + public Shape getClip () + { + return clip; + } + + public Rectangle getClipBounds () + { + if (clip == null) + return null; + else + return clip.getBounds (); + } + + public void setClip (int x, int y, int width, int height) + { + cairoNewPath (); + cairoRectangle (x, y, width, height); + cairoClosePath (); + cairoClip (); + clip = new Rectangle (x, y, width, height); + } + + public void setClip (Shape s) + { + clip (s); + } + + public void draw3DRect(int x, int y, int width, + int height, boolean raised) + { + Color std = fg; + Color light = std.brighter(); + Color dark = std.darker(); + + if (!raised) + { + Color t = light; + light = dark; + dark = t; + } + + double x1 = (double) x; + double x2 = (double) x + width; + + double y1 = (double) y; + double y2 = (double) y + height; + + cairoSave (); + + cairoNewPath (); + setColor (light); + cairoMoveTo (x1, y1); + cairoLineTo (x2, y1); + cairoLineTo (x2, y2); + cairoStroke (); + + cairoNewPath (); + setColor (dark); + cairoMoveTo (x1, y1); + cairoLineTo (x1, y2); + cairoLineTo (x2, y2); + cairoStroke (); + + cairoRestore (); + setColor (std); + + } + + public void fill3DRect(int x, int y, int width, + int height, boolean raised) + { + double step = 1.0; + if (stroke != null && stroke instanceof BasicStroke) + { + BasicStroke bs = (BasicStroke) stroke; + step = bs.getLineWidth(); + } + + Color bright = fg.brighter (); + Color dark = fg.darker (); + + draw3DRect (x, y, width, height, raised); + + cairoSave (); + cairoTranslate (step/2.0, step/2.0); + cairoNewPath (); + cairoRectangle ((double) x, (double) y, + ((double) width) - step, + ((double) height) - step ); + cairoClosePath (); + cairoFill (); + cairoRestore (); + } + + + public void drawRect (int x, int y, int width, int height) + { + draw(new Rectangle (x, y, width, height)); + } + + public void fillRect (int x, int y, int width, int height) + { + fill(new Rectangle (x, y, width, height)); + } + + public void clearRect (int x, int y, int width, int height) + { + cairoSave (); + cairoSetRGBColor (bg.getRed() / 255.0, + bg.getGreen() / 255.0, + bg.getBlue() / 255.0); + cairoSetAlpha (1.0); + cairoNewPath (); + cairoRectangle (x, y, width, height); + cairoClosePath (); + cairoFill (); + cairoRestore (); + } + + public void setBackground(Color c) + { + bg = c; + } + + + public Color getBackground() + { + return bg; + } + + + private void doPolygon(int[] xPoints, int[] yPoints, int nPoints, + boolean close, boolean fill) + { + if (nPoints < 1) + return; + GeneralPath gp = new GeneralPath (); + gp.moveTo ((float)xPoints[0], (float)yPoints[0]); + for (int i = 1; i < nPoints; i++) + gp.lineTo ((float)xPoints[i], (float)yPoints[i]); + + if (close) + gp.closePath (); + + Shape sh = gp; + if (fill == false && + stroke != null && + !(stroke instanceof BasicStroke)) + { + sh = stroke.createStrokedShape (gp); + fill = true; + } + + if (fill) + fill (sh); + else + draw (sh); + } + + public void drawLine (int x1, int y1, int x2, int y2) + { + int xp[] = new int[2]; + int yp[] = new int[2]; + + xp[0] = x1; + xp[1] = x2; + yp[0] = y1; + yp[1] = y2; + + doPolygon (xp, yp, 2, false, false); + } + + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + doPolygon (xPoints, yPoints, nPoints, true, true); + } + + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + doPolygon (xPoints, yPoints, nPoints, true, false); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) + { + doPolygon (xPoints, yPoints, nPoints, false, false); + } + + private boolean drawRaster (ColorModel cm, Raster r) + { + if (r == null) + return false; + + SampleModel sm = r.getSampleModel (); + DataBuffer db = r.getDataBuffer (); + + if (db == null || sm == null) + return false; + + if (cm == null) + cm = ColorModel.getRGBdefault (); + + int pixels[] = null; + + if (sm.getDataType () == DataBuffer.TYPE_INT && + db instanceof DataBufferInt && + db.getNumBanks () == 1) + { + // single bank, ARGB-ints buffer in sRGB space + DataBufferInt dbi = (DataBufferInt)db; + pixels = dbi.getData (); + } + else + pixels = r.getPixels (0, 0, r.getWidth (), r.getHeight (), pixels); + + ColorSpace cs = cm.getColorSpace (); + if (cs != null && + cs.getType () != ColorSpace.CS_sRGB) + { + int pixels2[] = new int[pixels.length]; + for (int i = 0; i < pixels2.length; i++) + pixels2[i] = cm.getRGB (pixels[i]); + pixels = pixels2; + } + + cairoSave (); + cairoTranslate (x, y); + drawPixels (pixels, r.getWidth (), r.getHeight (), r.getWidth ()); + cairoRestore (); + return true; + } + + public boolean drawImage (Image img, int x, int y, + ImageObserver observer) + { + if (img instanceof GtkOffScreenImage && + img.getGraphics () instanceof GdkGraphics2D && + (transform == null || transform.isIdentity ())) + { + // we are being asked to flush a double buffer from Gdk + GdkGraphics2D g2 = (GdkGraphics2D) img.getGraphics (); + gdkDrawDrawable (g2, x, y); + return true; + } + else + { + if (img instanceof BufferedImage) + { + // draw an image which has actually been loaded into memory fully + BufferedImage b = (BufferedImage) img; + return drawRaster (b.getColorModel (), b.getData ()); + } + else + { + // begin progressive loading in a separate thread + new PainterThread (this, img); + return false; + } + } + } + + + //////////////////////////////////////// + ////// Supporting Private Classes ////// + //////////////////////////////////////// + + private class PainterThread implements Runnable, ImageConsumer + { + + // this is a helper which is spun off when someone tries to do + // Graphics2D.drawImage on an image we cannot determine to be either + // one of our own offscreen images or a BufferedImage; that is, when + // someone wants to draw an image which is possibly still loading over + // a network or something. you run it in a separate thread and it + // writes through to the underlying Graphics2D as pixels becomg + // available. + + GdkGraphics2D gr; + Image image; + ColorModel defaultModel; + + public PainterThread (GdkGraphics2D g, Image im) + { + image = im; + this.gr = (GdkGraphics2D) g.create (); + new Thread (this).start (); + } + + public void imageComplete (int status) + { + } + + public void setColorModel (ColorModel model) + { + defaultModel = model; + } + + public void setDimensions (int width, int height) + { + } + + public void setHints (int hintflags) + { + } + + public void setPixels (int x, int y, int w, int h, ColorModel model, + byte[] pixels, int off, int scansize) + { + } + + public void setPixels (int x, int y, int w, int h, ColorModel model, + int[] pixels, int off, int scansize) + { + gr.cairoSave (); + gr.cairoTranslate (x, y); + + if (model == null) + model = defaultModel; + + int pixels2[]; + if (model != null) + { + pixels2 = new int[pixels.length]; + for (int yy = 0; yy < h; yy++) + for (int xx = 0; xx < w; xx++) + { + int i = yy * scansize + xx; + pixels2[i] = model.getRGB (pixels[i]); + } + } + else + pixels2 = pixels; + + gr.drawPixels (pixels2, w, h, scansize); + gr.cairoRestore (); + } + + public void setProperties (java.util.Hashtable props) + { + } + + public void run () + { + image.getSource ().startProduction (this); + gr.dispose (); + } + } + + + private class BitwiseXorComposite implements Composite + { + // this is a special class which does a bitwise XOR composite, for + // backwards compatibility sake. it does *not* implement the + // porter-duff XOR operator. the porter-duff XOR is unrelated to + // bitwise XOR; it just happens to have a similar name but it + // represents a desire to composite the exclusive or of overlapping + // subpixel regions. bitwise XOR is for drawing "highlights" such as + // cursors (in a cheap oldskool bitblit fashion) by inverting colors + // temporarily and then inverting them back. + + Color xorColor; + + class BitwiseXorCompositeContext implements CompositeContext + { + ColorModel srcColorModel; + ColorModel dstColorModel; + + public BitwiseXorCompositeContext (ColorModel s, + ColorModel d) + { + srcColorModel = s; + dstColorModel = d; + } + + public void dispose () + { + } + + public void compose (Raster src, + Raster dstIn, + WritableRaster dstOut) + { + Rectangle srcRect = src.getBounds (); + Rectangle dstInRect = dstIn.getBounds (); + Rectangle dstOutRect = dstOut.getBounds (); + + int xp = xorColor.getRGB (); + int x = 0, y = 0; + int w = Math.min (Math.min (srcRect.width, dstOutRect.width), dstInRect.width); + int h = Math.min (Math.min (srcRect.height, dstOutRect.height), dstInRect.height); + Object srcPix = null, dstPix = null; + + for (y = 0; y < h; y++) + for (x = 0; x < w; x++) + { + srcPix = src.getDataElements (x + srcRect.x, y + srcRect.y, srcPix); + dstPix = dstIn.getDataElements (x + dstInRect.x, y + dstInRect.y, dstPix); + int sp = srcColorModel.getRGB (srcPix); + int dp = dstColorModel.getRGB (dstPix); + int rp = sp ^ xp ^ dp; + dstOut.setDataElements (x + dstOutRect.x, y + dstOutRect.y, + dstColorModel.getDataElements (rp, null)); + } + } + } + + public BitwiseXorComposite (Color c) + { + xorColor = c; + } + + public CompositeContext createContext (ColorModel srcColorModel, + ColorModel dstColorModel, + RenderingHints hints) + { + return new BitwiseXorCompositeContext (srcColorModel, dstColorModel); + } + } + + + /////////////////////////////////////////////// + ////// Unimplemented Stubs and Overloads ////// + /////////////////////////////////////////////// + + public boolean drawImage(Image image, + AffineTransform xform, + ImageObserver obs) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawImage(BufferedImage image, + BufferedImageOp op, + int x, + int y) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawRenderedImage(RenderedImage image, + AffineTransform xform) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawRenderableImage(RenderableImage image, + AffineTransform xform) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawString(String text, float x, float y) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawString(AttributedCharacterIterator iterator, + float x, float y) + { + throw new java.lang.UnsupportedOperationException (); + } + + public boolean hit(Rectangle rect, Shape text, + boolean onStroke) + { + throw new java.lang.UnsupportedOperationException (); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + throw new java.lang.UnsupportedOperationException (); + } + + public void setComposite(Composite comp) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void setRenderingHint(RenderingHints.Key hintKey, + Object hintValue) + { + throw new java.lang.UnsupportedOperationException (); + } + + public Object getRenderingHint(RenderingHints.Key hintKey) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void setRenderingHints(Map hints) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void addRenderingHints(Map hints) + { + throw new java.lang.UnsupportedOperationException (); + } + + public RenderingHints getRenderingHints() + { + throw new java.lang.UnsupportedOperationException (); + } + + public void shear(double shearX, double shearY) + { + throw new java.lang.UnsupportedOperationException (); + } + + public Composite getComposite() + { + throw new java.lang.UnsupportedOperationException (); + } + + public FontRenderContext getFontRenderContext () + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawGlyphVector (GlyphVector g, float x, float y) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void copyArea (int x, int y, int width, int height, int dx, int dy) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawArc (int x, int y, int width, int height, + int startAngle, int arcAngle) + { + throw new java.lang.UnsupportedOperationException (); + } + + public boolean drawImage (Image img, int x, int y, Color bgcolor, + ImageObserver observer) + { + throw new java.lang.UnsupportedOperationException (); + } + + public boolean drawImage (Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + throw new java.lang.UnsupportedOperationException (); + } + + public boolean drawImage (Image img, int x, int y, int width, int height, + ImageObserver observer) + { + throw new java.lang.UnsupportedOperationException (); + } + + public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) + { + throw new java.lang.UnsupportedOperationException (); + } + + public boolean drawImage (Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawOval(int x, int y, int width, int height) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawString (String str, int x, int y) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void drawString (AttributedCharacterIterator ci, int x, int y) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void fillArc (int x, int y, int width, int height, + int startAngle, int arcAngle) + { + cairoNewPath (); + walkPath (new Arc2D.Double((double)x, (double)y, + (double)width, (double)height, + (double)startAngle, (double)arcAngle, + Arc2D.PIE).getPathIterator (null)); + cairoClosePath (); + cairoFill (); + } + + public void fillOval(int x, int y, int width, int height) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void fillRoundRect (int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + throw new java.lang.UnsupportedOperationException (); + } + + public Font getFont () + { + throw new java.lang.UnsupportedOperationException (); + } + + public FontMetrics getFontMetrics () + { + throw new java.lang.UnsupportedOperationException (); + } + + public FontMetrics getFontMetrics (Font f) + { + throw new java.lang.UnsupportedOperationException (); + } + + public void setFont (Font f) + { + if (f instanceof GdkFont) + font = (GdkFont) f; + else + font = new GdkFont (f.getAttributes ()); + } + + public String toString() + { + throw new java.lang.UnsupportedOperationException (); + } + +} diff --git a/libjava/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java b/libjava/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java new file mode 100644 index 00000000000..55f3338006e --- /dev/null +++ b/libjava/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java @@ -0,0 +1,217 @@ +/* GdkPixbufDecoder.java -- Image data decoding object + Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 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 java.awt.image.*; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Vector; +import java.util.Hashtable; +import gnu.classpath.Configuration; + +public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder +{ + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("gtkpeer"); + } + initStaticState (); + } + native static void initStaticState (); + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + // the current set of ImageConsumers for this decoder + Vector curr; + + // interface to GdkPixbuf + native void initState (); + native void pumpBytes (byte bytes[], int len); + native void finish (); + + // gdk-pixbuf provids data in RGBA format + static final ColorModel cm = new DirectColorModel (32, 0xff000000, + 0x00ff0000, + 0x0000ff00, + 0x000000ff); + public GdkPixbufDecoder (String filename) + { + super (filename); + initState (); + } + + public GdkPixbufDecoder (URL url) + { + super (url); + initState (); + } + + // called back by native side + void areaPrepared (int width, int height) + { + + if (curr == null) + return; + + for (int i = 0; i < curr.size (); i++) + { + ImageConsumer ic = (ImageConsumer) curr.elementAt (i); + ic.setDimensions (width, height); + ic.setColorModel (cm); + ic.setHints (ImageConsumer.RANDOMPIXELORDER); + } + } + + // called back by native side + void areaUpdated (int x, int y, int width, int height, + int pixels[], int scansize) + { + if (curr == null) + return; + + for (int i = 0; i < curr.size (); i++) + { + ImageConsumer ic = (ImageConsumer) curr.elementAt (i); + ic.setPixels (x, y, width, height, cm, pixels, 0, scansize); + } + } + + // called from an async image loader of one sort or another, this method + // repeatedly reads bytes from the input stream and passes them through a + // GdkPixbufLoader using the native method pumpBytes. pumpBytes in turn + // decodes the image data and calls back areaPrepared and areaUpdated on + // this object, feeding back decoded pixel blocks, which we pass to each + // of the ImageConsumers in the provided Vector. + + void produce (Vector v, FileInputStream is) throws IOException + { + curr = v; + + byte bytes[] = new byte[4096]; + int len = 0; + while ((len = is.read (bytes)) != -1) + pumpBytes (bytes, len); + + for (int i = 0; i < curr.size (); i++) + { + ImageConsumer ic = (ImageConsumer) curr.elementAt (i); + ic.imageComplete (ImageConsumer.STATICIMAGEDONE); + } + + curr = null; + } + + // remaining helper class and static method is a convenience for the Gtk + // peers, for loading a BufferedImage in off a disk file. one would think + // this ought to be fairly straightforward, but it does not appear + // anywhere else I can find. + + private class BufferedImageBuilder implements ImageConsumer + { + BufferedImage bufferedImage; + ColorModel defaultModel; + + public BufferedImage getBufferedImage() + { + return bufferedImage; + } + + public void setDimensions(int width, int height) + { + bufferedImage = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB); + } + + public void setProperties(Hashtable props) {} + + public void setColorModel(ColorModel model) + { + defaultModel = model; + } + + public void setHints(int flags) {} + + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, + int offset, int scansize) + { + } + + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, + int offset, int scansize) + { + if (bufferedImage != null) + { + + if (model == null) + model = defaultModel; + + int pixels2[]; + if (model != null) + { + pixels2 = new int[pixels.length]; + for (int yy = 0; yy < h; yy++) + for (int xx = 0; xx < w; xx++) + { + int i = yy * scansize + xx; + pixels2[i] = model.getRGB (pixels[i]); + } + } + else + pixels2 = pixels; + + bufferedImage.setRGB (x, y, w, h, pixels2, offset, scansize); + } + } + + public void imageComplete(int status) {} + } + + public static BufferedImage createBufferedImage (String filename) + { + BufferedImageBuilder bb = new BufferedImageBuilder (); + GdkPixbufDecoder dec = new GdkPixbufDecoder (filename); + dec.startProduction (bb); + return bb.getBufferedImage (); + } + +} diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c new file mode 100644 index 00000000000..04eb2e5a524 --- /dev/null +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c @@ -0,0 +1,1069 @@ +/* gnu_java_awt_peer_gtk_GdkGraphics2d.c + Copyright (C) 2003 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., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 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. */ + +#include "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GdkGraphics2D.h" +#include +#include +#include + +#include +#include + +#include +#include +#include + +struct state_table *native_graphics2d_state_table; + +#define NSA_G2D_INIT(env, clazz) \ + native_graphics2d_state_table = init_state_table (env, clazz) + +#define NSA_GET_G2D_PTR(env, obj) \ + get_state (env, obj, native_graphics2d_state_table) + +#define NSA_SET_G2D_PTR(env, obj, ptr) \ + set_state (env, obj, native_graphics2d_state_table, (void *)ptr) + +#define NSA_DEL_G2D_PTR(env, obj) \ + remove_state_slot (env, obj, native_graphics2d_state_table) + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initStaticState + (JNIEnv *env, jclass clazz) +{ + NSA_G2D_INIT (env, clazz); +} + +/* these public final constants are part of the java2d public API, so we + write them explicitly here to save fetching them from the constant pool + all the time. */ + +#ifndef min +#define min(x,y) ((x) < (y) ? (x) : (y)) +#endif + +enum java_awt_alpha_composite_rule + { + java_awt_alpha_composite_CLEAR = 1, + java_awt_alpha_composite_SRC = 2, + java_awt_alpha_composite_SRC_OVER = 3, + java_awt_alpha_composite_DST_OVER = 4, + java_awt_alpha_composite_SRC_IN = 5, + java_awt_alpha_composite_DST_IN = 6, + java_awt_alpha_composite_SRC_OUT = 7, + java_awt_alpha_composite_DST_OUT = 8, + java_awt_alpha_composite_DST = 9, + java_awt_alpha_composite_SRC_ATOP = 10, + java_awt_alpha_composite_DST_ATOP = 11, + java_awt_alpha_composite_XOR = 12 + }; + +enum java_awt_basic_stroke_join_rule + { + java_awt_basic_stroke_JOIN_MITER = 0, + java_awt_basic_stroke_JOIN_ROUND = 1, + java_awt_basic_stroke_JOIN_BEVEL = 2 + }; + +enum java_awt_basic_stroke_cap_rule + { + java_awt_basic_stroke_CAP_BUTT = 0, + java_awt_basic_stroke_CAP_ROUND = 1, + java_awt_basic_stroke_CAP_SQUARE = 2 + }; + +enum java_awt_geom_path_iterator_winding_rule + { + java_awt_geom_path_iterator_WIND_EVEN_ODD = 0, + java_awt_geom_path_iterator_WIND_NON_ZERO = 1 + }; + + +static void +grab_current_drawable (GtkWidget *widget, GdkDrawable **draw, GdkWindow **win) +{ + g_assert (widget != NULL); + g_assert (draw != NULL); + g_assert (win != NULL); + + if (GTK_IS_WINDOW (widget)) + { + *win = find_gtk_layout (widget)->bin_window; + } + else if (GTK_IS_LAYOUT (widget)) + { + *win = GTK_LAYOUT (widget)->bin_window; + } + else + { + *win = widget->window; + } + + *draw = *win; + gdk_window_get_internal_paint_info (*win, draw, 0, 0); + g_object_ref (*draw); +} + + +static int +x_server_has_render_extension (void) +{ + int ev = 0, err = 0; + return (int) XRenderQueryExtension (GDK_DISPLAY (), &ev, &err); +} + + +static void +init_graphics2d_as_pixbuf (struct graphics2d *gr) +{ + gint width, height; + gint bits_per_sample = 8; + gint total_channels = 4; + gboolean has_alpha = TRUE; + + g_assert (gr != NULL); + g_assert (gr->drawable != NULL); + + if (gr->debug) printf ("initializing graphics2d as pixbuf\n"); + gdk_drawable_get_size (gr->drawable, &width, &height); + gr->drawbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, + has_alpha, bits_per_sample, + width, height); + g_assert (gr->drawbuf != NULL); + g_assert (gdk_pixbuf_get_bits_per_sample (gr->drawbuf) == bits_per_sample); + g_assert (gdk_pixbuf_get_n_channels (gr->drawbuf) == total_channels); + + gr->surface = cairo_surface_create_for_image (gdk_pixbuf_get_pixels (gr->drawbuf), + CAIRO_FORMAT_ARGB32, + gdk_pixbuf_get_width (gr->drawbuf), + gdk_pixbuf_get_height (gr->drawbuf), + gdk_pixbuf_get_rowstride (gr->drawbuf)); + g_assert (gr->surface != NULL); + g_assert (gr->cr != NULL); + cairo_set_target_surface (gr->cr, gr->surface); +} + +static void +init_graphics2d_as_renderable (struct graphics2d *gr) +{ + Drawable draw; + Display * dpy; + Visual * vis; + + g_assert (gr != NULL); + g_assert (gr->drawable != NULL); + + gr->drawbuf = NULL; + + if (gr->debug) printf ("initializing graphics2d as renderable\n"); + draw = gdk_x11_drawable_get_xid (gr->drawable); + + dpy = gdk_x11_drawable_get_xdisplay (gr->drawable); + g_assert (dpy != NULL); + + vis = gdk_x11_visual_get_xvisual (gdk_drawable_get_visual (gr->drawable)); + g_assert (vis != NULL); + + gr->surface = cairo_surface_create_for_drawable (dpy, draw, vis, + CAIRO_FORMAT_ARGB32, + DefaultColormap (dpy, DefaultScreen (dpy))); + g_assert (gr->surface != NULL); + g_assert (gr->cr != NULL); + cairo_set_target_surface (gr->cr, gr->surface); +} + +static void +begin_drawing_operation (struct graphics2d * gr) +{ + gdk_threads_enter (); + if (gr->drawbuf) + { + + gint drawable_width, drawable_height; + gint pixbuf_width, pixbuf_height; + gint width, height; + + gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height); + pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf); + pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf); + width = min (drawable_width, pixbuf_width); + height = min (drawable_height, pixbuf_height); + + gdk_pixbuf_get_from_drawable (gr->drawbuf, /* destination pixbuf */ + gr->drawable, + NULL, /* colormap */ + 0, 0, 0, 0, + width, height); + + if (gr->debug) printf ("copied (%d, %d) pixels from GDK drawable to pixbuf\n", + width, height); + } +} + +static void +end_drawing_operation (struct graphics2d * gr) +{ + if (gr->drawbuf) + { + gint drawable_width, drawable_height; + gint pixbuf_width, pixbuf_height; + gint width, height; + + gdk_drawable_get_size (gr->drawable, &drawable_width, &drawable_height); + pixbuf_width = gdk_pixbuf_get_width (gr->drawbuf); + pixbuf_height = gdk_pixbuf_get_height (gr->drawbuf); + width = min (drawable_width, pixbuf_width); + height = min (drawable_height, pixbuf_height); + + gdk_draw_pixbuf (gr->drawable, NULL, gr->drawbuf, + 0, 0, 0, 0, + width, height, + GDK_RGB_DITHER_NORMAL, 0, 0); + + if (gr->debug) printf ("copied (%d, %d) pixels from pixbuf to GDK drawable\n", + width, height); + } + gdk_threads_leave (); +} + + +static void +update_pattern_transform (struct graphics2d *gr) +{ + double a, b, c, d, tx, ty; + cairo_matrix_t *mat = NULL; + + g_assert (gr != NULL); + if (gr->pattern == NULL) + return; + + return; + /* temporarily disabled: ambiguous behavior */ + /* cairo_get_matrix (gr->cr, &a, &b, &c, &d, &tx, &ty); */ + mat = cairo_matrix_create (); + g_assert (mat != NULL); + cairo_matrix_set_affine (mat, a, b, c, d, tx, ty); + cairo_surface_set_matrix (gr->pattern, mat); + cairo_matrix_destroy (mat); +} + +static void +check_for_debug (struct graphics2d *gr) +{ + gr->debug = (gboolean)(getenv("DEBUGJ2D") != NULL); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_copyState + (JNIEnv *env, jobject obj, jobject old) +{ + struct graphics2d *g = NULL, *g_old = NULL; + + g = (struct graphics2d *) malloc (sizeof (struct graphics2d)); + g_assert (g != NULL); + memset (g, 0, sizeof(struct graphics2d)); + + g_old = (struct graphics2d *) NSA_GET_G2D_PTR (env, old); + g_assert (g_old != NULL); + + g->drawable = g_old->drawable; + g->debug = g_old->debug; + + gdk_threads_enter (); + g_object_ref (g->drawable); + + g->cr = cairo_create(); + g_assert (g->cr != NULL); + + if (x_server_has_render_extension ()) + init_graphics2d_as_renderable (g); + else + init_graphics2d_as_pixbuf (g); + + cairo_surface_set_filter (g->surface, CAIRO_FILTER_BILINEAR); + + gdk_threads_leave (); + + NSA_SET_G2D_PTR (env, obj, g); +} + + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__II + (JNIEnv *env, jobject obj, jint width, jint height) +{ + struct graphics2d *gr; + + gdk_threads_enter (); + + gr = (struct graphics2d *) malloc (sizeof (struct graphics2d)); + g_assert (gr != NULL); + memset (gr, 0, sizeof(struct graphics2d)); + + check_for_debug (gr); + + if (gr->debug) printf ("constructing offscreen drawable of size (%d,%d)\n", + width, height); + + gr->drawable = (GdkDrawable *) gdk_pixmap_new (NULL, width, height, + gdk_rgb_get_visual ()->depth); + g_assert (gr->drawable != NULL); + + gr->cr = cairo_create(); + g_assert (gr->cr != NULL); + + if (x_server_has_render_extension ()) + init_graphics2d_as_renderable (gr); + else + init_graphics2d_as_pixbuf (gr); + + gdk_threads_leave (); + if (gr->debug) printf ("constructed offscreen drawable of size (%d,%d)\n", + width, height); + NSA_SET_G2D_PTR (env, obj, gr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_gdkDrawDrawable + (JNIEnv *env, jobject self, jobject other, jint x, jint y) +{ + struct graphics2d *src = NULL, *dst = NULL; + gint s_height, s_width, d_height, d_width, height, width; + GdkGC *gc; + + src = (struct graphics2d *)NSA_GET_G2D_PTR (env, other); + dst = (struct graphics2d *)NSA_GET_G2D_PTR (env, self); + g_assert (src != NULL); + g_assert (dst != NULL); + + if (src->debug) printf ("copying from offscreen drawable\n"); + + gdk_threads_enter (); + gdk_drawable_get_size (src->drawable, &s_width, &s_height); + gdk_drawable_get_size (dst->drawable, &d_width, &d_height); + width = min (s_width, d_width); + height = min (s_width, d_height); + + gc = gdk_gc_new (dst->drawable); + g_assert (gc != NULL); + + gdk_draw_drawable(dst->drawable, gc, src->drawable, + 0, 0, x, y, width, height); + + g_object_unref (gc); + + if (src->debug) printf ("copied %d x %d pixels from offscreen drawable\n", width, height); + gdk_threads_leave (); +} + +static jintArray +current_colors_of_widget (GtkWidget *widget, JNIEnv *env) +{ + GdkColor color; + jintArray array; + jint *rgb; + + g_assert (widget != NULL); + g_assert (env != NULL); + + color = widget->style->fg[GTK_STATE_NORMAL]; + array = (*env)->NewIntArray (env, 6); + + rgb = (*env)->GetIntArrayElements (env, array, NULL); + rgb[0] = color.red >> 8; + rgb[1] = color.green >> 8; + rgb[2] = color.blue >> 8; + + color = widget->style->bg[GTK_STATE_NORMAL]; + rgb[3] = color.red >> 8; + rgb[4] = color.green >> 8; + rgb[5] = color.blue >> 8; + + (*env)->ReleaseIntArrayElements (env, array, rgb, 0); + + return array; +} + +JNIEXPORT jintArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_initState__Lgnu_java_awt_peer_gtk_GtkComponentPeer_2 + (JNIEnv *env, jobject obj, jobject peer) +{ + struct graphics2d *gr = NULL; + GtkWidget *widget = NULL; + void *ptr = NULL; + jintArray color; + + ptr = NSA_GET_PTR (env, peer); + g_assert (ptr != NULL); + gdk_threads_enter (); + + gr = (struct graphics2d *) malloc (sizeof (struct graphics2d)); + g_assert (gr != NULL); + memset (gr, 0, sizeof(struct graphics2d)); + + check_for_debug (gr); + + gr->cr = cairo_create(); + g_assert (gr->cr != NULL); + + widget = GTK_WIDGET (ptr); + g_assert (widget != NULL); + + grab_current_drawable (widget, &(gr->drawable), &(gr->win)); + g_assert (gr->drawable != NULL); + + if (x_server_has_render_extension ()) + init_graphics2d_as_renderable (gr); + else + init_graphics2d_as_pixbuf (gr); + + color = current_colors_of_widget (widget, env); + + gdk_threads_leave (); + NSA_SET_G2D_PTR (env, obj, gr); + return color; +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_dispose + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + + gr = (struct graphics2d *) NSA_DEL_G2D_PTR (env, obj); + if (gr == NULL) + return; /* dispose has been called more than once */ + + gdk_threads_enter (); + + if (gr->surface) + cairo_surface_destroy (gr->surface); + + cairo_destroy (gr->cr); + + if (gr->drawbuf) + g_object_unref (gr->drawbuf); + + g_object_unref (gr->drawable); + free (gr); + + if (gr->pattern) + cairo_surface_destroy (gr->pattern); + + if (gr->pattern_pixels) + free (gr->pattern_pixels); + + if (gr->debug) printf ("disposed of graphics2d\n"); + + gdk_threads_leave (); +} + + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_setGradient + (JNIEnv *env, jobject obj, + jdouble x1, jdouble y1, + jdouble x2, jdouble y2, + jint r1, jint g1, jint b1, jint a1, + jint r2, jint g2, jint b2, jint a2, + jboolean cyclic) +{ + struct graphics2d *gr = NULL; + cairo_surface_t *surf = NULL; + cairo_matrix_t *mat = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + + if (gr->debug) printf ("setGradient (%f,%f) -> (%f,%f); (%d,%d,%d,%d) -> (%d,%d,%d,%d)\n", + x1, y1, + x2, y2, + r1, g1, b1, a1, + r2, g2, b2, a2); + + cairo_save (gr->cr); + + if (cyclic) + surf = cairo_surface_create_similar (gr->surface, CAIRO_FORMAT_ARGB32, 3, 2); + else + surf = cairo_surface_create_similar (gr->surface, CAIRO_FORMAT_ARGB32, 2, 2); + g_assert (surf != NULL); + + cairo_set_target_surface (gr->cr, surf); + + cairo_identity_matrix (gr->cr); + + cairo_set_rgb_color (gr->cr, r1 / 255.0, g1 / 255.0, b1 / 255.0); + cairo_set_alpha (gr->cr, a1 / 255.0); + cairo_rectangle (gr->cr, 0, 0, 1, 2); + cairo_fill (gr->cr); + + cairo_set_rgb_color (gr->cr, r2 / 255.0, g2 / 255.0, b2 / 255.0); + cairo_set_alpha (gr->cr, a2 / 255.0); + cairo_rectangle (gr->cr, 1, 0, 1, 2); + cairo_fill (gr->cr); + + if (cyclic) + { + cairo_set_rgb_color (gr->cr, r1 / 255.0, g1 / 255.0, b1 / 255.0); + cairo_set_alpha (gr->cr, a1 / 255.0); + cairo_rectangle (gr->cr, 2, 0, 1, 2); + cairo_fill (gr->cr); + } + + mat = cairo_matrix_create (); + g_assert (mat != NULL); + + /* + consider the vector [x2 - x1, y2 - y1] = [p,q] + + this is a line in space starting at an 'origin' x1, y1. + + it can also be thought of as a "transformed" unit vector in either the + x or y directions. we have just *drawn* our gradient as a unit vector + (well, a 2-3x unit vector) in the x dimension. so what we want to know + is which transformation turns our existing unit vector into [p,q]. + + which means solving for M in + + [p,q] = M[1,0] + + [p,q] = |a b| [1,0] + |c d| + + [p,q] = [a,c], with b = d = 0. + + what does this mean? it means that our gradient is 1-dimensional; as + you move through the x axis of our 2 or 3 pixel gradient from logical + x positions 0 to 1, the transformation of your x coordinate under the + matrix M causes you to accumulate both x and y values in fill + space. the y value of a gradient coordinate is ignored, since the + gradient is one dimensional. which is correct. + + unfortunately we want the opposite transformation, it seems, because of + the way cairo is going to use this transformation. I'm a bit confused by + that, but it seems to work right, so we take reciprocals of values and + negate offsets. oh well. + + */ + + double a = (x2 - x1 == 0.) ? 0. : ((cyclic ? 3.0 : 2.0) / (x2 - x1)); + double c = (y2 - y1 == 0.) ? 0. : (1. / (y2 - y1)); + double dx = (x1 == 0.) ? 0. : 1. / x1; + double dy = (y1 == 0.) ? 0. : 1. / y1; + + cairo_matrix_set_affine (mat, + a, 0., + c, 0., + dx, dy); + + cairo_surface_set_matrix (surf, mat); + cairo_matrix_destroy (mat); + cairo_surface_set_filter (surf, CAIRO_FILTER_BILINEAR); + + /* FIXME: repeating gradients (not to mention hold gradients) don't seem to work. */ + /* cairo_surface_set_repeat (surf, cyclic ? 1 : 0); */ + + if (gr->pattern) + cairo_surface_destroy (gr->pattern); + + if (gr->pattern_pixels) + { + free (gr->pattern_pixels); + gr->pattern_pixels = NULL; + } + + gr->pattern = surf; + + cairo_restore (gr->cr); + cairo_set_pattern (gr->cr, gr->pattern); + +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_setTexturePixels + (JNIEnv *env, jobject obj, jintArray jarr, jint w, jint h, jint stride) +{ + struct graphics2d *gr = NULL; + jint *jpixels = NULL; + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + + if (gr->debug) printf ("setTexturePixels (%d pixels, %dx%d, stride: %d)\n", + (*env)->GetArrayLength (env, jarr), w, h, stride); + + if (gr->pattern) + cairo_surface_destroy (gr->pattern); + + if (gr->pattern_pixels) + free (gr->pattern_pixels); + + gr->pattern = NULL; + gr->pattern_pixels = NULL; + + gr->pattern_pixels = (char *) malloc (h * stride * 4); + g_assert (gr->pattern_pixels != NULL); + + jpixels = (*env)->GetIntArrayElements (env, jarr, NULL); + g_assert (jpixels != NULL); + memcpy (gr->pattern_pixels, jpixels, h * stride * 4); + (*env)->ReleaseIntArrayElements (env, jarr, jpixels, 0); + + gr->pattern = cairo_surface_create_for_image (gr->pattern_pixels, + CAIRO_FORMAT_ARGB32, + w, h, stride * 4); + g_assert (gr->pattern != NULL); + cairo_surface_set_repeat (gr->pattern, 1); + cairo_set_pattern (gr->cr, gr->pattern); + +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_drawPixels + (JNIEnv *env, jobject obj, jintArray jarr, jint w, jint h, jint stride) +{ + struct graphics2d *gr = NULL; + jint *jpixels = NULL; + + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + + if (gr->debug) printf ("drawPixels (%d pixels, %dx%d, stride: %d)\n", + (*env)->GetArrayLength (env, jarr), w, h, stride); + + jpixels = (*env)->GetIntArrayElements (env, jarr, NULL); + g_assert (jpixels != NULL); + + begin_drawing_operation (gr); + + { + cairo_surface_t *surf = cairo_surface_create_for_image ((char *)jpixels, + CAIRO_FORMAT_ARGB32, + w, h, stride * 4); + cairo_surface_set_filter (surf, CAIRO_FILTER_BILINEAR); + cairo_show_surface (gr->cr, surf, w, h); + cairo_surface_destroy (surf); + } + + end_drawing_operation (gr); + + (*env)->ReleaseIntArrayElements (env, jarr, jpixels, 0); + +} + +/* passthrough methods to cairo */ + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSave + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_save\n"); + cairo_save (gr->cr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRestore + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_restore\n"); + cairo_restore (gr->cr); + update_pattern_transform (gr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetMatrix + (JNIEnv *env, jobject obj, + jdouble m00, jdouble m10, + jdouble m01, jdouble m11, + jdouble m02, jdouble m12) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_matrix\n"); + + { + cairo_matrix_t * mat = cairo_matrix_create (); + cairo_matrix_set_affine (mat, + m00, m10, + m01, m11, + m02, m12); + cairo_set_matrix (gr->cr, mat); + cairo_matrix_destroy (mat); + } + update_pattern_transform (gr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetOperator + (JNIEnv *env, jobject obj, jint op) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_operator %d\n", op); + switch ((enum java_awt_alpha_composite_rule) op) + { + case java_awt_alpha_composite_CLEAR: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_CLEAR); + break; + + case java_awt_alpha_composite_SRC: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_SRC); + break; + + case java_awt_alpha_composite_SRC_OVER: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_OVER); + break; + + case java_awt_alpha_composite_DST_OVER: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_OVER_REVERSE); + break; + + case java_awt_alpha_composite_SRC_IN: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_IN); + break; + + case java_awt_alpha_composite_DST_IN: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_IN_REVERSE); + break; + + case java_awt_alpha_composite_SRC_OUT: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_OUT); + break; + + case java_awt_alpha_composite_DST_OUT: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_OUT_REVERSE); + break; + + case java_awt_alpha_composite_DST: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_DST); + break; + + case java_awt_alpha_composite_SRC_ATOP: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_ATOP); + break; + + case java_awt_alpha_composite_DST_ATOP: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_ATOP_REVERSE); + break; + + case java_awt_alpha_composite_XOR: + cairo_set_operator (gr->cr, CAIRO_OPERATOR_XOR); + break; + } +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetRGBColor + (JNIEnv *env, jobject obj, jdouble r, jdouble g, jdouble b) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + + /* this is a very weird fact: GDK Pixbufs and RENDER drawables consider + colors in opposite pixel order. I have no idea why. thus when you + draw to a PixBuf, you must exchange the R and B components of your + color. */ + + if (gr->debug) printf ("cairo_set_rgb_color (%f, %f, %f)\n", r, g, b); + + if (gr->drawbuf) + cairo_set_rgb_color (gr->cr, b, g, r); + else + cairo_set_rgb_color (gr->cr, r, g, b); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetAlpha + (JNIEnv *env, jobject obj, jdouble a) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_alpha %f\n", a); + cairo_set_alpha (gr->cr, a); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetFillRule + (JNIEnv *env, jobject obj, jint rule) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + if (gr->debug) printf ("cairo_set_fill_rule %d\n", rule); + g_assert (gr != NULL); + switch ((enum java_awt_geom_path_iterator_winding_rule) rule) + { + case java_awt_geom_path_iterator_WIND_NON_ZERO: + cairo_set_fill_rule (gr->cr, CAIRO_FILL_RULE_WINDING); + break; + case java_awt_geom_path_iterator_WIND_EVEN_ODD: + cairo_set_fill_rule (gr->cr, CAIRO_FILL_RULE_EVEN_ODD); + break; + } +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineWidth + (JNIEnv *env, jobject obj, jdouble width) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_line_width %f\n", width); + cairo_set_line_width (gr->cr, width); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineCap + (JNIEnv *env, jobject obj, jint cap) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_line_cap %d\n", cap); + switch ((enum java_awt_basic_stroke_cap_rule) cap) + { + case java_awt_basic_stroke_CAP_BUTT: + cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_BUTT); + break; + + case java_awt_basic_stroke_CAP_ROUND: + cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_ROUND); + break; + + case java_awt_basic_stroke_CAP_SQUARE: + cairo_set_line_cap (gr->cr, CAIRO_LINE_CAP_SQUARE); + break; + } +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetLineJoin + (JNIEnv *env, jobject obj, jint join) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_line_join %d\n", join); + switch ((enum java_awt_basic_stroke_join_rule) join) + { + case java_awt_basic_stroke_JOIN_MITER: + cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_MITER); + break; + + case java_awt_basic_stroke_JOIN_ROUND: + cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_ROUND); + break; + + case java_awt_basic_stroke_JOIN_BEVEL: + cairo_set_line_join (gr->cr, CAIRO_LINE_JOIN_BEVEL); + break; + } +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetDash + (JNIEnv *env, jobject obj, jdoubleArray dashes, jint ndash, jdouble offset) +{ + struct graphics2d *gr = NULL; + jdouble *dasharr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_dash\n"); + dasharr = (*env)->GetDoubleArrayElements (env, dashes, NULL); + g_assert (dasharr != NULL); + cairo_set_dash (gr->cr, dasharr, ndash, offset); + (*env)->ReleaseDoubleArrayElements (env, dashes, dasharr, 0); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoSetMiterLimit + (JNIEnv *env, jobject obj, jdouble miter) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_set_miter_limit %f\n", miter); + cairo_set_miter_limit (gr->cr, miter); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoTranslate + (JNIEnv *env, jobject obj, jdouble dx, jdouble dy) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_translate (%f, %f)\n", dx, dy); + cairo_translate (gr->cr, dx, dy); + update_pattern_transform (gr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoScale + (JNIEnv *env, jobject obj, jdouble sx, jdouble sy) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_scale (%f, %f)\n", sx, sy); + cairo_scale (gr->cr, sx, sy); + update_pattern_transform (gr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRotate + (JNIEnv *env, jobject obj, jdouble angle) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_rotate %f\n", angle); + cairo_rotate (gr->cr, angle); + update_pattern_transform (gr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoNewPath + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_new_path\n"); + cairo_new_path (gr->cr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoMoveTo + (JNIEnv *env, jobject obj, jdouble x, jdouble y) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_move_to (%f, %f)\n", x, y); + cairo_move_to (gr->cr, x, y); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoLineTo + (JNIEnv *env, jobject obj, jdouble x, jdouble y) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_line_to (%f, %f)\n", x, y); + cairo_line_to (gr->cr, x, y); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoCurveTo + (JNIEnv *env, jobject obj, jdouble x1, jdouble y1, jdouble x2, jdouble y2, jdouble x3, jdouble y3) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_curve_to (%f, %f), (%f, %f), (%f, %f)\n", x1, y1, x2, y2, x3, y3); + cairo_curve_to (gr->cr, x1, y1, x2, y2, x3, y3); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelMoveTo + (JNIEnv *env, jobject obj, jdouble dx, jdouble dy) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_rel_move_to (%f, %f)\n", dx, dy); + cairo_rel_move_to (gr->cr, dx, dy); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelLineTo + (JNIEnv *env, jobject obj, jdouble dx, jdouble dy) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_rel_line_to (%f, %f)\n", dx, dy); + cairo_rel_line_to (gr->cr, dx, dy); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRelCurveTo + (JNIEnv *env, jobject obj, jdouble dx1, jdouble dy1, jdouble dx2, jdouble dy2, jdouble dx3, jdouble dy3) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_rel_curve_to (%f, %f), (%f, %f), (%f, %f)\n", dx1, dy1, dx2, dy2, dx3, dy3); + cairo_rel_curve_to (gr->cr, dx1, dy1, dx2, dy2, dx3, dy3); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoRectangle + (JNIEnv *env, jobject obj, jdouble x, jdouble y, jdouble width, jdouble height) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_rectangle (%f, %f) (%f, %f)\n", x, y, width, height); + cairo_rectangle (gr->cr, x, y, width, height); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoClosePath + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_close_path\n"); + cairo_close_path (gr->cr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoStroke + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_stroke\n"); + begin_drawing_operation (gr); + cairo_stroke (gr->cr); + end_drawing_operation (gr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoFill + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_fill\n"); + begin_drawing_operation (gr); + cairo_fill (gr->cr); + end_drawing_operation (gr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoClip + (JNIEnv *env, jobject obj) +{ + struct graphics2d *gr = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); + g_assert (gr != NULL); + if (gr->debug) printf ("cairo_clip\n"); + cairo_clip (gr->cr); +} + diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c new file mode 100644 index 00000000000..0d755721649 --- /dev/null +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c @@ -0,0 +1,236 @@ +/* gdkpixbufdecoder.c + Copyright (C) 1999, 2003 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., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 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. */ + + +#include +#include +#include + +#include "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GdkPixbufDecoder.h" + +struct state_table *native_pixbufdecoder_state_table; + +#define NSA_PB_INIT(env, clazz) \ + native_pixbufdecoder_state_table = init_state_table (env, clazz) + +#define NSA_GET_PB_PTR(env, obj) \ + get_state (env, obj, native_pixbufdecoder_state_table) + +#define NSA_SET_PB_PTR(env, obj, ptr) \ + set_state (env, obj, native_pixbufdecoder_state_table, (void *)ptr) + +#define NSA_DEL_PB_PTR(env, obj) \ + remove_state_slot (env, obj, native_pixbufdecoder_state_table) + + +jmethodID areaPreparedID; +jmethodID areaUpdatedID; + +static void +area_prepared (GdkPixbufLoader *loader, + jobject *decoder) +{ + jint width, height; + + GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf == NULL) + return; + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf), + + gdk_threads_leave (); + + g_assert (decoder != NULL); + + (*gdk_env)->CallVoidMethod (gdk_env, + *decoder, + areaPreparedID, + width, height); + + gdk_threads_enter (); +} + +static void +area_updated (GdkPixbufLoader *loader, + gint x, gint y, + gint width, gint height, + jobject *decoder) +{ + jint stride_bytes, stride_pixels, n_channels, n_pixels; + int i, px; + jintArray jpixels; + jint *java_pixels; + guchar *gdk_pixels; + + GdkPixbuf *pixbuf_no_alpha = NULL; + GdkPixbuf *pixbuf = NULL; + + pixbuf_no_alpha = gdk_pixbuf_loader_get_pixbuf (loader); + if (pixbuf_no_alpha == NULL) + return; + + pixbuf = gdk_pixbuf_add_alpha(pixbuf_no_alpha, FALSE, 0, 0, 0); + g_assert (gdk_pixbuf_get_has_alpha (pixbuf)); + + stride_bytes = gdk_pixbuf_get_rowstride (pixbuf); + n_channels = gdk_pixbuf_get_n_channels (pixbuf); + stride_pixels = stride_bytes / n_channels; + n_pixels = height * stride_pixels; + gdk_pixels = gdk_pixbuf_get_pixels (pixbuf); + + jpixels = (*gdk_env)->NewIntArray (gdk_env, n_pixels); + java_pixels = (*gdk_env)->GetIntArrayElements (gdk_env, jpixels, NULL); + + memcpy (java_pixels, + gdk_pixels + (y * stride_bytes), + (height * stride_bytes)); + + for (i = 0; i < n_pixels; ++i) + { + px = java_pixels[i]; + + /* move alpha around (GdkPixbufLoader results are AGBR not GBRA, in + the lsb sense) */ + /* px = ((px >> 24) & 0xff) | ((px << 8) & 0xffffff00); */ + + /* it appears to require a full byte swap, now, not just a shift to + the A channel. why did this change? don't know. */ + px = ((px >> 8) & 0x00ff00ff) | ((px << 8) & 0xff00ff00); + px = ((px >> 16) & 0x0000ffff) | ((px << 16) & 0xffff0000); + + java_pixels[i] = px; + } + + g_object_unref (pixbuf); + + gdk_threads_leave (); + + (*gdk_env)->ReleaseIntArrayElements (gdk_env, jpixels, java_pixels, 0); + (*gdk_env)->CallVoidMethod (gdk_env, + *decoder, + areaUpdatedID, + (jint) x, (jint) y, + (jint) width, (jint) height, + jpixels, + stride_pixels); + gdk_threads_enter (); +} + +static void +closed (GdkPixbufLoader *loader, jobject *decoder) +{ + gdk_threads_leave (); + (*gdk_env)->DeleteGlobalRef (gdk_env, *decoder); + free (decoder); + gdk_threads_enter (); +} + + + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initState + (JNIEnv *env, jobject obj) +{ + GdkPixbufLoader *loader = NULL; + jobject *decoder = NULL; + + decoder = (jobject *) malloc (sizeof (jobject)); + g_assert (decoder != NULL); + *decoder = (*env)->NewGlobalRef (env, obj); + + gdk_threads_enter (); + loader = gdk_pixbuf_loader_new (); + g_assert (loader != NULL); + g_signal_connect (loader, "area-prepared", G_CALLBACK (area_prepared), decoder); + g_signal_connect (loader, "area-updated", G_CALLBACK (area_updated), decoder); + g_signal_connect (loader, "closed", G_CALLBACK (closed), decoder); + gdk_threads_leave (); + + NSA_SET_PB_PTR (env, obj, loader); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_initStaticState + (JNIEnv *env, jclass clazz) +{ + areaPreparedID = (*env)->GetMethodID (env, clazz, + "areaPrepared", + "(II)V"); + + areaUpdatedID = (*env)->GetMethodID (env, clazz, + "areaUpdated", + "(IIII[II)V"); + NSA_PB_INIT (env, clazz); +} + + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_finish + (JNIEnv *env, jobject obj) +{ + GdkPixbufLoader *loader = NULL; + + loader = (GdkPixbufLoader *)NSA_DEL_PB_PTR (env, obj); + if (loader == NULL) + return; + + gdk_threads_enter (); + gdk_pixbuf_loader_close (loader, NULL); + g_object_unref (loader); + gdk_threads_leave (); +} + + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_pumpBytes + (JNIEnv *env, jobject obj, jbyteArray jarr, jint len) +{ + GdkPixbufLoader *loader = NULL; + jbyte *bytes = NULL; + + if (len < 1) + return; + + bytes = (*gdk_env)->GetByteArrayElements (gdk_env, jarr, NULL); + g_assert (bytes != NULL); + loader = (GdkPixbufLoader *)NSA_GET_PB_PTR (env, obj); + g_assert (loader != NULL); + + gdk_threads_enter (); + gdk_pixbuf_loader_write (loader, bytes, len, NULL); + gdk_threads_leave (); + + (*gdk_env)->ReleaseByteArrayElements (gdk_env, jarr, bytes, 0); +}