| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.java2d.marlin;  | 
 | 
 | 
 | 
import java.awt.geom.Path2D;  | 
 | 
import java.lang.ref.WeakReference;  | 
 | 
import java.util.concurrent.atomic.AtomicInteger;  | 
 | 
import sun.java2d.ReentrantContext;  | 
 | 
import sun.java2d.ReentrantContextProvider;  | 
 | 
import static sun.java2d.marlin.ArrayCache.*;  | 
 | 
import sun.java2d.marlin.MarlinRenderingEngine.NormalizingPathIterator;  | 
 | 
import static sun.java2d.marlin.MarlinUtils.logInfo;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
final class RendererContext extends ReentrantContext implements MarlinConst { | 
 | 
 | 
 | 
      | 
 | 
    private static final AtomicInteger contextCount = new AtomicInteger(1);  | 
 | 
      | 
 | 
    static final RendererStats stats = (doStats || doMonitors)  | 
 | 
                                       ? RendererStats.getInstance(): null;  | 
 | 
 | 
 | 
    private static final boolean USE_CACHE_HARD_REF = doStats  | 
 | 
        || (MarlinRenderingEngine.REF_TYPE == ReentrantContextProvider.REF_WEAK);  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static RendererContext createContext() { | 
 | 
        final RendererContext newCtx = new RendererContext("ctx" | 
 | 
                    + Integer.toString(contextCount.getAndIncrement()));  | 
 | 
 | 
 | 
        if (RendererContext.stats != null) { | 
 | 
            RendererContext.stats.allContexts.add(newCtx);  | 
 | 
        }  | 
 | 
        return newCtx;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    final String name;  | 
 | 
      | 
 | 
    boolean dirty = false;  | 
 | 
      | 
 | 
    WeakReference<ArrayCachesHolder> refArrayCaches = null;  | 
 | 
      | 
 | 
    ArrayCachesHolder hardRefArrayCaches = null;  | 
 | 
      | 
 | 
    final float[] float6 = new float[6];  | 
 | 
      | 
 | 
    final Curve curve = new Curve();  | 
 | 
      | 
 | 
    final NormalizingPathIterator nPCPathIterator;  | 
 | 
      | 
 | 
    final NormalizingPathIterator nPQPathIterator;  | 
 | 
      | 
 | 
    final TransformingPathConsumer2D transformerPC2D;  | 
 | 
      | 
 | 
    Path2D.Float p2d = null;  | 
 | 
    final Renderer renderer;  | 
 | 
    final Stroker stroker;  | 
 | 
      | 
 | 
    final CollinearSimplifier simplifier = new CollinearSimplifier();  | 
 | 
    final Dasher dasher;  | 
 | 
    final MarlinTileGenerator ptg;  | 
 | 
    final MarlinCache cache;  | 
 | 
      | 
 | 
    int stroking = 0;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    RendererContext(final String name) { | 
 | 
        if (logCreateContext) { | 
 | 
            MarlinUtils.logInfo("new RendererContext = " + name); | 
 | 
        }  | 
 | 
 | 
 | 
        this.name = name;  | 
 | 
 | 
 | 
          | 
 | 
        nPCPathIterator = new NormalizingPathIterator.NearestPixelCenter(float6);  | 
 | 
        nPQPathIterator  = new NormalizingPathIterator.NearestPixelQuarter(float6);  | 
 | 
 | 
 | 
          | 
 | 
        transformerPC2D = new TransformingPathConsumer2D();  | 
 | 
 | 
 | 
          | 
 | 
        cache = new MarlinCache(this);  | 
 | 
        renderer = new Renderer(this);   | 
 | 
        ptg = new MarlinTileGenerator(renderer);  | 
 | 
 | 
 | 
        stroker = new Stroker(this);  | 
 | 
        dasher = new Dasher(this);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    void dispose() { | 
 | 
        stroking = 0;  | 
 | 
          | 
 | 
        if (!USE_CACHE_HARD_REF) { | 
 | 
            hardRefArrayCaches = null;  | 
 | 
        }  | 
 | 
          | 
 | 
        if (dirty) { | 
 | 
            // may happen if an exception if thrown in the pipeline processing:  | 
 | 
            // force cleanup of all possible pipelined blocks (except Renderer):  | 
 | 
 | 
 | 
              | 
 | 
            this.nPCPathIterator.dispose();  | 
 | 
            this.nPQPathIterator.dispose();  | 
 | 
              | 
 | 
            this.dasher.dispose();  | 
 | 
              | 
 | 
            this.stroker.dispose();  | 
 | 
 | 
 | 
              | 
 | 
            dirty = false;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    ArrayCachesHolder getArrayCachesHolder() { | 
 | 
          | 
 | 
        ArrayCachesHolder holder = hardRefArrayCaches;  | 
 | 
        if (holder == null) { | 
 | 
              | 
 | 
            holder = (refArrayCaches != null)  | 
 | 
                     ? refArrayCaches.get()  | 
 | 
                     : null;  | 
 | 
              | 
 | 
            if (holder == null) { | 
 | 
                if (logCreateContext) { | 
 | 
                    MarlinUtils.logInfo("new ArrayCachesHolder for " | 
 | 
                                        + "RendererContext = " + name);  | 
 | 
                }  | 
 | 
 | 
 | 
                holder = new ArrayCachesHolder();  | 
 | 
 | 
 | 
                if (USE_CACHE_HARD_REF) { | 
 | 
                      | 
 | 
                    hardRefArrayCaches = holder;  | 
 | 
                }  | 
 | 
 | 
 | 
                  | 
 | 
                refArrayCaches = new WeakReference<ArrayCachesHolder>(holder);  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return holder;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    ByteArrayCache getDirtyByteArrayCache(final int length) { | 
 | 
        final int bucket = ArrayCache.getBucketDirtyBytes(length);  | 
 | 
        return getArrayCachesHolder().dirtyByteArrayCaches[bucket];  | 
 | 
    }  | 
 | 
 | 
 | 
    byte[] getDirtyByteArray(final int length) { | 
 | 
        if (length <= MAX_DIRTY_BYTE_ARRAY_SIZE) { | 
 | 
            return getDirtyByteArrayCache(length).getArray();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (doStats) { | 
 | 
            incOversize();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (doLogOverSize) { | 
 | 
            logInfo("getDirtyByteArray[oversize]: length=\t" + length); | 
 | 
        }  | 
 | 
 | 
 | 
        return new byte[length];  | 
 | 
    }  | 
 | 
 | 
 | 
    void putDirtyByteArray(final byte[] array) { | 
 | 
        final int length = array.length;  | 
 | 
        // odd sized array are non-cached arrays (initial arrays)  | 
 | 
          | 
 | 
        if (((length & 0x1) == 0) && (length <= MAX_DIRTY_BYTE_ARRAY_SIZE)) { | 
 | 
            getDirtyByteArrayCache(length).putDirtyArray(array, length);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    byte[] widenDirtyByteArray(final byte[] in,  | 
 | 
                               final int usedSize, final int needSize)  | 
 | 
    { | 
 | 
        final int length = in.length;  | 
 | 
        if (doChecks && length >= needSize) { | 
 | 
            return in;  | 
 | 
        }  | 
 | 
        if (doStats) { | 
 | 
            incResizeDirtyByte();  | 
 | 
        }  | 
 | 
 | 
 | 
        // maybe change bucket:  | 
 | 
          | 
 | 
        final byte[] res = getDirtyByteArray(getNewSize(usedSize, needSize));  | 
 | 
 | 
 | 
        System.arraycopy(in, 0, res, 0, usedSize);   | 
 | 
 | 
 | 
        // maybe return current array:  | 
 | 
          | 
 | 
        putDirtyByteArray(in);  | 
 | 
 | 
 | 
        if (doLogWidenArray) { | 
 | 
            logInfo("widenDirtyByteArray[" + res.length + "]: usedSize=\t" | 
 | 
                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"  | 
 | 
                    + needSize);  | 
 | 
        }  | 
 | 
        return res;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    IntArrayCache getIntArrayCache(final int length) { | 
 | 
        final int bucket = ArrayCache.getBucket(length);  | 
 | 
        return getArrayCachesHolder().intArrayCaches[bucket];  | 
 | 
    }  | 
 | 
 | 
 | 
    int[] getIntArray(final int length) { | 
 | 
        if (length <= MAX_ARRAY_SIZE) { | 
 | 
            return getIntArrayCache(length).getArray();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (doStats) { | 
 | 
            incOversize();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (doLogOverSize) { | 
 | 
            logInfo("getIntArray[oversize]: length=\t" + length); | 
 | 
        }  | 
 | 
 | 
 | 
        return new int[length];  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    int[] widenIntArray(final int[] in, final int usedSize,  | 
 | 
                        final int needSize, final int clearTo)  | 
 | 
    { | 
 | 
        final int length = in.length;  | 
 | 
        if (doChecks && length >= needSize) { | 
 | 
            return in;  | 
 | 
        }  | 
 | 
        if (doStats) { | 
 | 
            incResizeInt();  | 
 | 
        }  | 
 | 
 | 
 | 
        // maybe change bucket:  | 
 | 
          | 
 | 
        final int[] res = getIntArray(getNewSize(usedSize, needSize));  | 
 | 
 | 
 | 
        System.arraycopy(in, 0, res, 0, usedSize);   | 
 | 
 | 
 | 
        // maybe return current array:  | 
 | 
        putIntArray(in, 0, clearTo);   | 
 | 
 | 
 | 
        if (doLogWidenArray) { | 
 | 
            logInfo("widenIntArray[" + res.length + "]: usedSize=\t" | 
 | 
                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"  | 
 | 
                    + needSize);  | 
 | 
        }  | 
 | 
        return res;  | 
 | 
    }  | 
 | 
 | 
 | 
    void putIntArray(final int[] array, final int fromIndex,  | 
 | 
                     final int toIndex)  | 
 | 
    { | 
 | 
        final int length = array.length;  | 
 | 
        // odd sized array are non-cached arrays (initial arrays)  | 
 | 
          | 
 | 
        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) { | 
 | 
            getIntArrayCache(length).putArray(array, length, fromIndex, toIndex);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    IntArrayCache getDirtyIntArrayCache(final int length) { | 
 | 
        final int bucket = ArrayCache.getBucket(length);  | 
 | 
        return getArrayCachesHolder().dirtyIntArrayCaches[bucket];  | 
 | 
    }  | 
 | 
 | 
 | 
    int[] getDirtyIntArray(final int length) { | 
 | 
        if (length <= MAX_ARRAY_SIZE) { | 
 | 
            return getDirtyIntArrayCache(length).getArray();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (doStats) { | 
 | 
            incOversize();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (doLogOverSize) { | 
 | 
            logInfo("getDirtyIntArray[oversize]: length=\t" + length); | 
 | 
        }  | 
 | 
 | 
 | 
        return new int[length];  | 
 | 
    }  | 
 | 
 | 
 | 
    int[] widenDirtyIntArray(final int[] in,  | 
 | 
                             final int usedSize, final int needSize)  | 
 | 
    { | 
 | 
        final int length = in.length;  | 
 | 
        if (doChecks && length >= needSize) { | 
 | 
            return in;  | 
 | 
        }  | 
 | 
        if (doStats) { | 
 | 
            incResizeDirtyInt();  | 
 | 
        }  | 
 | 
 | 
 | 
        // maybe change bucket:  | 
 | 
          | 
 | 
        final int[] res = getDirtyIntArray(getNewSize(usedSize, needSize));  | 
 | 
 | 
 | 
        System.arraycopy(in, 0, res, 0, usedSize);   | 
 | 
 | 
 | 
        // maybe return current array:  | 
 | 
          | 
 | 
        putDirtyIntArray(in);  | 
 | 
 | 
 | 
        if (doLogWidenArray) { | 
 | 
            logInfo("widenDirtyIntArray[" + res.length + "]: usedSize=\t" | 
 | 
                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"  | 
 | 
                    + needSize);  | 
 | 
        }  | 
 | 
        return res;  | 
 | 
    }  | 
 | 
 | 
 | 
    void putDirtyIntArray(final int[] array) { | 
 | 
        final int length = array.length;  | 
 | 
        // odd sized array are non-cached arrays (initial arrays)  | 
 | 
          | 
 | 
        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) { | 
 | 
            getDirtyIntArrayCache(length).putDirtyArray(array, length);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    FloatArrayCache getDirtyFloatArrayCache(final int length) { | 
 | 
        final int bucket = ArrayCache.getBucket(length);  | 
 | 
        return getArrayCachesHolder().dirtyFloatArrayCaches[bucket];  | 
 | 
    }  | 
 | 
 | 
 | 
    float[] getDirtyFloatArray(final int length) { | 
 | 
        if (length <= MAX_ARRAY_SIZE) { | 
 | 
            return getDirtyFloatArrayCache(length).getArray();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (doStats) { | 
 | 
            incOversize();  | 
 | 
        }  | 
 | 
 | 
 | 
        if (doLogOverSize) { | 
 | 
            logInfo("getDirtyFloatArray[oversize]: length=\t" + length); | 
 | 
        }  | 
 | 
 | 
 | 
        return new float[length];  | 
 | 
    }  | 
 | 
 | 
 | 
    float[] widenDirtyFloatArray(final float[] in,  | 
 | 
                                 final int usedSize, final int needSize)  | 
 | 
    { | 
 | 
        final int length = in.length;  | 
 | 
        if (doChecks && length >= needSize) { | 
 | 
            return in;  | 
 | 
        }  | 
 | 
        if (doStats) { | 
 | 
            incResizeDirtyFloat();  | 
 | 
        }  | 
 | 
 | 
 | 
        // maybe change bucket:  | 
 | 
          | 
 | 
        final float[] res = getDirtyFloatArray(getNewSize(usedSize, needSize));  | 
 | 
 | 
 | 
        System.arraycopy(in, 0, res, 0, usedSize);   | 
 | 
 | 
 | 
        // maybe return current array:  | 
 | 
          | 
 | 
        putDirtyFloatArray(in);  | 
 | 
 | 
 | 
        if (doLogWidenArray) { | 
 | 
            logInfo("widenDirtyFloatArray[" + res.length + "]: usedSize=\t" | 
 | 
                    + usedSize + "\tlength=\t" + length + "\tneeded length=\t"  | 
 | 
                    + needSize);  | 
 | 
        }  | 
 | 
        return res;  | 
 | 
    }  | 
 | 
 | 
 | 
    void putDirtyFloatArray(final float[] array) { | 
 | 
        final int length = array.length;  | 
 | 
        // odd sized array are non-cached arrays (initial arrays)  | 
 | 
          | 
 | 
        if (((length & 0x1) == 0) && (length <= MAX_ARRAY_SIZE)) { | 
 | 
            getDirtyFloatArrayCache(length).putDirtyArray(array, length);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    static final class ArrayCachesHolder { | 
 | 
          | 
 | 
        final IntArrayCache[] intArrayCaches;  | 
 | 
          | 
 | 
        final IntArrayCache[] dirtyIntArrayCaches;  | 
 | 
        final FloatArrayCache[] dirtyFloatArrayCaches;  | 
 | 
        final ByteArrayCache[] dirtyByteArrayCaches;  | 
 | 
 | 
 | 
        ArrayCachesHolder() { | 
 | 
            intArrayCaches = new IntArrayCache[BUCKETS];  | 
 | 
            dirtyIntArrayCaches = new IntArrayCache[BUCKETS];  | 
 | 
            dirtyFloatArrayCaches = new FloatArrayCache[BUCKETS];  | 
 | 
            dirtyByteArrayCaches = new ByteArrayCache[BUCKETS];  | 
 | 
 | 
 | 
            for (int i = 0; i < BUCKETS; i++) { | 
 | 
                intArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);  | 
 | 
                  | 
 | 
                dirtyIntArrayCaches[i] = new IntArrayCache(ARRAY_SIZES[i]);  | 
 | 
                dirtyFloatArrayCaches[i] = new FloatArrayCache(ARRAY_SIZES[i]);  | 
 | 
                dirtyByteArrayCaches[i] = new ByteArrayCache(DIRTY_BYTE_ARRAY_SIZES[i]);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |