src/java.desktop/share/classes/sun/java2d/pipe/AAShapePipe.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -20,18 +20,16 @@
  *
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-
 package sun.java2d.pipe;
 
 import java.awt.BasicStroke;
 import java.awt.Rectangle;
 import java.awt.Shape;
 import java.awt.geom.Rectangle2D;
-import java.awt.geom.PathIterator;
 import sun.awt.SunHints;
 import sun.java2d.SunGraphics2D;
 
 /**
  * This class is used to convert raw geometry into 8-bit alpha tiles

@@ -43,10 +41,19 @@
 public class AAShapePipe
     implements ShapeDrawPipe, ParallelogramPipe
 {
     static RenderingEngine renderengine = RenderingEngine.getInstance();
 
+    // Per-thread TileState (~1K very small so do not use any Weak Reference)
+    private static final ThreadLocal<TileState> tileStateThreadLocal =
+            new ThreadLocal<TileState>() {
+        @Override
+        protected TileState initialValue() {
+            return new TileState();
+        }
+    };
+
     CompositePipe outpipe;
 
     public AAShapePipe(CompositePipe pipe) {
         outpipe = pipe;
     }

@@ -66,42 +73,30 @@
 
     public void fill(SunGraphics2D sg, Shape s) {
         renderPath(sg, s, null);
     }
 
-    private static Rectangle2D computeBBox(double ux1, double uy1,
-                                           double ux2, double uy2)
-    {
-        if ((ux2 -= ux1) < 0) {
-            ux1 += ux2;
-            ux2 = -ux2;
-        }
-        if ((uy2 -= uy1) < 0) {
-            uy1 += uy2;
-            uy2 = -uy2;
-        }
-        return new Rectangle2D.Double(ux1, uy1, ux2, uy2);
-    }
-
     public void fillParallelogram(SunGraphics2D sg,
                                   double ux1, double uy1,
                                   double ux2, double uy2,
                                   double x, double y,
                                   double dx1, double dy1,
                                   double dx2, double dy2)
     {
         Region clip = sg.getCompClip();
-        int abox[] = new int[4];
+        final TileState ts = tileStateThreadLocal.get();
+        final int[] abox = ts.abox;
+
         AATileGenerator aatg =
             renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0,
                                             clip, abox);
         if (aatg == null) {
             // Nothing to render
             return;
         }
 
-        renderTiles(sg, computeBBox(ux1, uy1, ux2, uy2), aatg, abox);
+        renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), aatg, abox, ts);
     }
 
     public void drawParallelogram(SunGraphics2D sg,
                                   double ux1, double uy1,
                                   double ux2, double uy2,

@@ -109,80 +104,67 @@
                                   double dx1, double dy1,
                                   double dx2, double dy2,
                                   double lw1, double lw2)
     {
         Region clip = sg.getCompClip();
-        int abox[] = new int[4];
+        final TileState ts = tileStateThreadLocal.get();
+        final int[] abox = ts.abox;
+
         AATileGenerator aatg =
             renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1, lw2,
                                             clip, abox);
         if (aatg == null) {
             // Nothing to render
             return;
         }
 
         // Note that bbox is of the original shape, not the wide path.
         // This is appropriate for handing to Paint methods...
-        renderTiles(sg, computeBBox(ux1, uy1, ux2, uy2), aatg, abox);
-    }
-
-    private static byte[] theTile;
-
-    private static synchronized byte[] getAlphaTile(int len) {
-        byte[] t = theTile;
-        if (t == null || t.length < len) {
-            t = new byte[len];
-        } else {
-            theTile = null;
-        }
-        return t;
-    }
-
-    private static synchronized void dropAlphaTile(byte[] t) {
-        theTile = t;
+        renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), aatg, abox, ts);
     }
 
     public void renderPath(SunGraphics2D sg, Shape s, BasicStroke bs) {
         boolean adjust = (bs != null &&
                           sg.strokeHint != SunHints.INTVAL_STROKE_PURE);
         boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED);
 
         Region clip = sg.getCompClip();
-        int abox[] = new int[4];
+        final TileState ts = tileStateThreadLocal.get();
+        final int[] abox = ts.abox;
+
         AATileGenerator aatg =
             renderengine.getAATileGenerator(s, sg.transform, clip,
                                             bs, thin, adjust, abox);
         if (aatg == null) {
             // Nothing to render
             return;
         }
 
-        renderTiles(sg, s, aatg, abox);
+        renderTiles(sg, s, aatg, abox, ts);
     }
 
     public void renderTiles(SunGraphics2D sg, Shape s,
-                            AATileGenerator aatg, int abox[])
+                            AATileGenerator aatg, int abox[], TileState ts)
     {
         Object context = null;
-        byte alpha[] = null;
         try {
             context = outpipe.startSequence(sg, s,
-                                            new Rectangle(abox[0], abox[1],
-                                                          abox[2] - abox[0],
-                                                          abox[3] - abox[1]),
+                                            ts.computeDevBox(abox),
                                             abox);
 
-            int tw = aatg.getTileWidth();
-            int th = aatg.getTileHeight();
-            alpha = getAlphaTile(tw * th);
+            final int tw = aatg.getTileWidth();
+            final int th = aatg.getTileHeight();
 
+            // get tile from thread local storage:
+            final byte[] alpha = ts.getAlphaTile(tw * th);
             byte[] atile;
 
             for (int y = abox[1]; y < abox[3]; y += th) {
+                int h = Math.min(th, abox[3] - y);
+
                 for (int x = abox[0]; x < abox[2]; x += tw) {
                     int w = Math.min(tw, abox[2] - x);
-                    int h = Math.min(th, abox[3] - y);
 
                     int a = aatg.getTypicalAlpha();
                     if (a == 0x00 ||
                         outpipe.needTile(context, x, y, w, h) == false)
                     {

@@ -205,11 +187,58 @@
         } finally {
             aatg.dispose();
             if (context != null) {
                 outpipe.endSequence(context);
             }
-            if (alpha != null) {
-                dropAlphaTile(alpha);
             }
         }
+
+    // Tile state used by AAShapePipe
+    static final class TileState {
+        // cached tile (32 x 32 tile by default)
+        private byte[] theTile = new byte[32 * 32];
+        // dirty aabox array
+        final int[] abox = new int[4];
+        // dirty bbox rectangle
+        private final Rectangle dev = new Rectangle();
+        // dirty bbox rectangle2D.Double
+        private final Rectangle2D.Double bbox2D = new Rectangle2D.Double();
+
+        byte[] getAlphaTile(int len) {
+            byte[] t = theTile;
+            if (t.length < len) {
+                // create a larger tile and may free current theTile (too small)
+                theTile = t = new byte[len];
+            }
+            return t;
+        }
+
+        Rectangle computeDevBox(final int[] abox) {
+            final Rectangle box = this.dev;
+            box.x = abox[0];
+            box.y = abox[1];
+            box.width = abox[2] - abox[0];
+            box.height = abox[3] - abox[1];
+            return box;
     }
+
+        Rectangle2D computeBBox(double ux1, double uy1,
+                                double ux2, double uy2)
+        {
+            if ((ux2 -= ux1) < 0.0) {
+                ux1 += ux2;
+                ux2 = -ux2;
+            }
+            if ((uy2 -= uy1) < 0.0) {
+                uy1 += uy2;
+                uy2 = -uy2;
+            }
+            final Rectangle2D.Double box = this.bbox2D;
+            box.x = ux1;
+            box.y = uy1;
+            box.width = ux2;
+            box.height = uy2;
+            return box;
+        }
+    }
+
 }