< prev index next >

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

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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

@@ -26,42 +26,44 @@
 
 import java.awt.BasicStroke;
 import java.awt.Rectangle;
 import java.awt.Shape;
 import java.awt.geom.Rectangle2D;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import sun.awt.SunHints;
 import sun.java2d.SunGraphics2D;
 
 /**
  * This class is used to convert raw geometry into 8-bit alpha tiles
  * using an AATileGenerator for application by the next stage of
  * the pipeline.
  * This class sets up the Generator and computes the alpha tiles
  * and then passes them on to a CompositePipe object for painting.
  */
-public class AAShapePipe
+public final class AAShapePipe
     implements ShapeDrawPipe, ParallelogramPipe
 {
-    static RenderingEngine renderengine = RenderingEngine.getInstance();
+    static final 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>() {
+    private static final ReentrantThreadLocal<TileState> tileStateThreadLocal =
+            new ReentrantThreadLocal<TileState>() {
         @Override
         protected TileState initialValue() {
             return new TileState();
         }
     };
 
-    CompositePipe outpipe;
+    final CompositePipe outpipe;
 
     public AAShapePipe(CompositePipe pipe) {
         outpipe = pipe;
     }
 
+    @Override
     public void draw(SunGraphics2D sg, Shape s) {
-        BasicStroke bs;
+        final BasicStroke bs;
 
         if (sg.stroke instanceof BasicStroke) {
             bs = (BasicStroke) sg.stroke;
         } else {
             s = sg.stroke.createStrokedShape(s);

@@ -69,107 +71,119 @@
         }
 
         renderPath(sg, s, bs);
     }
 
+    @Override
     public void fill(SunGraphics2D sg, Shape s) {
         renderPath(sg, s, null);
     }
 
+    @Override
     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();
         final TileState ts = tileStateThreadLocal.get();
-        final int[] abox = ts.abox;
+        try {
+            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;
+            final AATileGenerator aatg =
+                renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, 0, 0,
+                                                sg.getCompClip(), abox);
+            if (aatg != null) {
+                renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2),
+                            aatg, abox, ts);
+            }
+        } finally {
+            tileStateThreadLocal.restore(ts);
         }
-
-        renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), aatg, abox, ts);
     }
 
+    @Override
     public void drawParallelogram(SunGraphics2D sg,
                                   double ux1, double uy1,
                                   double ux2, double uy2,
                                   double x, double y,
                                   double dx1, double dy1,
                                   double dx2, double dy2,
                                   double lw1, double lw2)
     {
-        Region clip = sg.getCompClip();
         final TileState ts = tileStateThreadLocal.get();
-        final int[] abox = ts.abox;
+        try {
+            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;
+            final AATileGenerator aatg =
+                renderengine.getAATileGenerator(x, y, dx1, dy1, dx2, dy2, lw1,
+                                                lw2, sg.getCompClip(), abox);
+            if (aatg != null) {
+                // Note that bbox is of the original shape, not the wide path.
+                // This is appropriate for handing to Paint methods...
+                renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2),
+                            aatg, abox, ts);
+            }
+        } finally {
+            tileStateThreadLocal.restore(ts);
         }
