Package org.apache.harmony.awt.wtk.linux

Source Code of org.apache.harmony.awt.wtk.linux.LinuxCursorFactory

/*
*  Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You under the Apache License, Version 2.0
*  (the "License"); you may not use this file except in compliance with
*  the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
/**
* @author Dmitry A. Durnev
* @version $Revision$
*/
package org.apache.harmony.awt.wtk.linux;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.awt.image.WritableRaster;

import org.apache.harmony.awt.gl.Utils;
import org.apache.harmony.awt.internal.nls.Messages;
import org.apache.harmony.awt.nativebridge.linux.X11;
import org.apache.harmony.awt.nativebridge.linux.X11Defs;
import org.apache.harmony.awt.wtk.CursorFactory;
import org.apache.harmony.awt.wtk.NativeCursor;
import org.apache.harmony.misc.accessors.AccessorFactory;
import org.apache.harmony.misc.accessors.ArrayAccessor;
import org.apache.harmony.misc.accessors.LockedArray;
import org.apache.harmony.misc.accessors.MemoryAccessor;

/**
* Implementation of CursorFactory for Linux(X11) platform.
*/
public class LinuxCursorFactory extends CursorFactory implements X11Defs {
    private static final X11 x11 = X11.getInstance();
    private static final MemoryAccessor memAccess = AccessorFactory.getMemoryAccessor();

    private final long display;
    private final LinuxWindowFactory factory;

    LinuxCursorFactory(LinuxWindowFactory factory) {
        this.factory = factory;
        display = factory.getDisplay();
    }

    /**
     * Java to native type translation table:
     * native id of symbol in cursorfont(from cursorfont.h),
     * commented Java cursor type
     */
    static final int [] predefined = {
            XC_top_left_arrow, /*DEFAULT_CURSOR*/
            XC_cross, /*CROSSHAIR_CURSOR*/
            XC_xterm, /*TEXT_CURSOR*/
            XC_watch, /*WAIT_CURSOR*/
            XC_bottom_left_corner, /*SW_RESIZE_CURSOR*/
            XC_bottom_right_corner, /*SE_RESIZE_CURSOR*/
            XC_top_left_corner, /*NW_RESIZE_CURSOR*/
            XC_top_right_corner, /*NE_RESIZE_CURSOR*/
            XC_top_side, /*N_RESIZE_CURSOR*/
            XC_bottom_side, /*S_RESIZE_CURSOR*/
            XC_left_side, /*W_RESIZE_CURSOR*/
            XC_right_side, /*E_RESIZE_CURSOR*/
            XC_hand2, /*HAND_CURSOR*/
            XC_fleur, /*MOVE_CURSOR*/

    };
    /**
     * @see org.apache.harmony.awt.wtk.CursorFactory#createCursor(int)
     */
    public NativeCursor createCursor(int type) {
        if (type >= 0 && type < predefined.length) {
            long cursor = x11.XCreateFontCursor(display, predefined[type]);
            return new LinuxCursor(cursor, display);
        }
        return null;
    }

    /**
     * @see org.apache.harmony.awt.wtk.CursorFactory#createCustomCursor(java.awt.Image, int, int)
     */
    public NativeCursor createCustomCursor(Image img, int xHotSpot, int yHotSpot) {

        int width = img.getWidth(null);
        int height = img.getHeight(null);
        BufferedImage bufImg = Utils.getBufferedImage(img);
        //must convert image into TYPE_BYTE_BINARY format of depth 1
        BufferedImage bmpSrc = convertTo1Bit(/*bufImg*/img);
        BufferedImage bmpMask = getMask(bufImg);
        //get pixel data from bufImg & create X11 pixmap
        byte[] bmpSrcData = ((DataBufferByte) bmpSrc.getData().getDataBuffer()).getData();
        byte[] bmpMaskData = ((DataBufferByte) bmpMask.getData().getDataBuffer()).getData();

        ArrayAccessor arrayAccess = AccessorFactory.getArrayAccessor();
        long wnd = factory.getRootWindow();
        LockedArray larr = arrayAccess.lockArrayShort(bmpSrcData);
        long dataPtr = larr.getAddress();
        long pixmap = x11.XCreateBitmapFromData(display, wnd,
                dataPtr, width, height);
        //System.out.println("source pixmap=" + pixmap);
        larr.release();

        larr = arrayAccess.lockArrayShort(bmpMaskData);
        dataPtr = larr.getAddress();
        long pixmapMask = x11.XCreateBitmapFromData(display, wnd, dataPtr,
                width, height);
        //System.out.println("mask pixmap=" + pixmap);
        larr.release();
        int fgRGB = bufImg.getRGB(0, 0);
        Color fgColor = new Color(fgRGB);
        Color bkColor = getBkColor(bufImg, fgColor);
        X11.XColor bkColorPtr = getXColor(bkColor);
        X11.XColor fgColorPtr = getXColor(fgColor);
        //then pass this pixmap to x11.XCreatePixmapCursor()
        long cursor = x11.XCreatePixmapCursor(display, pixmap, pixmapMask,
                fgColorPtr, bkColorPtr, xHotSpot, yHotSpot);

        x11.XFreePixmap(display, pixmap);
        x11.XFreePixmap(display, pixmapMask);

        return new LinuxCursor(cursor, display);
    }

