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)

Reply via email to