Hi, Attached is a patch to optimize ellipse drawing in java2d. I'm seeing a ~25% speed boost from it on both draw and fill.
Also, ignore my earlier patch re alpha composite; I realised that it doesn't work with gradients/textures, and am working on a better patch. Francis 2006-07-12 Francis Kung <[EMAIL PROTECTED]> * gnu/java/awt/peer/gtk/CairoGraphics2D.java: Organized imports. (cairoArc): New native method. (cairoRestore): New native method. (cairoSave): New native method. (cairoScale): New native method. (createPath): New method to centralize code from draw and fill. (draw): Modified to use createPath method. (fill): Modified to use createPath method. * include/gnu_java_awt_peer_gtk_CairoGraphics2D.h: Added function declarations. * native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c (Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoScale): New method. (Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSave): New method. (Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoArc): New method.
Index: gnu/java/awt/peer/gtk/CairoGraphics2D.java =================================================================== RCS file: /cvsroot/classpath/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java,v retrieving revision 1.29 diff -u -r1.29 CairoGraphics2D.java --- gnu/java/awt/peer/gtk/CairoGraphics2D.java 30 Jun 2006 17:39:14 -0000 1.29 +++ gnu/java/awt/peer/gtk/CairoGraphics2D.java 12 Jul 2006 18:18:58 -0000 @@ -40,8 +40,8 @@ import gnu.java.awt.ClasspathToolkit; -import java.awt.AlphaComposite; import java.awt.AWTPermission; +import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; @@ -53,11 +53,11 @@ import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Paint; +import java.awt.Polygon; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Stroke; -import java.awt.Polygon; import java.awt.TexturePaint; import java.awt.Toolkit; import java.awt.font.FontRenderContext; @@ -66,6 +66,7 @@ import java.awt.geom.AffineTransform; import java.awt.geom.Arc2D; import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.PathIterator; @@ -322,6 +323,11 @@ * Set the current transform matrix */ private native void cairoSetMatrix(long pointer, double[] m); + + /** + * Scaling method + */ + private native void cairoScale(long pointer, double x, double y); /** * Set the compositing operator @@ -369,6 +375,18 @@ */ private native void cairoRectangle(long pointer, double x, double y, double width, double height); + + /** + * Appends an arc to the current path + */ + private native void cairoArc(long pointer, double x, double y, + double radius, double angle1, double angle2); + + /** + * Save / restore a cairo path + */ + private native void cairoSave(long pointer); + private native void cairoRestore(long pointer); /** * New current path @@ -920,36 +938,71 @@ return; } - cairoNewPath(nativePointer); - - if (s instanceof Rectangle2D) - { - Rectangle2D r = (Rectangle2D) s; - cairoRectangle(nativePointer, shifted(r.getX(), shiftDrawCalls), - shifted(r.getY(), shiftDrawCalls), r.getWidth(), - r.getHeight()); - } - else - walkPath(s.getPathIterator(null), shiftDrawCalls); + createPath(s); cairoStroke(nativePointer); } public void fill(Shape s) { + createPath(s); + + double alpha = 1.0; + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + cairoFill(nativePointer, alpha); + } + + private void createPath(Shape s) + { cairoNewPath(nativePointer); + + // Optimize rectangles, since there is a direct Cairo function if (s instanceof Rectangle2D) { - Rectangle2D r = (Rectangle2D) s; - cairoRectangle(nativePointer, r.getX(), r.getY(), r.getWidth(), + Rectangle2D r = (Rectangle2D) s; + cairoRectangle(nativePointer, shifted(r.getX(), shiftDrawCalls), + shifted(r.getY(), shiftDrawCalls), r.getWidth(), r.getHeight()); } - else - walkPath(s.getPathIterator(null), false); - double alpha = 1.0; - if (comp instanceof AlphaComposite) - alpha = ((AlphaComposite) comp).getAlpha(); - cairoFill(nativePointer, alpha); + // We can optimize ellipses too; however we don't bother optimizing arcs: + // the iterator is fast enough (an ellipse requires 5 steps using the + // iterator, while most arcs are only 2-3) + else if (s instanceof Ellipse2D) + { + Ellipse2D e = (Ellipse2D) s; + + double radius = Math.min(e.getHeight(), e.getWidth()) / 2; + + // Cairo only draws circular shapes, but we can use a stretch to make + // them into ellipses + double xscale = 1, yscale = 1; + if (e.getHeight() != e.getWidth()) + { + cairoSave(nativePointer); + + if (e.getHeight() < e.getWidth()) + xscale = e.getWidth() / (radius * 2); + else + yscale = e.getHeight() / (radius * 2); + + if (xscale != 1 || yscale != 1) + cairoScale(nativePointer, xscale, yscale); + } + + cairoArc(nativePointer, + shifted(e.getCenterX() / xscale, shiftDrawCalls), + shifted(e.getCenterY() / yscale, shiftDrawCalls), radius, 0, + Math.PI * 2); + + if (xscale != 1 || yscale != 1) + cairoRestore(nativePointer); + } + + // All other shapes are broken down and drawn in steps using the + // PathIterator + else + walkPath(s.getPathIterator(null), shiftDrawCalls); } /** Index: include/gnu_java_awt_peer_gtk_CairoGraphics2D.h =================================================================== RCS file: /cvsroot/classpath/classpath/include/gnu_java_awt_peer_gtk_CairoGraphics2D.h,v retrieving revision 1.7 diff -u -r1.7 gnu_java_awt_peer_gtk_CairoGraphics2D.h --- include/gnu_java_awt_peer_gtk_CairoGraphics2D.h 14 Jun 2006 13:51:04 -0000 1.7 +++ include/gnu_java_awt_peer_gtk_CairoGraphics2D.h 12 Jul 2006 18:18:59 -0000 @@ -16,6 +16,7 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_setGradient (JNIEnv *env, jobject, jlong, jdouble, jdouble, jdouble, jdouble, jint, jint, jint, jint, jint, jint, jint, jint, jboolean); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_setTexturePixels (JNIEnv *env, jobject, jlong, jintArray, jint, jint, jint); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSetMatrix (JNIEnv *env, jobject, jlong, jdoubleArray); +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoScale (JNIEnv *env, jobject, jlong, jdouble, jdouble); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSetOperator (JNIEnv *env, jobject, jlong, jint); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSetRGBAColor (JNIEnv *env, jobject, jlong, jdouble, jdouble, jdouble, jdouble); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSetFillRule (JNIEnv *env, jobject, jlong, jint); @@ -24,6 +25,9 @@ JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoDrawGlyphVector (JNIEnv *env, jobject, jlong, jobject, jfloat, jfloat, jint, jintArray, jfloatArray); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoRelCurveTo (JNIEnv *env, jobject, jlong, jdouble, jdouble, jdouble, jdouble, jdouble, jdouble); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoRectangle (JNIEnv *env, jobject, jlong, jdouble, jdouble, jdouble, jdouble); +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoArc (JNIEnv *env, jobject, jlong, jdouble, jdouble, jdouble, jdouble, jdouble); +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSave (JNIEnv *env, jobject, jlong); +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoRestore (JNIEnv *env, jobject, jlong); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoNewPath (JNIEnv *env, jobject, jlong); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoClosePath (JNIEnv *env, jobject, jlong); JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoMoveTo (JNIEnv *env, jobject, jlong, jdouble, jdouble); Index: native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c =================================================================== RCS file: /cvsroot/classpath/classpath/native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c,v retrieving revision 1.11 diff -u -r1.11 gnu_java_awt_peer_gtk_CairoGraphics2D.c --- native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c 14 Jun 2006 13:51:04 -0000 1.11 +++ native/jni/gtk-peer/gnu_java_awt_peer_gtk_CairoGraphics2D.c 12 Jul 2006 18:19:01 -0000 @@ -263,6 +263,17 @@ } JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoScale +(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), + jlong pointer, jdouble x, jdouble y) +{ + struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, pointer); + g_assert (gr != NULL); + + cairo_scale (gr->cr, x, y); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoDrawGlyphVector (JNIEnv *env, jobject obj, jlong pointer, jobject font, @@ -473,6 +484,28 @@ } JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoSave +(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), + jlong pointer) +{ + struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, pointer); + g_assert (gr != NULL); + + cairo_save (gr->cr); +} + +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoRestore +(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), + jlong pointer) +{ + struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, pointer); + g_assert (gr != NULL); + + cairo_restore (gr->cr); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoNewPath (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), jlong pointer) @@ -561,6 +594,17 @@ } JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoArc +(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), + jlong pointer, jdouble x, jdouble y, jdouble radius, jdouble angle1, + jdouble angle2) +{ + struct cairographics2d *gr = JLONG_TO_PTR(struct cairographics2d, pointer); + + cairo_arc (gr->cr, x, y, radius, angle1, angle2); +} + +JNIEXPORT void JNICALL Java_gnu_java_awt_peer_gtk_CairoGraphics2D_cairoClosePath (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)), jlong pointer)