    /**
     * Select one of bufImg pixel colors as background color
     * when foreground color is fgColor.
     * @param bufImg
     * @param fgColor
     * @return background color
     */
    private Color getBkColor(BufferedImage bufImg, Color fgColor) {
        int w = bufImg.getWidth(), h = bufImg.getHeight();
        float maxError = 0, error = 0;
        Color color, bkColor = fgColor;
        ColorSpace diffSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
        for (int x = 0; x < w; x++) {
            for (int y = 0; y < h; y++) {
                int rgb = bufImg.getRGB(x, y);
                color = new Color(rgb);
                error = getColorDistance(color, fgColor, diffSpace);
                if (error > maxError) {
                    maxError = error;
                    bkColor = color;
                }
            }
        }
        return bkColor;
    }

    /**
     * Returns square of "distance" between 2 colors in
     * color space cspace
     * @param color1
     * @param color2
     * @param cspace color space where to compare 2 colors
     * @return
     */
    private float getColorDistance(Color color1, Color color2, ColorSpace cspace) {
        float[] c1 = color1.getRGBColorComponents(/*cspace, */null);
        float[] c2 = color2.getRGBColorComponents(/*cspace, */null);

        float sum = 0;
        for (int i=0; i < Math.min(c1.length, c2.length); i++) {
            float diff = c1[i] - c2[i];
            sum += diff * diff;
        }
        return sum;
    }

    /**
     * @param fgRGB
     * @return
     */
    static X11.XColor getXColor(Color color) {
        X11.XColor xcolor = x11.createXColor(false);
        //shift to set MSB for 8-bit R,G,B values
        xcolor.set_green((short)(color.getGreen() << 8));
        xcolor.set_blue((short)(color.getBlue() << 8));
        xcolor.set_red((short)(color.getRed() << 8));

        return xcolor;
    }

    /**
     * Create a mask as 1-bit bitmap from bufImg with alpha.
     * Mask has the same size as bufImg. Mask pixel is 0 for
     * completely transparent pixel in bufImg (alpha=0) and 1 otherwise.
     * @param bufImg
     * @return new BufferedImage containing mask
     */
    static BufferedImage getMask(BufferedImage bufImg) {
        int w = bufImg.getWidth(), h = bufImg.getHeight();
        //WritableRaster alphaRaster = bufImg.getAlphaRaster();
        BufferedImage dstImg = new BufferedImage(w, h,
                BufferedImage.TYPE_BYTE_BINARY);
        WritableRaster raster = dstImg.getRaster();
       //dstImg.setData(alphaRaster);
        for (int x = 0; x < w; x++) {
            for (int y = 0; y < h; y++) {
                int rgb = bufImg.getRGB(x, y);
                //dstImg.setRGB(x, y, (rgb & 0xFF000000) != 0 ? 0xFFFFFF : 0x0);
                raster.setPixel(x, y, (rgb & 0xFF000000) != 0 ? new int[] {0x1} : new int[] {0x0});
            }
        }
        return dstImg;
    }

    /**
     * we have to explicitly free system("predefined") cursors on X11
     * because actually they're not "system", but just normal cursors
     */
    protected void finalize() {
        //System.out.println("finalizing system cursors on X11!");
        for (int i = 0; i < systemCursors.length; i++) {
            LinuxCursor cursor = (LinuxCursor) systemCursors[i];
            if (cursor != null) {
                cursor.destroy();
            }
        }
    }

    /**
     * @see org.apache.harmony.awt.wtk.CursorFactory#getBestCursorSize(int, int)
     */
    public Dimension getBestCursorSize(int prefWidth, int prefHeight) {
        long rwidthPtr = memAccess.malloc(4);
        long rheightPtr = memAccess.malloc(4);
        int status = x11.XQueryBestCursor(display, factory.getRootWindow(),
                prefWidth, prefHeight, rwidthPtr, rheightPtr);
        int rwidth = 0, rheight = 0;
        if (status == 1) {
            rwidth = memAccess.getInt(rwidthPtr);
            rheight = memAccess.getInt(rheightPtr);
        }
        memAccess.free(rwidthPtr);
        memAccess.free(rheightPtr);
        return new Dimension(rwidth, rheight);
    }

    /**
     * @see org.apache.harmony.awt.wtk.CursorFactory#getMaximumCursorColors()
     */
    public int getMaximumCursorColors() {
        // TODO query XServer if RENDER extension is supported
        // and return (& use for custom cursors) more than 2 colors in this case
        return 2;
    }

    X11.XColor getXColorByName(String strColor) {
        X11.XColor color = x11.createXColor(false);
        int status = x11.XParseColor(display,
                x11.XDefaultColormap(display, factory.getScreen()),
                strColor, color);
        if (status == 0) {
            // awt.13=Cannot allocate color named '{0}'
            throw new RuntimeException(Messages.getString("awt.13", strColor)); //$NON-NLS-1$
        }
        return color;
    }
    /**
     * Convert buffered image src to 1-bit BYTE_BINARY buffered image.
     * @param src Image to convert
     * @return new Buffered image containing 1-bit bitmap
     */
    static BufferedImage convertTo1Bit(Image src) {
        int w = src.getWidth(null);
        int h = src.getHeight(null);

        BufferedImage dstImg = new BufferedImage(w, h,
                BufferedImage.TYPE_BYTE_BINARY);
        dstImg.getGraphics().drawImage(src, 0, 0, null);
        return dstImg;

    }
}
TOP

Related Classes of org.apache.harmony.awt.wtk.linux.LinuxCursorFactory

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.