Package sun.java2d.windows

Source Code of sun.java2d.windows.Win32SurfaceDataProxy

/*
* Copyright (c) 2007, 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.
*/

package sun.java2d.windows;

import java.awt.Color;
import java.awt.Transparency;
import java.awt.Rectangle;
import java.awt.image.ColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;

import sun.awt.Win32GraphicsConfig;
import sun.awt.Win32GraphicsDevice;
import sun.awt.image.BufImgSurfaceData;
import sun.awt.image.SunWritableRaster;
import sun.java2d.SurfaceData;
import sun.java2d.SurfaceDataProxy;
import sun.java2d.SunGraphics2D;
import sun.java2d.StateTracker;
import sun.java2d.InvalidPipeException;
import sun.java2d.loops.CompositeType;

/**
* The proxy class contains the logic for when to replace a
* SurfaceData with a cached X11 Pixmap and the code to create
* the accelerated surfaces.
*/
public abstract class Win32SurfaceDataProxy extends SurfaceDataProxy {
    /**
     * Represents the maximum size (width * height) of an image that we should
     * scan for an unused color.  Any image larger than this would probably
     * require too much computation time.
     */
    private static final int MAX_SIZE = 65536;

    public static SurfaceDataProxy createProxy(SurfaceData srcData,
                                               Win32GraphicsConfig dstConfig)
    {
        Win32GraphicsDevice wgd =
            (Win32GraphicsDevice) dstConfig.getDevice();
        if (!wgd.isDDEnabledOnDevice() ||
            srcData instanceof Win32SurfaceData ||
            srcData instanceof Win32OffScreenSurfaceData)
        {
            // If they are not on the same screen then we could cache the
            // blit by returning an instance of Opaque below, but this
            // only happens for VolatileImage blits to the wrong screen
            // which we make no promises on so we just punt to UNCACHED...
            return UNCACHED;
        }

        ColorModel srcCM = srcData.getColorModel();
        int srcTransparency = srcCM.getTransparency();

        if (srcTransparency == Transparency.OPAQUE) {
            return new Opaque(dstConfig);
        } else if (srcTransparency == Transparency.BITMASK) {
            if (Bitmask.isCompatible(srcCM, srcData)) {
                return new Bitmask(dstConfig);
            }
        }

        return UNCACHED;
    }

    int srcTransparency;
    Win32GraphicsConfig wgc;

    public Win32SurfaceDataProxy(Win32GraphicsConfig wgc,
                                 int srcTransparency)
    {
        this.wgc = wgc;
        this.srcTransparency = srcTransparency;
        activateDisplayListener();
    }

    @Override
    public SurfaceData validateSurfaceData(SurfaceData srcData,
                                           SurfaceData cachedData,
                                           int w, int h)
    {
        if (cachedData == null ||
            !cachedData.isValid() ||
            cachedData.isSurfaceLost())
        {
            // use the device's color model for ddraw surfaces
            ColorModel dstScreenCM = wgc.getDeviceColorModel();
            try {
                cachedData =
                    Win32OffScreenSurfaceData.createData(w, h,
                                                         dstScreenCM,
                                                         wgc, null,
                                                         srcTransparency);
            } catch (InvalidPipeException e) {
                Win32GraphicsDevice wgd = (Win32GraphicsDevice) wgc.getDevice();
                if (!wgd.isDDEnabledOnDevice()) {
                    invalidate();
                    flush();
                    return null;
                }
            }
        }
        return cachedData;
    }

    /**
     * Proxy for opaque source images.
     */
    public static class Opaque extends Win32SurfaceDataProxy {
        static int TXMAX =
            (WindowsFlags.isDDScaleEnabled()
             ? SunGraphics2D.TRANSFORM_TRANSLATESCALE
             : SunGraphics2D.TRANSFORM_ANY_TRANSLATE);

        public Opaque(Win32GraphicsConfig wgc) {
            super(wgc, Transparency.OPAQUE);
        }

        @Override
        public boolean isSupportedOperation(SurfaceData srcData,
                                            int txtype,
                                            CompositeType comp,
                                            Color bgColor)
        {
            // we save a read from video memory for compositing
            // operations by copying from the buffered image sd
            return (txtype <= TXMAX &&
                    (CompositeType.SrcOverNoEa.equals(comp) ||
                     CompositeType.SrcNoEa.equals(comp)));
        }
    }

