--- gnu/java/awt/peer/gtk/GdkClasspathFontPeer.java 25 Oct 2003 18:41:45 -0000 1.1 +++ gnu/java/awt/peer/gtk/GdkClasspathFontPeer.java 18 Nov 2003 18:34:16 -0000 @@ -49,6 +49,7 @@ import java.util.StringTokenizer; import java.text.CharacterIterator; import java.text.AttributedCharacterIterator; +import java.text.StringCharacterIterator; import java.awt.font.TextAttribute; import gnu.classpath.Configuration; import gnu.java.awt.peer.ClasspathFontPeer; @@ -180,10 +181,56 @@ throw new UnsupportedOperationException (); } + protected class GdkFontLineMetrics extends LineMetrics + { + FontMetrics fm; + int nchars; + + public GdkFontLineMetrics (FontMetrics m, int n) + { + fm = m; + nchars = n; + } + + public float getAscent() + { + return (float) fm.getAscent (); + } + + public int getBaselineIndex() + { + return Font.ROMAN_BASELINE; + } + + public float[] getBaselineOffsets() + { + return new float[3]; + } + + public float getDescent() + { + return (float) fm.getDescent (); + } + + public float getHeight() + { + return (float) fm.getHeight (); + } + + public float getLeading() { return 0.f; } + public int getNumChars() { return nchars; } + public float getStrikethroughOffset() { return 0.f; } + public float getStrikethroughThickness() { return 0.f; } + public float getUnderlineOffset() { return 0.f; } + public float getUnderlineThickness() { return 0.f; } + + } + + public LineMetrics getLineMetrics (Font font, CharacterIterator ci, int begin, int limit, FontRenderContext rc) { - throw new UnsupportedOperationException (); + return new GdkFontLineMetrics (getFontMetrics (font), limit - begin); } public Rectangle2D getMaxCharBounds (Font font, FontRenderContext rc) @@ -214,25 +261,32 @@ public boolean hasUniformLineMetrics (Font font) { - throw new UnsupportedOperationException (); + return true; } public GlyphVector layoutGlyphVector (Font font, FontRenderContext frc, char[] chars, int start, int limit, int flags) { - throw new UnsupportedOperationException (); + int nchars = (limit - start) + 1; + char[] nc = new char[nchars]; + + for (int i = 0; i < nchars; ++i) + nc[i] = chars[start + i]; + + return createGlyphVector (font, frc, + new StringCharacterIterator (new String (nc))); } public LineMetrics getLineMetrics (Font font, String str, FontRenderContext frc) { - throw new UnsupportedOperationException(); + return new GdkFontLineMetrics (getFontMetrics (font), str.length ()); } public FontMetrics getFontMetrics (Font font) { - throw new UnsupportedOperationException(); + return new GdkClasspathFontPeerMetrics (font); } } --- gnu/java/awt/peer/gtk/GdkGraphics2D.java 25 Oct 2003 18:41:45 -0000 1.2 +++ gnu/java/awt/peer/gtk/GdkGraphics2D.java 18 Nov 2003 18:34:16 -0000 @@ -47,6 +47,7 @@ import java.text.AttributedCharacterIterator; import java.util.Map; +import java.util.Stack; import java.lang.Integer; import gnu.java.awt.ClasspathToolkit; import gnu.java.awt.peer.ClasspathFontPeer; @@ -79,6 +80,8 @@ private GtkComponentPeer component; private Font font; + private Stack stateStack; + native private int[] initState (GtkComponentPeer component); native private void initState (int width, int height); native private void copyState (GdkGraphics2D g); @@ -122,33 +125,50 @@ clip = new Rectangle (g.getClipBounds ()); if (g.transform == null) - transform = null; + transform = AffineTransform.getTranslateInstance (0.5, 0.5); else transform = new AffineTransform (g.transform); + font = g.font; component = g.component; copyState (g); setColor (fg); + setBackground (bg); + setPaint (paint); + setStroke (stroke); setClip (clip); setTransform (transform); + stateStack = new Stack(); } GdkGraphics2D (int width, int height) { initState (width, height); - bg = Color.black; - fg = Color.black; - transform = new AffineTransform (); + + setColor(Color.black); + setBackground (Color.black); + setPaint (getColor()); + setFont (new Font("SansSerif", Font.PLAIN, 12)); + setTransform (AffineTransform.getTranslateInstance (0.5, 0.5)); + setStroke (new BasicStroke ()); + + stateStack = new Stack(); } 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 (); + + setColor (new Color (rgb[0], rgb[1], rgb[2])); + setBackground (new Color (rgb[3], rgb[4], rgb[5])); + setPaint (getColor()); + setFont (new Font("SansSerif", Font.PLAIN, 12)); + setTransform (AffineTransform.getTranslateInstance (0.5, 0.5)); + setStroke (new BasicStroke ()); + + stateStack = new Stack (); } @@ -160,7 +180,7 @@ 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 drawPixels (int pixels[], int w, int h, int stride, double i2u[]); private native void setTexturePixels (int pixels[], int w, int h, int stride); private native void setGradient (double x1, double y1, double x2, double y2, @@ -171,13 +191,10 @@ // 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 cairoSetMatrix (double m[]); private native void cairoSetFont (GdkClasspathFontPeer peer); private native void cairoShowGlyphs (int codes[], - float positions[], - int nglyphs); + float positions[]); private native void cairoSetOperator (int cairoOperator); private native void cairoSetRGBColor (double red, double green, double blue); private native void cairoSetAlpha (double alpha); @@ -187,9 +204,6 @@ 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); @@ -213,6 +227,51 @@ ////// General Drawing Support Methods ////// ///////////////////////////////////////////// + private class DrawState + { + private Paint paint; + private Stroke stroke; + private Color fg; + private Color bg; + private Shape clip; + private AffineTransform transform; + private Font font; + DrawState (GdkGraphics2D g) + { + this.paint = g.paint; + this.stroke = g.stroke; + this.fg = g.fg; + this.bg = g.bg; + this.clip = g.clip; + if (g.transform != null) + this.transform = (AffineTransform) g.transform.clone(); + this.font = g.font; + } + public void restore(GdkGraphics2D g) + { + g.paint = this.paint; + g.stroke = this.stroke; + g.fg = this.fg; + g.bg = this.bg; + g.clip = this.clip; + g.transform = this.transform; + g.font = this.font; + } + } + + private void stateSave () + { + stateStack.push (new DrawState (this)); + cairoSave (); + } + + private void stateRestore () + { + ((DrawState)(stateStack.pop ())).restore (this); + cairoRestore (); + } + + double x; double y; private void setPos (double nx, double ny) @@ -288,7 +347,7 @@ return; } - cairoSave (); + stateSave (); cairoNewPath (); if (s instanceof Rectangle2D) { @@ -298,12 +357,12 @@ else walkPath (s.getPathIterator (null)); cairoStroke (); - cairoRestore (); + stateRestore (); } public void fill(Shape s) { - cairoSave(); + stateSave(); cairoNewPath (); if (s instanceof Rectangle2D) { @@ -313,24 +372,41 @@ else walkPath (s.getPathIterator (null)); cairoFill (); - cairoRestore (); + stateRestore (); } public void clip (Shape s) { + // update it + + if (clip == null || s == null) clip = s; - cairoNewPath (); - if (s instanceof Rectangle2D) + else if (s instanceof Rectangle2D + && clip instanceof Rectangle2D) { Rectangle2D r = (Rectangle2D)s; + Rectangle2D curr = (Rectangle2D)clip; + clip = curr.createIntersection (r); + } + else + throw new UnsupportedOperationException (); + + // draw it + if (clip != null) + { + cairoNewPath (); + if (clip instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D)clip; cairoRectangle (r.getX (), r.getY (), r.getWidth (), r.getHeight ()); } else - walkPath (s.getPathIterator (null)); + walkPath (clip.getPathIterator (null)); cairoClosePath (); cairoClip (); } + } public Paint getPaint () { @@ -339,11 +415,14 @@ public AffineTransform getTransform () { - return transform; + return (AffineTransform) transform.clone (); } public void setPaint (Paint p) { + if (paint == null) + return; + paint = p; if (paint instanceof Color) { @@ -385,7 +464,7 @@ { double m[] = new double[6]; transform.getMatrix (m); - cairoSetMatrix (m[0], m[1], m[2], m[3], m[4], m[5]); + cairoSetMatrix (m); } } @@ -400,32 +479,22 @@ public void rotate(double theta) { - if (transform != null) - transform.rotate (theta); - cairoRotate (theta); + transform (AffineTransform.getRotateInstance (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); + transform (AffineTransform.getRotateInstance (theta, x, y)); } public void scale(double sx, double sy) { - if (transform != null) - transform.scale (sx, sy); - cairoScale (sx, sy); + transform (AffineTransform.getScaleInstance (sx, sy)); } public void translate (double tx, double ty) { - if (transform != null) - transform.translate (tx, ty); - cairoTranslate (tx, ty); + transform (AffineTransform.getTranslateInstance (tx, ty)); } public void translate (int x, int y) @@ -433,6 +502,11 @@ translate ((double) x, (double) y); } + public void shear(double shearX, double shearY) + { + transform (AffineTransform.getShearInstance (shearX, shearY)); + } + public Stroke getStroke() { return stroke; @@ -445,7 +519,7 @@ { BasicStroke bs = (BasicStroke) stroke; cairoSetLineCap (bs.getEndCap()); - cairoSetLineWidth (bs.getLineWidth()); + cairoSetLineWidth (bs.getLineWidth() / 2.0); cairoSetLineJoin (bs.getLineJoin()); cairoSetMiterLimit (bs.getMiterLimit()); float dashes[] = bs.getDashArray(); @@ -467,7 +541,7 @@ public void setPaintMode () { - setComposite (java.awt.AlphaComposite.Xor); + setComposite (java.awt.AlphaComposite.SrcOver); } public void setXORMode (Color c) @@ -478,6 +552,7 @@ public void setColor (Color c) { fg = c; + paint = c; cairoSetRGBColor (fg.getRed() / 255.0, fg.getGreen() / 255.0, fg.getBlue() / 255.0); @@ -491,29 +566,12 @@ 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))); - } + clip (new Rectangle (x, y, width, height)); } public Shape getClip () { - return clip; + return getClipInDevSpace (); } public Rectangle getClipBounds () @@ -524,13 +582,32 @@ return clip.getBounds (); } + protected Rectangle2D getClipInDevSpace () + { + Rectangle2D uclip = clip.getBounds2D (); + if (transform == null) + return uclip; + else + { + Point2D pos = transform.transform (new Point2D.Double(uclip.getX (), + uclip.getY ()), + (Point2D)null); + Point2D extent = transform.deltaTransform (new Point2D.Double(uclip.getWidth (), + uclip.getHeight ()), + (Point2D)null); + return new Rectangle2D.Double (pos.getX (), pos.getY (), + extent.getX (), extent.getY ()); + } + } + 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); + clip = new Rectangle2D.Double ((double)x, (double)y, + (double)width, (double)height); } public void setClip (Shape s) @@ -558,7 +635,7 @@ double y1 = (double) y; double y2 = (double) y + height; - cairoSave (); + stateSave (); cairoNewPath (); setColor (light); @@ -574,9 +651,7 @@ cairoLineTo (x2, y2); cairoStroke (); - cairoRestore (); - setColor (std); - + stateRestore (); } public void fill3DRect(int x, int y, int width, @@ -594,15 +669,15 @@ draw3DRect (x, y, width, height, raised); - cairoSave (); - cairoTranslate (step/2.0, step/2.0); + stateSave (); + translate (step/2.0, step/2.0); cairoNewPath (); cairoRectangle ((double) x, (double) y, ((double) width) - step, ((double) height) - step ); cairoClosePath (); cairoFill (); - cairoRestore (); + stateRestore (); } @@ -618,7 +693,7 @@ public void clearRect (int x, int y, int width, int height) { - cairoSave (); + stateSave (); cairoSetRGBColor (bg.getRed() / 255.0, bg.getGreen() / 255.0, bg.getBlue() / 255.0); @@ -627,7 +702,7 @@ cairoRectangle (x, y, width, height); cairoClosePath (); cairoFill (); - cairoRestore (); + stateRestore (); } public void setBackground(Color c) @@ -635,13 +710,11 @@ bg = c; } - public Color getBackground() { return bg; } - private void doPolygon(int[] xPoints, int[] yPoints, int nPoints, boolean close, boolean fill) { @@ -698,7 +771,8 @@ doPolygon (xPoints, yPoints, nPoints, false, false); } - private boolean drawRaster (ColorModel cm, Raster r) + private boolean drawRaster (ColorModel cm, Raster r, + AffineTransform imageToUser) { if (r == null) return false; @@ -712,6 +786,16 @@ if (cm == null) cm = ColorModel.getRGBdefault (); + double[] i2u = new double[6]; + if (imageToUser != null) + imageToUser.getMatrix(i2u); + else + { + i2u[0] = 1; i2u[1] = 0; + i2u[2] = 0; i2u[3] = 1; + i2u[2] = 0; i2u[3] = 0; + } + int pixels[] = null; if (sm.getDataType () == DataBuffer.TYPE_INT && @@ -735,23 +819,39 @@ pixels = pixels2; } - cairoSave (); - cairoTranslate (x, y); - drawPixels (pixels, r.getWidth (), r.getHeight (), r.getWidth ()); - cairoRestore (); + stateSave (); + translate (x, y); + drawPixels (pixels, r.getWidth (), r.getHeight (), r.getWidth (), i2u); + stateRestore (); return true; } - public boolean drawImage (Image img, int x, int y, - ImageObserver observer) + public void drawRenderedImage(RenderedImage image, + AffineTransform xform) + { + drawRaster (image.getColorModel(), image.getData(), xform); + } + + public void drawRenderableImage(RenderableImage image, + AffineTransform xform) + { + drawRenderedImage (image.createRendering (new RenderContext (xform)), xform); + } + + public boolean drawImage(Image img, + AffineTransform xform, + ImageObserver obs) { if (img instanceof GtkOffScreenImage && img.getGraphics () instanceof GdkGraphics2D && - (transform == null || transform.isIdentity ())) + (xform == null + || xform.getType () == AffineTransform.TYPE_IDENTITY + || xform.getType () == AffineTransform.TYPE_TRANSLATION) + ) { // we are being asked to flush a double buffer from Gdk GdkGraphics2D g2 = (GdkGraphics2D) img.getGraphics (); - gdkDrawDrawable (g2, x, y); + gdkDrawDrawable (g2, (int)xform.getTranslateX(), (int)xform.getTranslateY()); return true; } else @@ -760,17 +860,32 @@ { // draw an image which has actually been loaded into memory fully BufferedImage b = (BufferedImage) img; - return drawRaster (b.getColorModel (), b.getData ()); + return drawRaster (b.getColorModel (), b.getData (), xform); } else { // begin progressive loading in a separate thread - new PainterThread (this, img); + new PainterThread (this, img, xform); return false; } } } + public void drawImage(BufferedImage image, + BufferedImageOp op, + int x, + int y) + { + Image filtered = op.filter(image, null); + drawImage(filtered, new AffineTransform(1f,0f,0f,1f,x,y), null); + } + + public boolean drawImage (Image img, int x, int y, + ImageObserver observer) + { + return drawImage(img, new AffineTransform(1f,0f,0f,1f,x,y), observer); + } + //////////////////////////////////////// ////// Supporting Private Classes ////// @@ -790,10 +905,12 @@ GdkGraphics2D gr; Image image; ColorModel defaultModel; + AffineTransform xform; - public PainterThread (GdkGraphics2D g, Image im) + public PainterThread (GdkGraphics2D g, Image im, AffineTransform xf) { image = im; + xform = xf; this.gr = (GdkGraphics2D) g.create (); new Thread (this).start (); } @@ -823,8 +940,8 @@ 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); + gr.stateSave (); + gr.translate (x, y); if (model == null) model = defaultModel; @@ -843,8 +960,10 @@ else pixels2 = pixels; - gr.drawPixels (pixels2, w, h, scansize); - gr.cairoRestore (); + double[] xf = new double[6]; + xform.getMatrix(xf); + gr.drawPixels (pixels2, w, h, scansize, xf); + gr.stateRestore (); } public void setProperties (java.util.Hashtable props) @@ -934,43 +1053,7 @@ ////// 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) @@ -1014,11 +1097,6 @@ 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 (); @@ -1026,18 +1104,20 @@ public FontRenderContext getFontRenderContext () { - throw new java.lang.UnsupportedOperationException (); + return new FontRenderContext (transform, true, true); } public void drawGlyphVector (GlyphVector g, float x, float y) { - cairoSave (); - cairoTranslate ((double)x, (double)y); + stateSave (); + setFont (g.getFont ()); + translate ((double)x, (double)y); + cairoMoveTo (0, 0); int nglyphs = g.getNumGlyphs (); int codes[] = g.getGlyphCodes (0, nglyphs, (int []) null); float posns[] = g.getGlyphPositions (0, nglyphs, (float []) null); - cairoShowGlyphs (codes, posns, nglyphs); - cairoRestore (); + cairoShowGlyphs (codes, posns); + stateRestore (); } public void copyArea (int x, int y, int width, int height, int dx, int dy) @@ -1048,7 +1128,10 @@ public void drawArc (int x, int y, int width, int height, int startAngle, int arcAngle) { - throw new java.lang.UnsupportedOperationException (); + draw (new Arc2D.Double((double)x, (double)y, + (double)width, (double)height, + (double)startAngle, (double)arcAngle, + Arc2D.OPEN)); } public boolean drawImage (Image img, int x, int y, Color bgcolor, @@ -1085,61 +1168,84 @@ public void drawOval(int x, int y, int width, int height) { - throw new java.lang.UnsupportedOperationException (); + drawArc (x, y, width, height, 0, 360); } public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { - throw new java.lang.UnsupportedOperationException (); + int x1 = x + arcWidth, x2 = x + width - arcWidth; + int y1 = y + arcHeight, y2 = y + height - arcHeight; + fillRect (x1, y, x2 - x1, height); + fillRect (x, y1, width, y2 - y1); + fillArc (x, y, arcWidth, arcHeight, 90, 90); + fillArc (x1, y, arcWidth, arcHeight, 0, 90); + fillArc (x2, y2, arcWidth, arcHeight, 270, 90); + fillArc (x, y2, arcWidth, arcHeight, 180, 90); } public void drawString (String str, int x, int y) { - throw new java.lang.UnsupportedOperationException (); + drawString (str, (float)x, (float)y); + } + + public void drawString (String str, float x, float y) + { + GlyphVector gv = font.createGlyphVector (getFontRenderContext(), str); + drawGlyphVector (gv, x, y); } public void drawString (AttributedCharacterIterator ci, int x, int y) { - throw new java.lang.UnsupportedOperationException (); + drawString (ci, (float)x, (float)y); + } + + public void drawString (AttributedCharacterIterator ci, float x, float y) + { + GlyphVector gv = font.createGlyphVector (getFontRenderContext(), ci); + drawGlyphVector (gv, x, y); } public void fillArc (int x, int y, int width, int height, int startAngle, int arcAngle) { - cairoNewPath (); - walkPath (new Arc2D.Double((double)x, (double)y, + fill (new Arc2D.Double((double)x, (double)y, (double)width, (double)height, (double)startAngle, (double)arcAngle, - Arc2D.PIE).getPathIterator (null)); - cairoClosePath (); - cairoFill (); + Arc2D.OPEN)); } public void fillOval(int x, int y, int width, int height) { - throw new java.lang.UnsupportedOperationException (); + fillArc (x, y, width, height, 0, 360); } public void fillRoundRect (int x, int y, int width, int height, int arcWidth, int arcHeight) { - throw new java.lang.UnsupportedOperationException (); + int x1 = x + arcWidth, x2 = x + width - arcWidth; + int y1 = y + arcHeight, y2 = y + height - arcHeight; + fillRect (x1, y, x2 - x1, height); + fillRect (x, y1, width, y2 - y1); + fillArc (x, y, arcWidth, arcHeight, 90, 90); + fillArc (x1, y, arcWidth, arcHeight, 0, 90); + fillArc (x2, y2, arcWidth, arcHeight, 270, 90); + fillArc (x, y2, arcWidth, arcHeight, 180, 90); } public Font getFont () { - throw new java.lang.UnsupportedOperationException (); + return font; } public FontMetrics getFontMetrics () { - throw new java.lang.UnsupportedOperationException (); + return Toolkit.getDefaultToolkit ().getFontMetrics (font); } public FontMetrics getFontMetrics (Font f) { - throw new java.lang.UnsupportedOperationException (); + return Toolkit.getDefaultToolkit ().getFontMetrics (f); } public void setFont (Font f) --- jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c 25 Oct 2003 18:41:45 -0000 1.2 +++ jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGraphics2D.c 18 Nov 2003 18:34:16 -0000 @@ -302,6 +302,8 @@ g_old = (struct graphics2d *) NSA_GET_G2D_PTR (env, old); g_assert (g_old != NULL); + if (g_old->debug) printf ("copying state from existing graphics2d\n"); + g->drawable = g_old->drawable; g->debug = g_old->debug; @@ -316,7 +318,7 @@ else init_graphics2d_as_pixbuf (g); - cairo_surface_set_filter (g->surface, CAIRO_FILTER_BILINEAR); + cairo_surface_set_filter (g->surface, CAIRO_FILTER_FAST); gdk_threads_leave (); @@ -649,36 +651,61 @@ } JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_drawPixels - (JNIEnv *env, jobject obj, jintArray jarr, jint w, jint h, jint stride) + (JNIEnv *env, jobject obj, jintArray java_pixels, + jint w, jint h, jint stride, jdoubleArray java_matrix) { struct graphics2d *gr = NULL; - jint *jpixels = NULL; + jint *native_pixels = NULL; + jdouble *native_matrix = 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); + (*env)->GetArrayLength (env, java_pixels), w, h, stride); - jpixels = (*env)->GetIntArrayElements (env, jarr, NULL); - g_assert (jpixels != NULL); + native_pixels = (*env)->GetIntArrayElements (env, java_pixels, NULL); + native_matrix = (*env)->GetDoubleArrayElements (env, java_matrix, NULL); + g_assert (native_pixels != NULL); + g_assert (native_matrix != NULL); + g_assert ((*env)->GetArrayLength (env, java_matrix) == 6); begin_drawing_operation (gr); - { - cairo_surface_t *surf = cairo_surface_create_for_image ((char *)jpixels, + cairo_matrix_t *mat = NULL; + cairo_surface_t *surf = cairo_surface_create_for_image ((char *)native_pixels, CAIRO_FORMAT_ARGB32, w, h, stride * 4); + mat = cairo_matrix_create (); + cairo_matrix_set_affine (mat, + native_matrix[0], native_matrix[1], + native_matrix[2], native_matrix[3], + native_matrix[4], native_matrix[5]); + cairo_surface_set_matrix (surf, mat); + if (native_matrix[0] != 1. + || native_matrix[1] != 0. + || native_matrix[2] != 0. + || native_matrix[3] != 1.) + { cairo_surface_set_filter (surf, CAIRO_FILTER_BILINEAR); + cairo_surface_set_filter (gr->surface, CAIRO_FILTER_BILINEAR); + } + else + { + cairo_surface_set_filter (surf, CAIRO_FILTER_FAST); + cairo_surface_set_filter (gr->surface, CAIRO_FILTER_FAST); + } cairo_show_surface (gr->cr, surf, w, h); + cairo_surface_set_filter (gr->surface, CAIRO_FILTER_FAST); + cairo_matrix_destroy (mat); cairo_surface_destroy (surf); } - end_drawing_operation (gr); - (*env)->ReleaseIntArrayElements (env, jarr, jpixels, 0); + (*env)->ReleaseIntArrayElements (env, java_pixels, native_pixels, 0); + (*env)->ReleaseDoubleArrayElements (env, java_matrix, native_matrix, 0); } @@ -706,25 +733,34 @@ } 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) + (JNIEnv *env, jobject obj, jdoubleArray java_matrix) { struct graphics2d *gr = NULL; + jdouble *native_matrix = NULL; + gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); g_assert (gr != NULL); - if (gr->debug) printf ("cairo_set_matrix\n"); + + native_matrix = (*env)->GetDoubleArrayElements (env, java_matrix, NULL); + g_assert (native_matrix != NULL); + g_assert ((*env)->GetArrayLength (env, java_matrix) == 6); + + if (gr->debug) printf ("cairo_set_matrix [ %f, %f, %f, %f, %f, %f ]\n", + native_matrix[0], native_matrix[1], + native_matrix[2], native_matrix[3], + native_matrix[4], native_matrix[5]); { cairo_matrix_t * mat = cairo_matrix_create (); cairo_matrix_set_affine (mat, - m00, m10, - m01, m11, - m02, m12); + native_matrix[0], native_matrix[1], + native_matrix[2], native_matrix[3], + native_matrix[4], native_matrix[5]); cairo_set_matrix (gr->cr, mat); cairo_matrix_destroy (mat); } + + (*env)->ReleaseDoubleArrayElements (env, java_matrix, native_matrix, 0); update_pattern_transform (gr); } @@ -750,8 +786,7 @@ ft = cairo_ft_font_create_for_ft_face (face); g_assert (ft != NULL); - if (gr->debug) printf ("cairo_set_font '%s'\n", - face->family_name); + if (gr->debug) printf ("cairo_set_font '%s'\n", face->family_name); cairo_set_font (gr->cr, ft); @@ -765,40 +800,46 @@ } JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGraphics2D_cairoShowGlyphs - (JNIEnv *env, jobject obj, jintArray jcodes, jfloatArray jposns, jint nglyphs) + (JNIEnv *env, jobject obj, jintArray java_codes, jfloatArray java_posns) { struct graphics2d *gr = NULL; cairo_glyph_t *glyphs = NULL; - jfloat *posns = NULL; - jint *codes = NULL; + jfloat *native_posns = NULL; + jint *native_codes = NULL; jint i; + jint ncodes, nposns; gr = (struct graphics2d *) NSA_GET_G2D_PTR (env, obj); g_assert (gr != NULL); - if (gr->debug) printf ("cairo_show_glyphs (%d glyphs)\n", nglyphs); + native_codes = (*env)->GetIntArrayElements (env, java_codes, NULL); + native_posns = (*env)->GetFloatArrayElements (env, java_posns, NULL); + g_assert (native_codes != NULL); + g_assert (native_posns != NULL); - glyphs = malloc (sizeof(cairo_glyph_t) * nglyphs); - g_assert (glyphs); + ncodes = (*env)->GetArrayLength (env, java_codes); + nposns = (*env)->GetArrayLength (env, java_posns); + g_assert (2 * ncodes == nposns); - codes = (*env)->GetIntArrayElements (env, jcodes, NULL); - g_assert (codes != NULL); + if (gr->debug) printf ("cairo_show_glyphs (%d glyphs)\n", ncodes); - posns = (*env)->GetFloatArrayElements (env, jposns, NULL); - g_assert (posns != NULL); + glyphs = malloc (sizeof(cairo_glyph_t) * ncodes); + g_assert (glyphs); - for (i = 0; i < nglyphs; ++i) + for (i = 0; i < ncodes; ++i) { - glyphs[i].index = codes[i]; - glyphs[i].x = (double) posns[2*i]; - glyphs[i].y = (double) posns[2*i + 1]; + glyphs[i].index = native_codes[i]; + glyphs[i].x = (double) native_posns[2*i]; + glyphs[i].y = (double) native_posns[2*i + 1]; + if (gr->debug) printf ("cairo_show_glyphs (glyph %d (code %d) : %f,%f)\n", + i, glyphs[i].index, glyphs[i].x, glyphs[i].y); } - (*env)->ReleaseIntArrayElements (env, jcodes, codes, 0); - (*env)->ReleaseFloatArrayElements (env, jposns, posns, 0); + (*env)->ReleaseIntArrayElements (env, java_codes, native_codes, 0); + (*env)->ReleaseFloatArrayElements (env, java_posns, native_posns, 0); begin_drawing_operation (gr); - cairo_show_glyphs (gr->cr, glyphs, nglyphs); + cairo_show_glyphs (gr->cr, glyphs, ncodes); end_drawing_operation (gr); free(glyphs); @@ -991,38 +1032,6 @@ 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) --- jni/gtk-peer/gnu_java_awt_peer_gtk_GdkClasspathFontPeer.c 25 Oct 2003 18:41:45 -0000 1.1 +++ jni/gtk-peer/gnu_java_awt_peer_gtk_GdkClasspathFontPeer.c 18 Nov 2003 18:34:16 -0000 @@ -120,6 +120,13 @@ pfont = (struct peerfont *)NSA_GET_FONT_PTR (env, self); g_assert (pfont != NULL); + if (pfont->ctx != NULL) + g_object_unref (pfont->ctx); + if (pfont->font != NULL) + g_object_unref (pfont->font); + if (pfont->desc != NULL) + pango_font_description_free (pfont->desc); + pfont->desc = pango_font_description_new (); g_assert (pfont->desc != NULL); --- jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGlyphVector.c 25 Oct 2003 18:41:45 -0000 1.1 +++ jni/gtk-peer/gnu_java_awt_peer_gtk_GdkGlyphVector.c 18 Nov 2003 18:34:16 -0000 @@ -40,6 +40,16 @@ struct state_table *native_glyphvector_state_table; +typedef struct { + double x; + double y; + double width; + double height; +} rect_t; + +#define DOUBLE_TO_26_6(d) ((FT_F26Dot6)((d) * 63.0)) +#define DOUBLE_FROM_26_6(t) (((double)((t) >> 6)) \ + + ((double)((t) & 0x3F) / 63.0)) JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_initStaticState (JNIEnv *env, jclass clazz) @@ -64,9 +74,12 @@ vec = (struct glyphvec *) g_malloc0 (sizeof (struct glyphvec)); g_assert (vec != NULL); - vec->desc = pango_font_description_copy (pfont->desc); + vec->desc = pango_font_describe (pfont->font); g_assert (vec->desc != NULL); + vec->font = pfont->font; + g_object_ref (vec->font); + vec->ctx = pfont->ctx; g_object_ref (vec->ctx); @@ -150,10 +163,10 @@ *g = gs->glyphs + nidx; } -static void union_rects (PangoRectangle *r1, - const PangoRectangle *r2) +static void union_rects (rect_t *r1, + const rect_t *r2) { - PangoRectangle r; + rect_t r; g_assert (r1 != NULL); g_assert (r2 != NULL); @@ -184,7 +197,7 @@ *r1 = r; } -static jdoubleArray rect_to_array (JNIEnv *env, const PangoRectangle *r) +static jdoubleArray rect_to_array (JNIEnv *env, const rect_t *r) { /* We often return rectangles as arrays : { x, y, w, h } */ jdoubleArray ret; @@ -193,11 +206,11 @@ ret = (*env)->NewDoubleArray (env, 4); rp = (*env)->GetDoubleArrayElements (env, ret, NULL); g_assert (rp != NULL); - rp[0] = r->x / (double)PANGO_SCALE; + rp[0] = r->x; /* freetype and pango's view of space is upside down from java2d's */ - rp[1] = (r->y / (double)PANGO_SCALE) * -1; - rp[2] = r->width / (double)PANGO_SCALE; - rp[3] = r->height / (double)PANGO_SCALE; + rp[1] = r->y * -1; + rp[2] = r->width; + rp[3] = r->height; (*env)->ReleaseDoubleArrayElements (env, ret, rp, 0); return ret; } @@ -251,18 +264,14 @@ str = (gchar *)(*env)->GetStringUTFChars (env, chars, NULL); g_assert (str != NULL); - /* step 1: mark the text as having our FontFescription as an - attribute, then "itemize" the text */ + /* step 1: set our FontFescription in the context, then "itemize" the + text */ attrs = pango_attr_list_new (); g_assert (attrs != NULL); - PangoAttribute *da = pango_attr_font_desc_new(vec->desc); - g_assert (da != NULL); - da->start_index = 0; - da->end_index = len; + pango_context_set_font_description (vec->ctx, vec->desc); - pango_attr_list_insert (attrs, da); items = pango_itemize (vec->ctx, str, 0, len, attrs, NULL); g_assert (items != NULL); @@ -393,15 +402,19 @@ } -JNIEXPORT jdoubleArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_allLogicalExtents +JNIEXPORT jdoubleArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_allInkExtents (JNIEnv *env, jobject self) { struct glyphvec *vec = NULL; + int j; GList *i; PangoGlyphItem *gi = NULL; - PangoRectangle rect = {0,0,0,0}; - PangoRectangle tmp, dummy; + rect_t rect = {0,0,0,0}; + rect_t tmp; jdoubleArray ret; + double x = 0, y = 0; + double pointsize; + FT_Face face; gdk_threads_enter (); g_assert (self != NULL); @@ -409,17 +422,33 @@ g_assert (vec != NULL); g_assert (vec->glyphitems != NULL); + pointsize = pango_font_description_get_size (vec->desc); + pointsize /= (double) PANGO_SCALE; + for (i = g_list_first (vec->glyphitems); i != NULL; i = g_list_next (i)) { g_assert (i->data != NULL); gi = (PangoGlyphItem *)i->data; g_assert (gi->glyphs != NULL); - pango_glyph_string_extents (gi->glyphs, - gi->item->analysis.font, - &dummy, - &tmp); + face = pango_ft2_font_get_face (gi->item->analysis.font); + FT_Set_Char_Size( face, + DOUBLE_TO_26_6 (pointsize), + DOUBLE_TO_26_6 (pointsize), + 0, 0); + + for (j = 0; j < gi->glyphs->num_glyphs; ++j) + { + FT_Load_Glyph (face, gi->glyphs->glyphs[j].glyph, FT_LOAD_DEFAULT); + /* FIXME: this needs to change for vertical layouts */ + tmp.x = x + DOUBLE_FROM_26_6 (face->glyph->metrics.horiBearingX); + tmp.y = y + DOUBLE_FROM_26_6 (face->glyph->metrics.horiBearingY); + tmp.width = DOUBLE_FROM_26_6 (face->glyph->metrics.width); + tmp.height = DOUBLE_FROM_26_6 (face->glyph->metrics.height); union_rects (&rect, &tmp); + x += DOUBLE_FROM_26_6 (face->glyph->advance.x); + y += DOUBLE_FROM_26_6 (face->glyph->advance.y); + } } ret = rect_to_array (env, &rect); @@ -428,15 +457,19 @@ } -JNIEXPORT jdoubleArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_allInkExtents +JNIEXPORT jdoubleArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_allLogicalExtents (JNIEnv *env, jobject self) { struct glyphvec *vec = NULL; + int j; GList *i; PangoGlyphItem *gi = NULL; - PangoRectangle rect = {0,0,0,0}; - PangoRectangle tmp, dummy; + rect_t rect = {0,0,0,0}; + rect_t tmp; jdoubleArray ret; + double x = 0, y = 0; + double pointsize; + FT_Face face; gdk_threads_enter (); g_assert (self != NULL); @@ -444,17 +477,38 @@ g_assert (vec != NULL); g_assert (vec->glyphitems != NULL); + pointsize = pango_font_description_get_size (vec->desc); + pointsize /= (double) PANGO_SCALE; + for (i = g_list_first (vec->glyphitems); i != NULL; i = g_list_next (i)) { g_assert (i->data != NULL); gi = (PangoGlyphItem *)i->data; g_assert (gi->glyphs != NULL); - pango_glyph_string_extents (gi->glyphs, - gi->item->analysis.font, - &tmp, - &dummy); + face = pango_ft2_font_get_face (gi->item->analysis.font); + FT_Set_Char_Size( face, + DOUBLE_TO_26_6 (pointsize), + DOUBLE_TO_26_6 (pointsize), + 0, 0); + + for (j = 0; j < gi->glyphs->num_glyphs; ++j) + { + FT_Load_Glyph (face, gi->glyphs->glyphs[j].glyph, FT_LOAD_DEFAULT); + + /* FIXME: also, this is probably not the correct set of metrics; + the "logical bounds" are some fancy combination of hori + advance and height such that it's good for inverting as a + highlight. revisit. */ + + tmp.x = x; + tmp.y = y; + tmp.width = DOUBLE_FROM_26_6 (face->glyph->advance.x); + tmp.height = DOUBLE_FROM_26_6 (face->glyph->advance.y); union_rects (&rect, &tmp); + x += DOUBLE_FROM_26_6 (face->glyph->advance.x); + y += DOUBLE_FROM_26_6 (face->glyph->advance.y); + } } ret = rect_to_array (env, &rect); @@ -462,15 +516,17 @@ return ret; } + JNIEXPORT jdoubleArray JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_glyphLogicalExtents (JNIEnv *env, jobject self, jint idx) { struct glyphvec *vec = NULL; - PangoRectangle rect = {0,0,0,0}; - PangoRectangle dummy; + rect_t rect = {0,0,0,0}; PangoGlyphInfo *gi = NULL; PangoFont *font = NULL; jdoubleArray ret; + double pointsize; + FT_Face face; gdk_threads_enter (); g_assert (self != NULL); @@ -482,7 +538,25 @@ g_assert (gi != NULL); g_assert (font != NULL); - pango_font_get_glyph_extents (font, gi->glyph, &dummy, &rect); + pointsize = pango_font_description_get_size (vec->desc); + pointsize /= (double) PANGO_SCALE; + face = pango_ft2_font_get_face (font); + FT_Set_Char_Size( face, + DOUBLE_TO_26_6 (pointsize), + DOUBLE_TO_26_6 (pointsize), + 0, 0); + + FT_Load_Glyph (face, gi->glyph, FT_LOAD_DEFAULT); + + /* FIXME: this is probably not the correct set of metrics; + the "logical bounds" are some fancy combination of hori + advance and height such that it's good for inverting as a + highlight. revisit. */ + + rect.x = 0; + rect.y = 0; + rect.width = DOUBLE_FROM_26_6 (face->glyph->advance.x); + rect.height = DOUBLE_FROM_26_6 (face->glyph->advance.y); ret = rect_to_array (env, &rect); gdk_threads_leave (); @@ -494,11 +568,12 @@ (JNIEnv *env, jobject self, jint idx) { struct glyphvec *vec = NULL; - PangoRectangle rect = {0,0,0,0}; - PangoRectangle dummy; + rect_t rect = {0,0,0,0}; PangoGlyphInfo *gi = NULL; PangoFont *font = NULL; jdoubleArray ret; + double pointsize; + FT_Face face; gdk_threads_enter (); g_assert (self != NULL); @@ -510,12 +585,26 @@ g_assert (gi != NULL); g_assert (font != NULL); - pango_font_get_glyph_extents (font, gi->glyph, &rect, &dummy); + pointsize = pango_font_description_get_size (vec->desc); + pointsize /= (double) PANGO_SCALE; + face = pango_ft2_font_get_face (font); + FT_Set_Char_Size( face, + DOUBLE_TO_26_6 (pointsize), + DOUBLE_TO_26_6 (pointsize), + 0, 0); + + FT_Load_Glyph (face, gi->glyph, FT_LOAD_DEFAULT); + /* FIXME: this needs to change for vertical layouts */ + rect.x = DOUBLE_FROM_26_6 (face->glyph->metrics.horiBearingX); + rect.y = DOUBLE_FROM_26_6 (face->glyph->metrics.horiBearingY); + rect.width = DOUBLE_FROM_26_6 (face->glyph->metrics.width); + rect.height = DOUBLE_FROM_26_6 (face->glyph->metrics.height); ret = rect_to_array (env, &rect); gdk_threads_leave (); return ret; } + JNIEXPORT jboolean JNICALL Java_gnu_java_awt_peer_gtk_GdkGlyphVector_glyphIsHorizontal (JNIEnv *env, jobject self, jint idx)