1 /* 2 * Copyright (c) 1997, 2014, 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 package sun.awt; 27 28 import sun.awt.CustomCursor; 29 import java.awt.*; 30 import java.awt.image.*; 31 import sun.awt.image.ImageRepresentation; 32 33 /** 34 * A class to encapsulate a custom image-based cursor. 35 * 36 * @see Component#setCursor 37 * @author Thomas Ball 38 */ 39 @SuppressWarnings("serial") // JDK-implementation class 40 public abstract class X11CustomCursor extends CustomCursor { 41 42 public X11CustomCursor(Image cursor, Point hotSpot, String name) 43 throws IndexOutOfBoundsException { 44 super(cursor, hotSpot, name); 45 } 46 47 protected void createNativeCursor(Image im, int[] pixels, int width, int height, 48 int xHotSpot, int yHotSpot) { 49 50 class CCount implements Comparable<CCount> { 51 int color; 52 int count; 53 54 public CCount(int cl, int ct) { 55 color = cl; 56 count = ct; 57 } 58 59 public int compareTo(CCount cc) { 60 return cc.count - count; 61 } 62 } 63 64 int tmp[] = new int[pixels.length]; 65 for (int i=0; i<pixels.length; i++) { 66 if ((pixels[i] & 0xff000000) == 0) { 67 tmp[i] = -1; 68 } else { 69 tmp[i] = pixels[i] & 0x00ffffff; 70 } 71 } 72 java.util.Arrays.sort(tmp); 73 74 int fc = 0x000000; 75 int bc = 0xffffff; 76 CCount cols[] = new CCount[pixels.length]; 77 78 int is = 0; 79 int numColors = 0; 80 while ( is < pixels.length ) { 81 if (tmp[is] != -1) { 82 cols[numColors++] = new CCount(tmp[is], 1); 83 break; 84 } 85 is ++; 86 } 87 88 for (int i = is+1; i < pixels.length; i++) { 89 if (tmp[i] != cols[numColors-1].color) { 90 cols[numColors++] = new CCount(tmp[i], 1); 91 } else { 92 cols[numColors-1].count ++; 93 } 94 } 95 java.util.Arrays.sort(cols, 0, numColors); 96 97 if (numColors > 0) fc = cols[0].color; 98 int fcr = (fc >> 16) & 0x000000ff; 99 int fcg = (fc >> 8) & 0x000000ff; 100 int fcb = (fc >> 0) & 0x000000ff; 101 102 int rdis = 0; 103 int gdis = 0; 104 int bdis = 0; 105 for (int j = 1; j < numColors; j++) { 106 int rr = (cols[j].color >> 16) & 0x000000ff; 107 int gg = (cols[j].color >> 8) & 0x000000ff; 108 int bb = (cols[j].color >> 0) & 0x000000ff; 109 rdis = rdis + cols[j].count * rr; 110 gdis = gdis + cols[j].count * gg; 111 bdis = bdis + cols[j].count * bb; 112 } 113 int rest = pixels.length - ((numColors > 0) ? cols[0].count : 0); 114 // 4653170 Avoid divide / zero exception 115 if (rest > 0) { 116 rdis = rdis / rest - fcr; 117 gdis = gdis / rest - fcg; 118 bdis = bdis / rest - fcb; 119 } 120 rdis = (rdis*rdis + gdis*gdis + bdis*bdis) / 2; 121 // System.out.println(" rdis is "+ rdis); 122 123 for (int j = 1; j < numColors; j++) { 124 int rr = (cols[j].color >> 16) & 0x000000ff; 125 int gg = (cols[j].color >> 8) & 0x000000ff; 126 int bb = (cols[j].color >> 0) & 0x000000ff; 127 128 if ( (rr-fcr)*(rr-fcr) + (gg-fcg)*(gg-fcg) + (bb-fcb)*(bb-fcb) 129 >= rdis ) { 130 bc = cols[j].color; 131 break; 132 } 133 } 134 int bcr = (bc >> 16) & 0x000000ff; 135 int bcg = (bc >> 8) & 0x000000ff; 136 int bcb = (bc >> 0) & 0x000000ff; 137 138 139 // On Solaris 2.5.x, the above code for cursor of any size runs fine 140 // but on Solaris 2.6, the width of a cursor has to be 8 divisible, 141 // otherwise, the cursor could be displayed as garbaged. 142 // To work around the 2.6 problem, the following code pads any cursor 143 // with a transparent area to make a new cursor of width 8 multiples. 144 // --- Bug 4148455 145 int wNByte = (width + 7)/8; 146 int tNByte = wNByte * height; 147 byte[] xorMask = new byte[tNByte]; 148 byte[] andMask = new byte[tNByte]; 149 150 for (int i = 0; i < width; i++) { 151 int omask = 1 << (i % 8); 152 for (int j = 0; j < height; j++) { 153 int ip = j*width + i; 154 int ibyte = j*wNByte + i/8; 155 156 if ((pixels[ip] & 0xff000000) != 0) { 157 andMask[ibyte] |= omask; 158 } 159 160 int pr = (pixels[ip] >> 16) & 0x000000ff; 161 int pg = (pixels[ip] >> 8) & 0x000000ff; 162 int pb = (pixels[ip] >> 0) & 0x000000ff; 163 if ( (pr-fcr)*(pr-fcr) + (pg-fcg)*(pg-fcg) + (pb-fcb)*(pb-fcb) 164 <= (pr-bcr)*(pr-bcr) + (pg-bcg)*(pg-bcg) + (pb-bcb)*(pb-bcb) ) { 165 // show foreground color 166 xorMask[ibyte] |= omask; 167 } 168 } 169 } 170 171 createCursor(xorMask, andMask, 8*wNByte, height, fc, bc, xHotSpot, yHotSpot); 172 } 173 174 protected abstract void createCursor(byte[] xorMask, byte[] andMask, 175 int width, int height, 176 int fcolor, int bcolor, 177 int xHotSpot, int yHotSpot); 178 179 }