    /**
     * Proxy for bitmask transparent source images.
     * This proxy can accelerate unscaled SrcOver copies with no bgColor.
     *
     * Note that this proxy plays some games with returning the srcData
     * from the validate method.  It needs to do this since the conditions
     * for caching an accelerated copy depend on many factors that can
     * change over time, including:
     *
     * - the depth of the display
     * - the availability of a transparent pixel
     */
    public static class Bitmask extends Win32SurfaceDataProxy {
        /**
         * Tests a source image ColorModel and SurfaceData to
         * see if they are of an appropriate size and type to
         * perform our transparent pixel searches.
         *
         * Note that some dynamic factors may occur which prevent
         * us from finding or using a transparent pixel.  These
         * are detailed above in the class comments.  We do not
         * test those conditions here, but rely on the Bitmask
         * proxy to verify those conditions on the fly.
         */
        public static boolean isCompatible(ColorModel srcCM,
                                           SurfaceData srcData)
        {
            if (srcCM instanceof IndexColorModel) {
                return true;
            } else if (srcCM instanceof DirectColorModel) {
                return isCompatibleDCM((DirectColorModel) srcCM, srcData);
            }

            return false;
        }

        /**
         * Tests a given DirectColorModel to make sure it is
         * compatible with the assumptions we make when scanning
         * a DCM image for a transparent pixel.
         */
        public static boolean isCompatibleDCM(DirectColorModel dcm,
                                              SurfaceData srcData)
        {
            // The BISD restriction is because we need to
            // examine the pixels to find a tranparent color
            if (!(srcData instanceof BufImgSurfaceData)) {
                return false;
            }

            // The size restriction prevents us from wasting too
            // much time scanning large images for unused pixel values.
            Rectangle bounds = srcData.getBounds();
            // Using division instead of multiplication avoids overflow
            if (bounds.width <= 0 ||
                MAX_SIZE / bounds.width < bounds.height)
            {
                return false;
            }

            // Below we use the pixels from the data buffer to map
            // directly to pixel values using the dstData.pixelFor()
            // method so the pixel format must be compatible with
            // ARGB or we could end up with bad results.  We assume
            // here that the destination is opaque and so only the
            // red, green, and blue masks matter.
            // These new checks for RGB masks are more correct,
            // but potentially reject the acceleration of some images
            // that we used to allow just because we cannot prove
            // that they will work OK.  If we ever had an INT_BGR
            // image for instance, would that have really failed here?
            // 565 and 555 screens will both keep equal numbers of
            // bits of red and blue, but will differ in the amount of
            // green they keep so INT_BGR might be safe, but if anyone
            // ever created an INT_RBG image then 555 and 565 might
            // differ in whether they thought a transparent pixel
            // was available.  Also, are there any other strange
            // screen formats where bizarre orderings of the RGB
            // would cause the tests below to make mistakes?
            return ((dcm.getPixelSize() == 25) &&
                    (dcm.getTransferType() == DataBuffer.TYPE_INT) &&
                    (dcm.getRedMask()   == 0x00ff0000) &&
                    (dcm.getGreenMask() == 0x0000ff00) &&
                    (dcm.getBlueMask()  == 0x000000ff));
        }

        int transPixel;
        Color transColor;

        // The real accelerated surface - only used when we can find
        // a transparent color.
        SurfaceData accelData;

        public Bitmask(Win32GraphicsConfig wgc) {
            super(wgc, Transparency.BITMASK);
        }

        @Override
        public boolean isSupportedOperation(SurfaceData srcData,
                                            int txtype,
                                            CompositeType comp,
                                            Color bgColor)
        {
            // We have accelerated loops only for blits with SrcOverNoEa
            // (no blit bg loops or blit loops with SrcNoEa)
            return (CompositeType.SrcOverNoEa.equals(comp) &&
                    bgColor == null &&
                    txtype < SunGraphics2D.TRANSFORM_TRANSLATESCALE);
        }

        /**
         * Note that every time we update the surface we may or may
         * not find a transparent pixel depending on what was modified
         * in the source image since the last time we looked.
         * Our validation method saves the accelerated surface aside
         * in a different field so we can switch back and forth between
         * the accelerated version and null depending on whether we
         * find a transparent pixel.
         * Note that we also override getRetryTracker() and return a
         * tracker that tracks the source pixels so that we do not
         * try to revalidate until there are new pixels to be scanned.
         */
        @Override
        public SurfaceData validateSurfaceData(SurfaceData srcData,
                                               SurfaceData cachedData,
                                               int w, int h)
        {
            // Evaluate the dest screen pixel size every time
            ColorModel dstScreenCM = wgc.getDeviceColorModel();
            if (dstScreenCM.getPixelSize() <= 8) {
                return null;
            }
            accelData = super.validateSurfaceData(srcData, accelData, w, h);
            return (accelData != null &&
                    findTransparentPixel(srcData, accelData))
                ? accelData
                : null;
        }

        @Override
        public StateTracker getRetryTracker(SurfaceData srcData) {
            // If we failed to validate, it is permanent until the
            // next change to srcData...
            return srcData.getStateTracker();
        }

        @Override
        public void updateSurfaceData(SurfaceData srcData,
                                      SurfaceData dstData,
                                      int w, int h)
        {
            updateSurfaceDataBg(srcData, dstData, w, h, transColor);
        }

        /**
         * Invoked when the cached surface should be dropped.
         * Overrides the base class implementation so we can invalidate
         * the accelData field instead of the cachedSD field.
         */
        @Override
        public synchronized void flush() {
            SurfaceData accelData = this.accelData;
            if (accelData != null) {
                this.accelData = null;
                accelData.flush();
            }
            super.flush();
        }

        /**
         * The following constants determine the size of the histograms
         * used when searching for an unused color
         */
        private static final int ICM_HISTOGRAM_SIZE = 256;
        private static final int ICM_HISTOGRAM_MASK = ICM_HISTOGRAM_SIZE - 1;
        private static final int DCM_HISTOGRAM_SIZE = 1024;
        private static final int DCM_HISTOGRAM_MASK = DCM_HISTOGRAM_SIZE - 1;

        /**
         * Attempts to find an unused pixel value in the image and if
         * successful, sets up the DirectDraw surface so that it uses
         * this value as its color key.
         */
        public boolean findTransparentPixel(SurfaceData srcData,
                                            SurfaceData accelData)
        {
            ColorModel srcCM = srcData.getColorModel();
            boolean success = false;

            if (srcCM instanceof IndexColorModel) {
                success = findUnusedPixelICM((IndexColorModel) srcCM,
                                             accelData);
            } else if (srcCM instanceof DirectColorModel) {
                success = findUnusedPixelDCM((BufImgSurfaceData) srcData,
                                             accelData);
            }

            if (success) {
                int rgb = accelData.rgbFor(transPixel);
                transColor = new Color(rgb);
                Win32OffScreenSurfaceData wossd =
                    (Win32OffScreenSurfaceData) accelData;
                wossd.setTransparentPixel(transPixel);
            } else {
                transColor = null;
            }
            return success;
        }

        /**
         * Attempts to find an unused pixel value in the color map of an
         * IndexColorModel.  If successful, it returns that value (in the
         * ColorModel of the destination surface) or null otherwise.
         */
        private boolean findUnusedPixelICM(IndexColorModel icm,
                                           SurfaceData accelData) {
            int mapsize = icm.getMapSize();
            int[] histogram = new int[ICM_HISTOGRAM_SIZE];
            int[] cmap = new int[mapsize];
            icm.getRGBs(cmap);

            // load up the histogram
            for (int i = 0; i < mapsize; i++) {
                int pixel = accelData.pixelFor(cmap[i]);
                histogram[pixel & ICM_HISTOGRAM_MASK]++;
            }

            // find an empty histo-bucket
            for (int j = 0; j < histogram.length; j++) {
                if (histogram[j] == 0) {
                    transPixel = j;
                    return true;
                }
            }

            return false;
        }

        /**
         * Attempts to find an unused pixel value in an image with a
         * 25-bit DirectColorModel and a DataBuffer of TYPE_INT.
         * If successful, it returns that value (in the ColorModel
         * of the destination surface) or null otherwise.
         */
        private boolean findUnusedPixelDCM(BufImgSurfaceData bisd,
                                           SurfaceData accelData)
        {
            BufferedImage bimg = (BufferedImage) bisd.getDestination();
            DataBufferInt db =
                (DataBufferInt) bimg.getRaster().getDataBuffer();
            int[] pixels = SunWritableRaster.stealData(db, 0);
            int[] histogram = new int[DCM_HISTOGRAM_SIZE];

            // load up the histogram
            // REMIND: we could possibly make this faster by keeping track
            // of the unique colors found, and only doing a pixelFor()
            // when we come across a new unique color
            // REMIND: We are assuming pixels are in ARGB format.  Is that
            // a safe assumption here?
            for (int i = 0; i < pixels.length; i++) {
                int pixel = accelData.pixelFor(pixels[i]);
                histogram[pixel & DCM_HISTOGRAM_MASK]++;
            }

            // find an empty histo-bucket
            for (int j = 0; j < histogram.length; j++) {
                if (histogram[j] == 0) {
                    transPixel = j;
                    return true;
                }
            }

            return false;
        }
    }
}
TOP

Related Classes of sun.java2d.windows.Win32SurfaceDataProxy

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.