1 /*
2  * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  * @author Charlton Innovations, Inc.
28  */
29 
30 package sun.java2d.loops;
31 
32 import java.awt.image.BufferedImage;
33 import java.awt.AlphaComposite;
34 import java.awt.Rectangle;
35 import sun.awt.image.BufImgSurfaceData;
36 import sun.java2d.SurfaceData;
37 import sun.java2d.pipe.Region;
38 import java.lang.reflect.Field;
39 import java.util.StringTokenizer;
40 import java.util.Iterator;
41 import java.util.HashMap;
42 import java.util.Map;
43 import java.io.PrintStream;
44 import java.io.OutputStream;
45 import java.io.FileOutputStream;
46 import java.io.FileNotFoundException;
47 import java.security.AccessController;
48 import java.security.PrivilegedAction;
49 import sun.security.action.GetPropertyAction;
50 
51 /**
52  * defines interface for primitives which can be placed into
53  * the graphic component manager framework
54  */
55 public abstract class GraphicsPrimitive {
56 
57     protected static interface GeneralBinaryOp {
58         /**
59          * This method allows the setupGeneralBinaryOp method to set
60          * the converters into the General version of the Primitive.
61          */
setPrimitives(Blit srcconverter, Blit dstconverter, GraphicsPrimitive genericop, Blit resconverter)62         public void setPrimitives(Blit srcconverter,
63                                   Blit dstconverter,
64                                   GraphicsPrimitive genericop,
65                                   Blit resconverter);
66 
67         /**
68          * These 4 methods are implemented automatically for any
69          * GraphicsPrimitive.  They are used by setupGeneralBinaryOp
70          * to retrieve the information needed to find the right
71          * converter primitives.
72          */
getSourceType()73         public SurfaceType getSourceType();
getCompositeType()74         public CompositeType getCompositeType();
getDestType()75         public SurfaceType getDestType();
getSignature()76         public String getSignature();
getPrimTypeID()77         public int getPrimTypeID();
78     }
79 
80     protected static interface GeneralUnaryOp {
81         /**
82          * This method allows the setupGeneralUnaryOp method to set
83          * the converters into the General version of the Primitive.
84          */
setPrimitives(Blit dstconverter, GraphicsPrimitive genericop, Blit resconverter)85         public void setPrimitives(Blit dstconverter,
86                                   GraphicsPrimitive genericop,
87                                   Blit resconverter);
88 
89         /**
90          * These 3 methods are implemented automatically for any
91          * GraphicsPrimitive.  They are used by setupGeneralUnaryOp
92          * to retrieve the information needed to find the right
93          * converter primitives.
94          */
getCompositeType()95         public CompositeType getCompositeType();
getDestType()96         public SurfaceType getDestType();
getSignature()97         public String getSignature();
getPrimTypeID()98         public int getPrimTypeID();
99     }
100 
101     /**
102     *  INSTANCE DATA MEMBERS DESCRIBING CHARACTERISTICS OF THIS PRIMITIVE
103     **/
104 
105     // Making these be instance data members (instead of virtual methods
106     // overridden by subclasses) is actually cheaper, since each class
107     // is a singleton.  As instance data members with final accessors,
108     // accesses can be inlined.
109     private String methodSignature;
110     private int uniqueID;
111     private static int unusedPrimID = 1;
112 
113     private SurfaceType sourceType;
114     private CompositeType compositeType;
115     private SurfaceType destType;
116 
117     private long pNativePrim;   // Native blit loop info
118 
makePrimTypeID()119     public synchronized static final int makePrimTypeID() {
120         if (unusedPrimID > 255) {
121             throw new InternalError("primitive id overflow");
122         }
123         return unusedPrimID++;
124     }
125 
makeUniqueID(int primTypeID, SurfaceType src, CompositeType cmp, SurfaceType dst)126     public synchronized static final int makeUniqueID(int primTypeID,
127                                                       SurfaceType src,
128                                                       CompositeType cmp,
129                                                       SurfaceType dst)
130     {
131         return (primTypeID << 24) |
132             (dst.getUniqueID() << 16) |
133             (cmp.getUniqueID() << 8)  |
134             (src.getUniqueID());
135     }
136 
137     /**
138      * Create a new GraphicsPrimitive with all of the required
139      * descriptive information.
140      */
GraphicsPrimitive(String methodSignature, int primTypeID, SurfaceType sourceType, CompositeType compositeType, SurfaceType destType)141     protected GraphicsPrimitive(String methodSignature,
142                                 int primTypeID,
143                                 SurfaceType sourceType,
144                                 CompositeType compositeType,
145                                 SurfaceType destType)
146     {
147         this.methodSignature = methodSignature;
148         this.sourceType = sourceType;
149         this.compositeType = compositeType;
150         this.destType = destType;
151 
152         if(sourceType == null || compositeType == null || destType == null) {
153             this.uniqueID = primTypeID << 24;
154         } else {
155             this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID,
156                                                            sourceType,
157                                                            compositeType,
158                                                            destType);
159         }
160     }
161 
162     /**
163      * Create a new GraphicsPrimitive for native invocation
164      * with all of the required descriptive information.
165      */
GraphicsPrimitive(long pNativePrim, String methodSignature, int primTypeID, SurfaceType sourceType, CompositeType compositeType, SurfaceType destType)166     protected GraphicsPrimitive(long pNativePrim,
167                                 String methodSignature,
168                                 int primTypeID,
169                                 SurfaceType sourceType,
170                                 CompositeType compositeType,
171                                 SurfaceType destType)
172     {
173         this.pNativePrim = pNativePrim;
174         this.methodSignature = methodSignature;
175         this.sourceType = sourceType;
176         this.compositeType = compositeType;
177         this.destType = destType;
178 
179         if(sourceType == null || compositeType == null || destType == null) {
180             this.uniqueID = primTypeID << 24;
181         } else {
182             this.uniqueID = GraphicsPrimitive.makeUniqueID(primTypeID,
183                                                            sourceType,
184                                                            compositeType,
185                                                            destType);
186         }
187     }
188 
189     /**
190     *   METHODS TO DESCRIBE THE SURFACES PRIMITIVES
191     *   CAN OPERATE ON AND THE FUNCTIONALITY THEY IMPLEMENT
192     **/
193 
194     /**
195      * Gets instance ID of this graphics primitive.
196      *
197      * Instance ID is comprised of four distinct ids (ORed together)
198      * that uniquely identify each instance of a GraphicsPrimitive
199      * object. The four ids making up instance ID are:
200      * 1. primitive id - identifier shared by all primitives of the
201      * same type (eg. all Blits have the same primitive id)
202      * 2. sourcetype id - identifies source surface type
203      * 3. desttype id - identifies destination surface type
204      * 4. compositetype id - identifies composite used
205      *
206      * @return instance ID
207      */
getUniqueID()208     public final int getUniqueID() {
209         return uniqueID;
210     }
211 
212     /**
213      */
getSignature()214     public final String getSignature() {
215         return methodSignature;
216     }
217 
218     /**
219      * Gets unique id for this GraphicsPrimitive type.
220      *
221      * This id is used to identify the TYPE of primitive (Blit vs. BlitBg)
222      * as opposed to INSTANCE of primitive.
223      *
224      * @return primitive ID
225      */
getPrimTypeID()226     public final int getPrimTypeID() {
227         return uniqueID >>> 24;
228     }
229 
230     /**
231      */
getNativePrim()232     public final long getNativePrim() {
233         return pNativePrim;
234     }
235 
236     /**
237      */
getSourceType()238     public final SurfaceType getSourceType() {
239         return sourceType;
240     }
241 
242     /**
243      */
getCompositeType()244     public final CompositeType getCompositeType() {
245         return compositeType;
246     }
247 
248     /**
249      */
getDestType()250     public final SurfaceType getDestType() {
251         return destType;
252     }
253 
254     /**
255      * Return true if this primitive can be used for the given signature
256      * surfaces, and composite.
257      *
258      * @param signature The signature of the given operation.  Must be
259      *          == (not just .equals) the signature string given by the
260      *          abstract class that declares the operation.
261      * @param srctype The surface type for the source of the operation
262      * @param comptype The composite type for the operation
263      * @param dsttype The surface type for the destination of the operation
264      */
satisfies(String signature, SurfaceType srctype, CompositeType comptype, SurfaceType dsttype)265     public final boolean satisfies(String signature,
266                                    SurfaceType srctype,
267                                    CompositeType comptype,
268                                    SurfaceType dsttype)
269     {
270         if (signature != methodSignature) {
271             return false;
272         }
273         while (true) {
274             if (srctype == null) {
275                 return false;
276             }
277             if (srctype.equals(sourceType)) {
278                 break;
279             }
280             srctype = srctype.getSuperType();
281         }
282         while (true) {
283             if (comptype == null) {
284                 return false;
285             }
286             if (comptype.equals(compositeType)) {
287                 break;
288             }
289             comptype = comptype.getSuperType();
290         }
291         while (true) {
292             if (dsttype == null) {
293                 return false;
294             }
295             if (dsttype.equals(destType)) {
296                 break;
297             }
298             dsttype = dsttype.getSuperType();
299         }
300         return true;
301     }
302 
303     //
304     // A version of satisfies used for regression testing
305     //
satisfiesSameAs(GraphicsPrimitive other)306     final boolean satisfiesSameAs(GraphicsPrimitive other) {
307         return (methodSignature == other.methodSignature &&
308                 sourceType.equals(other.sourceType) &&
309                 compositeType.equals(other.compositeType) &&
310                 destType.equals(other.destType));
311     }
312 
makePrimitive(SurfaceType srctype, CompositeType comptype, SurfaceType dsttype)313     public abstract GraphicsPrimitive makePrimitive(SurfaceType srctype,
314                                                     CompositeType comptype,
315                                                     SurfaceType dsttype);
316 
traceWrap()317     public abstract GraphicsPrimitive traceWrap();
318 
319     static HashMap traceMap;
320 
321     public static int traceflags;
322     public static String tracefile;
323     public static PrintStream traceout;
324 
325     public static final int TRACELOG = 1;
326     public static final int TRACETIMESTAMP = 2;
327     public static final int TRACECOUNTS = 4;
328 
329     static {
330         GetPropertyAction gpa = new GetPropertyAction("sun.java2d.trace");
331         String trace = AccessController.doPrivileged(gpa);
332         if (trace != null) {
333             boolean verbose = false;
334             int traceflags = 0;
335             StringTokenizer st = new StringTokenizer(trace, ",");
336             while (st.hasMoreTokens()) {
337                 String tok = st.nextToken();
338                 if (tok.equalsIgnoreCase("count")) {
339                     traceflags |= GraphicsPrimitive.TRACECOUNTS;
340                 } else if (tok.equalsIgnoreCase("log")) {
341                     traceflags |= GraphicsPrimitive.TRACELOG;
342                 } else if (tok.equalsIgnoreCase("timestamp")) {
343                     traceflags |= GraphicsPrimitive.TRACETIMESTAMP;
344                 } else if (tok.equalsIgnoreCase("verbose")) {
345                     verbose = true;
346                 } else if (tok.regionMatches(true, 0, "out:", 0, 4)) {
347                     tracefile = tok.substring(4);
348                 } else {
349                     if (!tok.equalsIgnoreCase("help")) {
350                         System.err.println("unrecognized token: "+tok);
351                     }
352                     System.err.println("usage: -Dsun.java2d.trace="+
353                                        "[log[,timestamp]],[count],"+
354                                        "[out:<filename>],[help],[verbose]");
355                 }
356             }
357             if (verbose) {
358                 System.err.print("GraphicsPrimitive logging ");
359                 if ((traceflags & GraphicsPrimitive.TRACELOG) != 0) {
360                     System.err.println("enabled");
361                     System.err.print("GraphicsPrimitive timetamps ");
362                     if ((traceflags & GraphicsPrimitive.TRACETIMESTAMP) != 0) {
363                         System.err.println("enabled");
364                     } else {
365                         System.err.println("disabled");
366                     }
367                 } else {
368                     System.err.println("[and timestamps] disabled");
369                 }
370                 System.err.print("GraphicsPrimitive invocation counts ");
371                 if ((traceflags & GraphicsPrimitive.TRACECOUNTS) != 0) {
372                     System.err.println("enabled");
373                 } else {
374                     System.err.println("disabled");
375                 }
376                 System.err.print("GraphicsPrimitive trace output to ");
377                 if (tracefile == null) {
378                     System.err.println("System.err");
379                 } else {
380                     System.err.println("file '"+tracefile+"'");
381                 }
382             }
383             GraphicsPrimitive.traceflags = traceflags;
384         }
385     }
386 
tracingEnabled()387     public static boolean tracingEnabled() {
388         return (traceflags != 0);
389     }
390 
getTraceOutputFile()391     private static PrintStream getTraceOutputFile() {
392         if (traceout == null) {
393             if (tracefile != null) {
394                 FileOutputStream o = AccessController.doPrivileged(
395                     new PrivilegedAction<FileOutputStream>() {
396                         public FileOutputStream run() {
397                             try {
398                                 return new FileOutputStream(tracefile);
399                             } catch (FileNotFoundException e) {
400                                 return null;
401                             }
402                         }
403                     });
404                 if (o != null) {
405                     traceout = new PrintStream(o);
406                 } else {
407                     traceout = System.err;
408                 }
409             } else {
410                 traceout = System.err;
411             }
412         }
413         return traceout;
414     }
415 
416     public static class TraceReporter extends Thread {
setShutdownHook()417         public static void setShutdownHook() {
418             AccessController.doPrivileged(new PrivilegedAction<Void>() {
419                 public Void run() {
420                     TraceReporter t = new TraceReporter();
421                     t.setContextClassLoader(null);
422                     Runtime.getRuntime().addShutdownHook(t);
423                     return null;
424                 }
425             });
426         }
427 
run()428         public void run() {
429             PrintStream ps = getTraceOutputFile();
430             Iterator iterator = traceMap.entrySet().iterator();
431             long total = 0;
432             int numprims = 0;
433             while (iterator.hasNext()) {
434                 Map.Entry me = (Map.Entry) iterator.next();
435                 Object prim = me.getKey();
436                 int[] count = (int[]) me.getValue();
437                 if (count[0] == 1) {
438                     ps.print("1 call to ");
439                 } else {
440                     ps.print(count[0]+" calls to ");
441                 }
442                 ps.println(prim);
443                 numprims++;
444                 total += count[0];
445             }
446             if (numprims == 0) {
447                 ps.println("No graphics primitives executed");
448             } else if (numprims > 1) {
449                 ps.println(total+" total calls to "+
450                            numprims+" different primitives");
451             }
452         }
453     }
454 
tracePrimitive(Object prim)455     public synchronized static void tracePrimitive(Object prim) {
456         if ((traceflags & TRACECOUNTS) != 0) {
457             if (traceMap == null) {
458                 traceMap = new HashMap();
459                 TraceReporter.setShutdownHook();
460             }
461             Object o = traceMap.get(prim);
462             if (o == null) {
463                 o = new int[1];
464                 traceMap.put(prim, o);
465             }
466             ((int[]) o)[0]++;
467         }
468         if ((traceflags & TRACELOG) != 0) {
469             PrintStream ps = getTraceOutputFile();
470             if ((traceflags & TRACETIMESTAMP) != 0) {
471                 ps.print(System.currentTimeMillis()+": ");
472             }
473             ps.println(prim);
474         }
475     }
476 
setupGeneralBinaryOp(GeneralBinaryOp gbo)477     protected void setupGeneralBinaryOp(GeneralBinaryOp gbo) {
478         int primID = gbo.getPrimTypeID();
479         String methodSignature = gbo.getSignature();
480         SurfaceType srctype = gbo.getSourceType();
481         CompositeType comptype = gbo.getCompositeType();
482         SurfaceType dsttype = gbo.getDestType();
483         Blit convertsrc, convertdst, convertres;
484         GraphicsPrimitive performop;
485 
486         convertsrc = createConverter(srctype, SurfaceType.IntArgb);
487         performop = GraphicsPrimitiveMgr.locatePrim(primID,
488                                                     SurfaceType.IntArgb,
489                                                     comptype, dsttype);
490         if (performop != null) {
491             convertdst = null;
492             convertres = null;
493         } else {
494             performop = getGeneralOp(primID, comptype);
495             if (performop == null) {
496                 throw new InternalError("Cannot construct general op for "+
497                                         methodSignature+" "+comptype);
498             }
499             convertdst = createConverter(dsttype, SurfaceType.IntArgb);
500             convertres = createConverter(SurfaceType.IntArgb, dsttype);
501         }
502 
503         gbo.setPrimitives(convertsrc, convertdst, performop, convertres);
504     }
505 
setupGeneralUnaryOp(GeneralUnaryOp guo)506     protected void setupGeneralUnaryOp(GeneralUnaryOp guo) {
507         int primID = guo.getPrimTypeID();
508         String methodSignature = guo.getSignature();
509         CompositeType comptype = guo.getCompositeType();
510         SurfaceType dsttype = guo.getDestType();
511 
512         Blit convertdst = createConverter(dsttype, SurfaceType.IntArgb);
513         GraphicsPrimitive performop = getGeneralOp(primID, comptype);
514         Blit convertres = createConverter(SurfaceType.IntArgb, dsttype);
515         if (convertdst == null || performop == null || convertres == null) {
516             throw new InternalError("Cannot construct binary op for "+
517                                     comptype+" "+dsttype);
518         }
519 
520         guo.setPrimitives(convertdst, performop, convertres);
521     }
522 
createConverter(SurfaceType srctype, SurfaceType dsttype)523     protected static Blit createConverter(SurfaceType srctype,
524                                           SurfaceType dsttype)
525     {
526         if (srctype.equals(dsttype)) {
527             return null;
528         }
529         Blit cv = Blit.getFromCache(srctype, CompositeType.SrcNoEa, dsttype);
530         if (cv == null) {
531             throw new InternalError("Cannot construct converter for "+
532                                     srctype+"=>"+dsttype);
533         }
534         return cv;
535     }
536 
convertFrom(Blit ob, SurfaceData srcData, int srcX, int srcY, int w, int h, SurfaceData dstData)537     protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData,
538                                              int srcX, int srcY, int w, int h,
539                                              SurfaceData dstData)
540     {
541         return convertFrom(ob, srcData,
542                            srcX, srcY, w, h, dstData,
543                            BufferedImage.TYPE_INT_ARGB);
544     }
545 
convertFrom(Blit ob, SurfaceData srcData, int srcX, int srcY, int w, int h, SurfaceData dstData, int type)546     protected static SurfaceData convertFrom(Blit ob, SurfaceData srcData,
547                                              int srcX, int srcY, int w, int h,
548                                              SurfaceData dstData, int type)
549     {
550         if (dstData != null) {
551             Rectangle r = dstData.getBounds();
552             if (w > r.width || h > r.height) {
553                 dstData = null;
554             }
555         }
556         if (dstData == null) {
557             BufferedImage dstBI = new BufferedImage(w, h, type);
558             dstData = BufImgSurfaceData.createData(dstBI);
559         }
560         ob.Blit(srcData, dstData, AlphaComposite.Src, null,
561                 srcX, srcY, 0, 0, w, h);
562         return dstData;
563     }
564 
convertTo(Blit ob, SurfaceData srcImg, SurfaceData dstImg, Region clip, int dstX, int dstY, int w, int h)565     protected static void convertTo(Blit ob,
566                                     SurfaceData srcImg, SurfaceData dstImg,
567                                     Region clip,
568                                     int dstX, int dstY, int w, int h)
569     {
570         if (ob != null) {
571             ob.Blit(srcImg, dstImg, AlphaComposite.Src, clip,
572                     0, 0, dstX, dstY, w, h);
573         }
574     }
575 
getGeneralOp(int primID, CompositeType comptype)576     protected static GraphicsPrimitive getGeneralOp(int primID,
577                                                     CompositeType comptype)
578     {
579         return GraphicsPrimitiveMgr.locatePrim(primID,
580                                                SurfaceType.IntArgb,
581                                                comptype,
582                                                SurfaceType.IntArgb);
583     }
584 
simplename(Field[] fields, Object o)585     public static String simplename(Field[] fields, Object o) {
586         for (int i = 0; i < fields.length; i++) {
587             Field f = fields[i];
588             try {
589                 if (o == f.get(null)) {
590                     return f.getName();
591                 }
592             } catch (Exception e) {
593             }
594         }
595         return "\""+o.toString()+"\"";
596     }
597 
simplename(SurfaceType st)598     public static String simplename(SurfaceType st) {
599         return simplename(SurfaceType.class.getDeclaredFields(), st);
600     }
601 
simplename(CompositeType ct)602     public static String simplename(CompositeType ct) {
603         return simplename(CompositeType.class.getDeclaredFields(), ct);
604     }
605 
606     private String cachedname;
607 
toString()608     public String toString() {
609         if (cachedname == null) {
610             String sig = methodSignature;
611             int index = sig.indexOf('(');
612             if (index >= 0) {
613                 sig = sig.substring(0, index);
614             }
615             cachedname = (getClass().getName()+"::"+
616                           sig+"("+
617                           simplename(sourceType)+", "+
618                           simplename(compositeType)+", "+
619                           simplename(destType)+")");
620         }
621         return cachedname;
622     }
623 }
624