jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java
changeset 25859 3317bb8137f4
parent 24522 3a0bbf9f5e81
child 29922 7b9c1e1532cf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/java2d/loops/GraphicsPrimitive.java	Sun Aug 17 15:54:13 2014 +0100
@@ -0,0 +1,624 @@
+/*
+ * Copyright (c) 1997, 2011, 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
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * 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.
+ */
+
+/*
+ * @author Charlton Innovations, Inc.
+ */
+
+package sun.java2d.loops;
+
+import java.awt.image.BufferedImage;
+import java.awt.AlphaComposite;
+import java.awt.Rectangle;
+import sun.awt.image.BufImgSurfaceData;
+import sun.java2d.SurfaceData;
+import sun.java2d.pipe.Region;
+import java.lang.reflect.Field;
+import java.util.StringTokenizer;
+import java.util.Iterator;
+import java.util.HashMap;
+import java.util.Map;
+import java.io.PrintStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * defines interface for primitives which can be placed into
+ * the graphic component manager framework
+ */
+public abstract class GraphicsPrimitive {
+
+    protected static interface GeneralBinaryOp {
+        /**
+         * This method allows the setupGeneralBinaryOp method to set
+         * the converters into the General version of the Primitive.
+         */
+        public void setPrimitives(Blit srcconverter,
+                                  Blit dstconverter,
+                                  GraphicsPrimitive genericop,
+                                  Blit resconverter);
+
+        /**
+         * These 4 methods are implemented automatically for any
+         * GraphicsPrimitive.  They are used by setupGeneralBinaryOp
+         * to retrieve the information needed to find the right
+         * converter primitives.
+         */
+        public SurfaceType getSourceType();
+        public CompositeType getCompositeType();
+        public SurfaceType getDestType();
+        public String getSignature();
+        public int getPrimTypeID();
+    }
+
+    protected static interface GeneralUnaryOp {
+        /**
+         * This method allows the setupGeneralUnaryOp method to set
+         * the converters into the General version of the Primitive.
+         */
+        public void setPrimitives(Blit dstconverter,
+                                  GraphicsPrimitive genericop,
+                                  Blit resconverter);
+
+        /**
+         * These 3 methods are implemented automatically for any
+         * GraphicsPrimitive.  They are used by setupGeneralUnaryOp
+         * to retrieve the information needed to find the right
+         * converter primitives.
+         */
+        public CompositeType getCompositeType();
+        public SurfaceType getDestType();
+        public String getSignature();
+        public int getPrimTypeID();
+    }
+
+    /**
+    *  INSTANCE DATA MEMBERS DESCRIBING CHARACTERISTICS OF THIS PRIMITIVE
+    **/
+
+    // Making these be instance data members (instead of virtual methods
+    // overridden by subclasses) is actually cheaper, since each class
+    // is a singleton.  As instance data members with final accessors,
+    // accesses can be inlined.
+    private String methodSignature;
+    private int uniqueID;
+    private static int unusedPrimID = 1;
+
+    private SurfaceType sourceType;
+    private CompositeType compositeType;
+    private SurfaceType destType;
+
+    private long pNativePrim;   // Native blit loop info
+
+    public synchronized static final int makePrimTypeID() {
+        if (unusedPrimID > 255) {
+            throw new InternalError("primitive id overflow");
+        }
+        return unusedPrimID++;
+    }
+
+    public synchronized static final int makeUniqueID(int primTypeID,
+                                                      SurfaceType src,
+                                                      CompositeType cmp,
+                                                      SurfaceType dst)
+    {
+        return (primTypeID << 24) |
+            (dst.getUniqueID() << 16) |
+            (cmp.getUniqueID() << 8)  |
+            (src.getUniqueID());
+    }
+
+    /**
+     * Create a new GraphicsPrimitive with all of the required
+     * descriptive information.
+     */
+    protected GraphicsPrimitive(String methodSignature,
+                                int primTypeID,
+                                SurfaceType sourceType,
+                                CompositeType compositeType,
+                                SurfaceType destType)
+    {
+        this.methodSignature = methodSignature;
+        this.sourceType = sourceType;
+        this.compositeType = compositeType;
+        this.destType = destType;
+
+        if(sourceType == null || compositeType == null || destType == null) {
+            this.uniqueID = primTypeID << 24;
+        } else {
+            this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID,
+                                                           sourceType,
+                                                           compositeType,
+                                                           destType);
+        }
+    }
+
+    /**
+     * Create a new GraphicsPrimitive for native invocation
+     * with all of the required descriptive information.
+     */
+    protected GraphicsPrimitive(long pNativePrim,
+                                String methodSignature,
+                                int primTypeID,
+                                SurfaceType sourceType,
+                                CompositeType compositeType,
+                                SurfaceType destType)
+    {
+        this.pNativePrim = pNativePrim;
+        this.methodSignature = methodSignature;
+        this.sourceType = sourceType;
+        this.compositeType = compositeType;
+        this.destType = destType;
+
+        if(sourceType == null || compositeType == null || destType == null) {
+            this.uniqueID = primTypeID << 24;
+        } else {
+            this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID,
+                                                           sourceType,
+                                                           compositeType,
+                                                           destType);
+        }
+    }
+
+    /**
+    *   METHODS TO DESCRIBE THE SURFACES PRIMITIVES
+    *   CAN OPERATE ON AND THE FUNCTIONALITY THEY IMPLEMENT
+    **/
+
+    /**
+     * Gets instance ID of this graphics primitive.
+     *
+     * Instance ID is comprised of four distinct ids (ORed together)
+     * that uniquely identify each instance of a GraphicsPrimitive
+     * object. The four ids making up instance ID are:
+     * 1. primitive id - identifier shared by all primitives of the
+     * same type (eg. all Blits have the same primitive id)
+     * 2. sourcetype id - identifies source surface type
+     * 3. desttype id - identifies destination surface type
+     * 4. compositetype id - identifies composite used
+     *
+     * @return instance ID
+     */
+    public final int getUniqueID() {
+        return uniqueID;
+    }
+
+    /**
+     */
+    public final String getSignature() {
+        return methodSignature;
+    }
+
+    /**
+     * Gets unique id for this GraphicsPrimitive type.
+     *
+     * This id is used to identify the TYPE of primitive (Blit vs. BlitBg)
+     * as opposed to INSTANCE of primitive.
+     *
+     * @return primitive ID
+     */
+    public final int getPrimTypeID() {
+        return uniqueID >>> 24;
+    }
+
+    /**
+     */
+    public final long getNativePrim() {
+        return pNativePrim;
+    }
+
+    /**
+     */
+    public final SurfaceType getSourceType() {
+        return sourceType;
+    }
+
+    /**
+     */
+    public final CompositeType getCompositeType() {
+        return compositeType;
+    }
+
+    /**
+     */
+    public final SurfaceType getDestType() {
+        return destType;
+    }
+
+    /**
+     * Return true if this primitive can be used for the given signature
+     * surfaces, and composite.
+     *
+     * @param signature The signature of the given operation.  Must be
+     *          == (not just .equals) the signature string given by the
+     *          abstract class that declares the operation.
+     * @param srctype The surface type for the source of the operation
+     * @param comptype The composite type for the operation
+     * @param dsttype The surface type for the destination of the operation
+     */
+    public final boolean satisfies(String signature,
+                                   SurfaceType srctype,
+                                   CompositeType comptype,
+                                   SurfaceType dsttype)
+    {
+        if (signature != methodSignature) {
+            return false;
+        }
+        while (true) {
+            if (srctype == null) {
+                return false;
+            }
+            if (srctype.equals(sourceType)) {
+                break;
+            }
+            srctype = srctype.getSuperType();
+        }
+        while (true) {
+            if (comptype == null) {
+                return false;
+            }
+            if (comptype.equals(compositeType)) {
+                break;
+            }
+            comptype = comptype.getSuperType();
+        }
+        while (true) {
+            if (dsttype == null) {
+                return false;
+            }
+            if (dsttype.equals(destType)) {
+                break;
+            }
+            dsttype = dsttype.getSuperType();
+        }
+        return true;
+    }
+
+    //
+    // A version of satisfies used for regression testing
+    //
+    final boolean satisfiesSameAs(GraphicsPrimitive other) {
+        return (methodSignature == other.methodSignature &&
+                sourceType.equals(other.sourceType) &&
+                compositeType.equals(other.compositeType) &&
+                destType.equals(other.destType));
+    }
+
+    public abstract GraphicsPrimitive makePrimitive(SurfaceType srctype,
+                                                    CompositeType comptype,
+                                                    SurfaceType dsttype);
+
+    public abstract GraphicsPrimitive traceWrap();
+
+    static HashMap<Object, int[]> traceMap;
+
+    public static int traceflags;
+    public static String tracefile;
+    public static PrintStream traceout;
+
+    public static final int TRACELOG = 1;
+    public static final int TRACETIMESTAMP = 2;
+    public static final int TRACECOUNTS = 4;
+
+    static {
+        GetPropertyAction gpa = new GetPropertyAction("sun.java2d.trace");
+        String trace = AccessController.doPrivileged(gpa);
+        if (trace != null) {
+            boolean verbose = false;
+            int traceflags = 0;
+            StringTokenizer st = new StringTokenizer(trace, ",");
+            while (st.hasMoreTokens()) {
+                String tok = st.nextToken();
+                if (tok.equalsIgnoreCase("count")) {
+                    traceflags |= GraphicsPrimitive.TRACECOUNTS;
+                } else if (tok.equalsIgnoreCase("log")) {
+                    traceflags |= GraphicsPrimitive.TRACELOG;
+                } else if (tok.equalsIgnoreCase("timestamp")) {
+                    traceflags |= GraphicsPrimitive.TRACETIMESTAMP;
+                } else if (tok.equalsIgnoreCase("verbose")) {
+                    verbose = true;
+                } else if (tok.regionMatches(true, 0, "out:", 0, 4)) {
+                    tracefile = tok.substring(4);
+                } else {
+                    if (!tok.equalsIgnoreCase("help")) {
+                        System.err.println("unrecognized token: "+tok);
+                    }
+                    System.err.println("usage: -Dsun.java2d.trace="+
+                                       "[log[,timestamp]],[count],"+
+                                       "[out:<filename>],[help],[verbose]");
+                }
+            }
+            if (verbose) {
+                System.err.print("GraphicsPrimitive logging ");
+                if ((traceflags & GraphicsPrimitive.TRACELOG) != 0) {
+                    System.err.println("enabled");
+                    System.err.print("GraphicsPrimitive timetamps ");
+                    if ((traceflags & GraphicsPrimitive.TRACETIMESTAMP) != 0) {
+                        System.err.println("enabled");
+                    } else {
+                        System.err.println("disabled");
+                    }
+                } else {
+                    System.err.println("[and timestamps] disabled");
+                }
+                System.err.print("GraphicsPrimitive invocation counts ");
+                if ((traceflags & GraphicsPrimitive.TRACECOUNTS) != 0) {
+                    System.err.println("enabled");
+                } else {
+                    System.err.println("disabled");
+                }
+                System.err.print("GraphicsPrimitive trace output to ");
+                if (tracefile == null) {
+                    System.err.println("System.err");
+                } else {
+                    System.err.println("file '"+tracefile+"'");
+                }
+            }
+            GraphicsPrimitive.traceflags = traceflags;
+        }
+    }
+
+    public static boolean tracingEnabled() {
+        return (traceflags != 0);
+    }
+
+    private static PrintStream getTraceOutputFile() {
+        if (traceout == null) {
+            if (tracefile != null) {
+                FileOutputStream o = AccessController.doPrivileged(
+                    new PrivilegedAction<FileOutputStream>() {
+                        public FileOutputStream run() {
+                            try {
+                                return new FileOutputStream(tracefile);
+                            } catch (FileNotFoundException e) {
+                                return null;
+                            }
+                        }
+                    });
+                if (o != null) {
+                    traceout = new PrintStream(o);
+                } else {
+                    traceout = System.err;
+                }
+            } else {
+                traceout = System.err;
+            }
+        }
+        return traceout;
+    }
+
+    public static class TraceReporter extends Thread {
+        public static void setShutdownHook() {
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    TraceReporter t = new TraceReporter();
+                    t.setContextClassLoader(null);
+                    Runtime.getRuntime().addShutdownHook(t);
+                    return null;
+                }
+            });
+        }
+
+        public void run() {
+            PrintStream ps = getTraceOutputFile();
+            Iterator<Map.Entry<Object, int[]>> iterator =
+                traceMap.entrySet().iterator();
+            long total = 0;
+            int numprims = 0;
+            while (iterator.hasNext()) {
+                Map.Entry<Object, int[]> me = iterator.next();
+                Object prim = me.getKey();
+                int[] count = me.getValue();
+                if (count[0] == 1) {
+                    ps.print("1 call to ");
+                } else {
+                    ps.print(count[0]+" calls to ");
+                }
+                ps.println(prim);
+                numprims++;
+                total += count[0];
+            }
+            if (numprims == 0) {
+                ps.println("No graphics primitives executed");
+            } else if (numprims > 1) {
+                ps.println(total+" total calls to "+
+                           numprims+" different primitives");
+            }
+        }
+    }
+
+    public synchronized static void tracePrimitive(Object prim) {
+        if ((traceflags & TRACECOUNTS) != 0) {
+            if (traceMap == null) {
+                traceMap = new HashMap<>();
+                TraceReporter.setShutdownHook();
+            }
+            int[] o = traceMap.get(prim);
+            if (o == null) {
+                o = new int[1];
+                traceMap.put(prim, o);
+            }
+            o[0]++;
+        }
+        if ((traceflags & TRACELOG) != 0) {
+            PrintStream ps = getTraceOutputFile();
+            if ((traceflags & TRACETIMESTAMP) != 0) {
+                ps.print(System.currentTimeMillis()+": ");
+            }
+            ps.println(prim);
+        }
+    }
+
+    protected void setupGeneralBinaryOp(GeneralBinaryOp gbo) {
+        int primID = gbo.getPrimTypeID();
+        String methodSignature = gbo.getSignature();
+        SurfaceType srctype = gbo.getSourceType();
+        CompositeType comptype = gbo.getCompositeType();
+        SurfaceType dsttype = gbo.getDestType();
+        Blit convertsrc, convertdst, convertres;
+        GraphicsPrimitive performop;
+
+        convertsrc = createConverter(srctype, SurfaceType.IntArgb);
+        performop = GraphicsPrimitiveMgr.locatePrim(primID,
+                                                    SurfaceType.IntArgb,
+                                                    comptype, dsttype);
+        if (performop != null) {
+            convertdst = null;
+            convertres = null;
+        } else {
+            performop = getGeneralOp(primID, comptype);
+            if (performop == null) {
+                throw new InternalError("Cannot construct general op for "+
+                                        methodSignature+" "+comptype);
+            }
+            convertdst = createConverter(dsttype, SurfaceType.IntArgb);
+            convertres = createConverter(SurfaceType.IntArgb, dsttype);
+        }
+
+        gbo.setPrimitives(convertsrc, convertdst, performop, convertres);
+    }
+
+    protected void setupGeneralUnaryOp(GeneralUnaryOp guo) {
+        int primID = guo.getPrimTypeID();
+        String methodSignature = guo.getSignature();
+        CompositeType comptype = guo.getCompositeType();
+        SurfaceType dsttype = guo.getDestType();
+
+        Blit convertdst = createConverter(dsttype, SurfaceType.IntArgb);
+        GraphicsPrimitive performop = getGeneralOp(primID, comptype);
+        Blit convertres = createConverter(SurfaceType.IntArgb, dsttype);
+        if (convertdst == null || performop == null || convertres == null) {
+            throw new InternalError("Cannot construct binary op for "+
+                                    comptype+" "+dsttype);
+        }
+
+        guo.setPrimitives(convertdst, performop, convertres);
+    }
+
+    protected static Blit createConverter(SurfaceType srctype,
+                                          SurfaceType dsttype)
+    {
+        if (srctype.equals(dsttype)) {
+            return null;
+        }
+        Blit cv = Blit.getFromCache(srctype, CompositeType.SrcNoEa, dsttype);
+        if (cv == null) {
+            throw new InternalError("Cannot construct converter for "+
+                                    srctype+"=>"+dsttype);
+        }
+        return cv;
+    }
+
+    protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData,
+                                             int srcX, int srcY, int w, int h,
+                                             SurfaceData dstData)
+    {
+        return convertFrom(ob, srcData,
+                           srcX, srcY, w, h, dstData,
+                           BufferedImage.TYPE_INT_ARGB);
+    }
+
+    protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData,
+                                             int srcX, int srcY, int w, int h,
+                                             SurfaceData dstData, int type)
+    {
+        if (dstData != null) {
+            Rectangle r = dstData.getBounds();
+            if (w > r.width || h > r.height) {
+                dstData = null;
+            }
+        }
+        if (dstData == null) {
+            BufferedImage dstBI = new BufferedImage(w, h, type);
+            dstData = BufImgSurfaceData.createData(dstBI);
+        }
+        ob.Blit(srcData, dstData, AlphaComposite.Src, null,
+                srcX, srcY, 0, 0, w, h);
+        return dstData;
+    }
+
+    protected static void convertTo(Blit ob,
+                                    SurfaceData srcImg, SurfaceData dstImg,
+                                    Region clip,
+                                    int dstX, int dstY, int w, int h)
+    {
+        if (ob != null) {
+            ob.Blit(srcImg, dstImg, AlphaComposite.Src, clip,
+                    0, 0, dstX, dstY, w, h);
+        }
+    }
+
+    protected static GraphicsPrimitive getGeneralOp(int primID,
+                                                    CompositeType comptype)
+    {
+        return GraphicsPrimitiveMgr.locatePrim(primID,
+                                               SurfaceType.IntArgb,
+                                               comptype,
+                                               SurfaceType.IntArgb);
+    }
+
+    public static String simplename(Field[] fields, Object o) {
+        for (int i = 0; i < fields.length; i++) {
+            Field f = fields[i];
+            try {
+                if (o == f.get(null)) {
+                    return f.getName();
+                }
+            } catch (Exception e) {
+            }
+        }
+        return "\""+o.toString()+"\"";
+    }
+
+    public static String simplename(SurfaceType st) {
+        return simplename(SurfaceType.class.getDeclaredFields(), st);
+    }
+
+    public static String simplename(CompositeType ct) {
+        return simplename(CompositeType.class.getDeclaredFields(), ct);
+    }
+
+    private String cachedname;
+
+    public String toString() {
+        if (cachedname == null) {
+            String sig = methodSignature;
+            int index = sig.indexOf('(');
+            if (index >= 0) {
+                sig = sig.substring(0, index);
+            }
+            cachedname = (getClass().getName()+"::"+
+                          sig+"("+
+                          simplename(sourceType)+", "+
+                          simplename(compositeType)+", "+
+                          simplename(destType)+")");
+        }
+        return cachedname;
+    }
+}