1/*
2 * Copyright (c) 1997, 2006, 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
30package sun.java2d.loops;
31
32import java.util.Comparator;
33import java.util.Arrays;
34import sun.java2d.SunGraphics2D;
35
36/**
37 *   GraphicsComponentMgr provides services to
38 *   1. register primitives for later use
39 *   2. locate an instance of a primitve based on characteristics
40 */
41public final class GraphicsPrimitiveMgr {
42
43    private static final boolean debugTrace = false;
44    private static GraphicsPrimitive primitives[];
45    private static GraphicsPrimitive generalPrimitives[];
46    private static boolean needssort = true;
47
48    private static native void initIDs(Class<?> GP, Class<?> ST, Class<?> CT,
49                                       Class<?> SG2D, Class<?> Color, Class<?> AT,
50                                       Class<?> XORComp, Class<?> AlphaComp,
51                                       Class<?> Path2D, Class<?> Path2DFloat,
52                                       Class<?> SHints);
53    private static native void registerNativeLoops();
54
55    static {
56        initIDs(GraphicsPrimitive.class,
57                SurfaceType.class,
58                CompositeType.class,
59                SunGraphics2D.class,
60                java.awt.Color.class,
61                java.awt.geom.AffineTransform.class,
62                XORComposite.class,
63                java.awt.AlphaComposite.class,
64                java.awt.geom.Path2D.class,
65                java.awt.geom.Path2D.Float.class,
66                sun.awt.SunHints.class);
67        CustomComponent.register();
68        GeneralRenderer.register();
69        registerNativeLoops();
70    }
71
72    private static class PrimitiveSpec {
73        public int uniqueID;
74    }
75
76    private static Comparator<GraphicsPrimitive> primSorter =
77            new Comparator<GraphicsPrimitive>() {
78        public int compare(GraphicsPrimitive o1, GraphicsPrimitive o2) {
79            int id1 = o1.getUniqueID();
80            int id2 = o2.getUniqueID();
81
82            return (id1 == id2 ? 0 : (id1 < id2 ? -1 : 1));
83        }
84    };
85
86    private static Comparator<Object> primFinder = new Comparator<Object>() {
87        public int compare(Object o1, Object o2) {
88            int id1 = ((GraphicsPrimitive) o1).getUniqueID();
89            int id2 = ((PrimitiveSpec) o2).uniqueID;
90
91            return (id1 == id2 ? 0 : (id1 < id2 ? -1 : 1));
92        }
93    };
94
95    /**
96     * Ensure that noone can instantiate this class.
97     */
98    private GraphicsPrimitiveMgr() {
99    }
100
101    public static synchronized void register(GraphicsPrimitive[] newPrimitives)
102    {
103        GraphicsPrimitive[] devCollection = primitives;
104        int oldSize = 0;
105        int newSize = newPrimitives.length;
106        if (debugTrace) {
107            writeLog("Registering " + newSize + " primitives");
108            for (int i = 0; i < newSize; i++) {
109                writeLog(newPrimitives[i].toString());
110            }
111        }
112        if (devCollection != null) {
113            oldSize = devCollection.length;
114        }
115        GraphicsPrimitive[] temp = new GraphicsPrimitive[oldSize + newSize];
116        if (devCollection != null) {
117            System.arraycopy(devCollection, 0, temp, 0, oldSize);
118        }
119        System.arraycopy(newPrimitives, 0, temp, oldSize, newSize);
120        needssort = true;
121        primitives = temp;
122    }
123
124    public static synchronized void registerGeneral(GraphicsPrimitive gen) {
125        if (generalPrimitives == null) {
126            generalPrimitives = new GraphicsPrimitive[] {gen};
127            return;
128        }
129        int len = generalPrimitives.length;
130        GraphicsPrimitive[] newGen = new GraphicsPrimitive[len + 1];
131        System.arraycopy(generalPrimitives, 0, newGen, 0, len);
132        newGen[len] = gen;
133        generalPrimitives = newGen;
134    }
135
136    public static synchronized GraphicsPrimitive locate(int primTypeID,
137                                                        SurfaceType dsttype)
138    {
139        return locate(primTypeID,
140                      SurfaceType.OpaqueColor,
141                      CompositeType.Src,
142                      dsttype);
143    }
144
145    public static synchronized GraphicsPrimitive locate(int primTypeID,
146                                                        SurfaceType srctype,
147                                                        CompositeType comptype,
148                                                        SurfaceType dsttype)
149    {
150        /*
151          System.out.println("Looking for:");
152          System.out.println("    method: "+signature);
153          System.out.println("    from:   "+srctype);
154          System.out.println("    by:     "+comptype);
155          System.out.println("    to:     "+dsttype);
156        */
157        GraphicsPrimitive prim = locatePrim(primTypeID,
158                                            srctype, comptype, dsttype);
159
160        if (prim == null) {
161            //System.out.println("Trying general loop");
162            prim = locateGeneral(primTypeID);
163            if (prim != null) {
164                prim = prim.makePrimitive(srctype, comptype, dsttype);
165                if (prim != null && GraphicsPrimitive.traceflags != 0) {
166                    prim = prim.traceWrap();
167                }
168            }
169        }
170        return prim;
171    }
172
173    public static synchronized GraphicsPrimitive
174        locatePrim(int primTypeID,
175                   SurfaceType srctype,
176                   CompositeType comptype,
177                   SurfaceType dsttype)
178    {
179        /*
180          System.out.println("Looking for:");
181          System.out.println("    method: "+signature);
182          System.out.println("    from:   "+srctype);
183          System.out.println("    by:     "+comptype);
184          System.out.println("    to:     "+dsttype);
185        */
186        SurfaceType src, dst;
187        CompositeType cmp;
188        GraphicsPrimitive prim;
189        PrimitiveSpec spec = new PrimitiveSpec();
190
191        for (dst = dsttype; dst != null; dst = dst.getSuperType()) {
192            for (src = srctype; src != null; src = src.getSuperType()) {
193                for (cmp = comptype; cmp != null; cmp = cmp.getSuperType()) {
194                    /*
195                      System.out.println("Trying:");
196                      System.out.println("    method: "+spec.methodSignature);
197                      System.out.println("    from:   "+spec.sourceType);
198                      System.out.println("    by:     "+spec.compType);
199                      System.out.println("    to:     "+spec.destType);
200                    */
201
202                    spec.uniqueID =
203                        GraphicsPrimitive.makeUniqueID(primTypeID, src, cmp, dst);
204                    prim = locate(spec);
205                    if (prim != null) {
206                        //System.out.println("<GPMgr> Found: " + prim + " in " + i + " steps");
207                        return prim;
208                    }
209                }
210            }
211        }
212        return null;
213    }
214
215    private static GraphicsPrimitive locateGeneral(int primTypeID) {
216        if (generalPrimitives == null) {
217            return null;
218        }
219        for (int i = 0; i < generalPrimitives.length; i++) {
220            GraphicsPrimitive prim = generalPrimitives[i];
221            if (prim.getPrimTypeID() == primTypeID) {
222                return prim;
223            }
224        }
225        return null;
226        //throw new InternalError("No general handler registered for"+signature);
227    }
228
229    private static GraphicsPrimitive locate(PrimitiveSpec spec) {
230        if (needssort) {
231            if (GraphicsPrimitive.traceflags != 0) {
232                for (int i = 0; i < primitives.length; i++) {
233                    primitives[i] = primitives[i].traceWrap();
234                }
235            }
236            Arrays.sort(primitives, primSorter);
237            needssort = false;
238        }
239        GraphicsPrimitive[] devCollection = primitives;
240        if (devCollection == null) {
241            return null;
242        }
243        int index = Arrays.binarySearch(devCollection, spec, primFinder);
244        if (index >= 0) {
245            GraphicsPrimitive prim = devCollection[index];
246            if (prim instanceof GraphicsPrimitiveProxy) {
247                prim = ((GraphicsPrimitiveProxy) prim).instantiate();
248                devCollection[index] = prim;
249                if (debugTrace) {
250                    writeLog("Instantiated graphics primitive " + prim);
251                }
252            }
253            if (debugTrace) {
254                writeLog("Lookup found[" + index + "]["+ prim + "]");
255            }
256            return prim;
257        }
258        if (debugTrace) {
259            writeLog("Lookup found nothing for:");
260            writeLog(" " + spec.uniqueID);
261        }
262        return null;
263    }
264
265    private static void writeLog(String str) {
266        if (debugTrace) {
267            System.err.println(str);
268        }
269    }
270
271    /**
272     * Test that all of the GraphicsPrimitiveProxy objects actually
273     * resolve to something.  Throws a RuntimeException if anything
274     * is wrong, an has no effect if all is well.
275     */
276    // This is only really meant to be called from GraphicsPrimitiveProxyTest
277    // in the regression tests directory, but it has to be here because
278    // it needs access to a private data structure.  It is not very
279    // big, though.
280    public static void testPrimitiveInstantiation() {
281        testPrimitiveInstantiation(false);
282    }
283
284    public static void testPrimitiveInstantiation(boolean verbose) {
285        int resolved = 0;
286        int unresolved = 0;
287        GraphicsPrimitive[] prims = primitives;
288        for (int j = 0; j < prims.length; j++) {
289            GraphicsPrimitive p = prims[j];
290            if (p instanceof GraphicsPrimitiveProxy) {
291                GraphicsPrimitive r = ((GraphicsPrimitiveProxy) p).instantiate();
292                if (!r.getSignature().equals(p.getSignature()) ||
293                    r.getUniqueID() != p.getUniqueID()) {
294                    System.out.println("r.getSignature == "+r.getSignature());
295                    System.out.println("r.getUniqueID == " + r.getUniqueID());
296                    System.out.println("p.getSignature == "+p.getSignature());
297                    System.out.println("p.getUniqueID == " + p.getUniqueID());
298                    throw new RuntimeException("Primitive " + p
299                                               + " returns wrong signature for "
300                                               + r.getClass());
301                }
302                // instantiate checks that p.satisfiesSameAs(r)
303                unresolved++;
304                p = r;
305                if (verbose) {
306                    System.out.println(p);
307                }
308            } else {
309                if (verbose) {
310                    System.out.println(p + " (not proxied).");
311                }
312                resolved++;
313            }
314        }
315        System.out.println(resolved+
316                           " graphics primitives were not proxied.");
317        System.out.println(unresolved+
318                           " proxied graphics primitives resolved correctly.");
319        System.out.println(resolved+unresolved+
320                           " total graphics primitives");
321    }
322
323    public static void main(String argv[]) {
324        // REMIND: Should trigger loading of platform primitives somehow...
325        if (needssort) {
326            Arrays.sort(primitives, primSorter);
327            needssort = false;
328        }
329        testPrimitiveInstantiation(argv.length > 0);
330    }
331}
332