-
-        // Note that bbox is of the original shape, not the wide path.
-        // This is appropriate for handing to Paint methods...
-        renderTiles(sg, ts.computeBBox(ux1, uy1, ux2, uy2), aatg, abox, ts);
     }
 
     public void renderPath(SunGraphics2D sg, Shape s, BasicStroke bs) {
-        boolean adjust = (bs != null &&
+        final boolean adjust = (bs != null &&
                           sg.strokeHint != SunHints.INTVAL_STROKE_PURE);
-        boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED);
+        final boolean thin = (sg.strokeState <= SunGraphics2D.STROKE_THINDASHED);
 
-        Region clip = sg.getCompClip();
         final TileState ts = tileStateThreadLocal.get();
-        final int[] abox = ts.abox;
+        try {
+            final int[] abox = ts.abox;
 
-        AATileGenerator aatg =
-            renderengine.getAATileGenerator(s, sg.transform, clip,
-                                            bs, thin, adjust, abox);
-        if (aatg == null) {
-            // Nothing to render
-            return;
+            final AATileGenerator aatg =
+                renderengine.getAATileGenerator(s, sg.transform, sg.getCompClip(),
+                                                bs, thin, adjust, abox);
+            if (aatg != null) {
+                renderTiles(sg, s, aatg, abox, ts);
+            }
+        } finally {
+            tileStateThreadLocal.restore(ts);
         }
-
-        renderTiles(sg, s, aatg, abox, ts);
     }
 
     public void renderTiles(SunGraphics2D sg, Shape s,
-                            AATileGenerator aatg, int abox[], TileState ts)
+                            final AATileGenerator aatg,
+                            final int[] abox, final TileState ts)
     {
         Object context = null;
         try {
+            // reentrance: outpipe may also use AAShapePipe:
             context = outpipe.startSequence(sg, s,
                                             ts.computeDevBox(abox),
                                             abox);
 
+            // copy of int[] abox as local variables for performance:
+            final int x0 = abox[0];
+            final int y0 = abox[1];
+            final int x1 = abox[2];
+            final int y1 = abox[3];
+
             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 y = y0; y < y1; y += th) {
+                final int h = Math.min(th, y1 - y);
 
-                for (int x = abox[0]; x < abox[2]; x += tw) {
-                    int w = Math.min(tw, abox[2] - x);
+                for (int x = x0; x < x1; x += tw) {
+                    final int w = Math.min(tw, x1 - x);
 
-                    int a = aatg.getTypicalAlpha();
-                    if (a == 0x00 ||
-                        outpipe.needTile(context, x, y, w, h) == false)
-                    {
+                    final int a = aatg.getTypicalAlpha();
+
+                    if (a == 0x00 || !outpipe.needTile(context, x, y, w, h)) {
                         aatg.nextTile();
                         outpipe.skipTile(context, x, y);
                         continue;
                     }
                     if (a == 0xff) {

@@ -178,12 +192,11 @@
                     } else {
                         atile = alpha;
                         aatg.getAlpha(alpha, 0, tw);
                     }
 
-                    outpipe.renderPathTile(context, atile, 0, tw,
-                                           x, y, w, h);
+                    outpipe.renderPathTile(context, atile, 0, tw, x, y, w, h);
                 }
             }
         } finally {
             aatg.dispose();
             if (context != null) {

@@ -191,11 +204,11 @@
             }
         }
     }
 
     // Tile state used by AAShapePipe
-    static final class TileState {
+    static final class TileState extends ReentrantContext {
         // 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

@@ -239,6 +252,55 @@
             box.height = uy2;
             return box;
         }
     }
 
+    static class ReentrantThreadLocal<K extends ReentrantContext>
+        extends ThreadLocal<K>
+    {
+        final static int DEPTH_UNDEFINED = 0;
+        final static int DEPTH_TL = 1;
+        final static int DEPTH_CLQ = 2;
+
+        // ReentrantContext queue for child contexts
+        private final ConcurrentLinkedQueue<K> ctxQueue
+            = new ConcurrentLinkedQueue<K>();
+
+        /**
+         * Give a ReentrantContext instance from thread-local or CLQ storage
+         * @return ReentrantContext instance
+         */
+        @Override
+        public final K get() {
+            K ctx = super.get();
+            // Check reentrance:
+            if (ctx.depth == ReentrantThreadLocal.DEPTH_UNDEFINED) {
+                ctx.depth = ReentrantThreadLocal.DEPTH_TL;
+            } else {
+                // get or create another ReentrantContext from queue:
+                ctx = ctxQueue.poll();
+                if (ctx == null) {
+                    // create a new ReentrantContext if none is available
+                    ctx = initialValue();
+                    ctx.depth = ReentrantThreadLocal.DEPTH_CLQ;
+                }
+            }
+            return ctx;
+        }
+
+        /**
+         * Restore the given ReentrantContext instance for reuse
+         * @param ctx ReentrantContext instance
+         */
+        public final void restore(final K ctx) {
+            if (ctx.depth == ReentrantThreadLocal.DEPTH_TL) {
+                ctx.depth = ReentrantThreadLocal.DEPTH_UNDEFINED;
+            } else {
+                ctxQueue.offer(ctx);
+            }
+        }
+    }
+
+    static class ReentrantContext {
+        int depth = ReentrantThreadLocal.DEPTH_UNDEFINED;
+    }
 }
< prev index next >