| 1 | /* | 
|---|
| 2 | * Copyright (c) 2005, 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 | #include "splashscreen_gfx_impl.h" | 
|---|
| 27 |  | 
|---|
| 28 | /* *INDENT-OFF* */ | 
|---|
| 29 | const byte_t baseDitherMatrix[DITHER_SIZE][DITHER_SIZE] = { | 
|---|
| 30 | /* Bayer's order-4 dither array.  Generated by the code given in | 
|---|
| 31 | * Stephen Hawley's article "Ordered Dithering" in Graphics Gems I. | 
|---|
| 32 | */ | 
|---|
| 33 | {   0,192, 48,240, 12,204, 60,252,  3,195, 51,243, 15,207, 63,255 }, | 
|---|
| 34 | { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 }, | 
|---|
| 35 | {  32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 }, | 
|---|
| 36 | { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 }, | 
|---|
| 37 | {   8,200, 56,248,  4,196, 52,244, 11,203, 59,251,  7,199, 55,247 }, | 
|---|
| 38 | { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 }, | 
|---|
| 39 | {  40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 }, | 
|---|
| 40 | { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 }, | 
|---|
| 41 | {   2,194, 50,242, 14,206, 62,254,  1,193, 49,241, 13,205, 61,253 }, | 
|---|
| 42 | { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 }, | 
|---|
| 43 | {  34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 }, | 
|---|
| 44 | { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 }, | 
|---|
| 45 | {  10,202, 58,250,  6,198, 54,246,  9,201, 57,249,  5,197, 53,245 }, | 
|---|
| 46 | { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 }, | 
|---|
| 47 | {  42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 }, | 
|---|
| 48 | { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 } | 
|---|
| 49 | }; | 
|---|
| 50 | /* *INDENT-ON* */ | 
|---|
| 51 |  | 
|---|
| 52 | // FIXME: tinting on some colormaps (e.g. 1-2-1) means something is slightly wrong with | 
|---|
| 53 | // colormap calculation... probably it's some rounding error | 
|---|
| 54 |  | 
|---|
| 55 | /*  calculates the colorTable for mapping from 0..255 to 0..numColors-1 | 
|---|
| 56 | also calculates the dithering matrix, scaling baseDitherMatrix accordingly */ | 
|---|
| 57 | void | 
|---|
| 58 | initDither(DitherSettings * pDither, int numColors, int scale) | 
|---|
| 59 | { | 
|---|
| 60 | int i, j; | 
|---|
| 61 |  | 
|---|
| 62 | pDither->numColors = numColors; | 
|---|
| 63 | for (i = 0; i < (MAX_COLOR_VALUE + 1) * 2; i++) { | 
|---|
| 64 | pDither->colorTable[i] = | 
|---|
| 65 | (((i > MAX_COLOR_VALUE) ? MAX_COLOR_VALUE : i) * | 
|---|
| 66 | (numColors - 1) / MAX_COLOR_VALUE) * scale; | 
|---|
| 67 | } | 
|---|
| 68 | for (i = 0; i < DITHER_SIZE; i++) | 
|---|
| 69 | for (j = 0; j < DITHER_SIZE; j++) | 
|---|
| 70 | pDither->matrix[i][j] = | 
|---|
| 71 | (int) baseDitherMatrix[i][j] / (numColors - 1); | 
|---|
| 72 | } | 
|---|
| 73 |  | 
|---|
| 74 | /* scale a number on the range of 0..numColorsIn-1 to 0..numColorsOut-1 | 
|---|
| 75 | 0 maps to 0 and numColorsIn-1 maps to numColorsOut-1 | 
|---|
| 76 | intermediate values are spread evenly between 0 and numColorsOut-1 */ | 
|---|
| 77 | INLINE int | 
|---|
| 78 | scaleColor(int color, int numColorsIn, int numColorsOut) | 
|---|
| 79 | { | 
|---|
| 80 | return (color * (numColorsOut - 1) + (numColorsIn - 1) / 2) | 
|---|
| 81 | / (numColorsIn - 1); | 
|---|
| 82 | } | 
|---|
| 83 |  | 
|---|
| 84 | /*  build a colormap for a color cube and a dithering matrix. color cube is quantized | 
|---|
| 85 | according to the provided maximum number of colors */ | 
|---|
| 86 | int | 
|---|
| 87 | quantizeColors(int maxNumColors, int *numColors) | 
|---|
| 88 | { | 
|---|
| 89 |  | 
|---|
| 90 | // static const int scale[3]={10000/11,10000/69,10000/30}; | 
|---|
| 91 | // FIXME: sort out the adaptive color cube subdivision... realistic 11:69:30 is good on photos, | 
|---|
| 92 | // but would be bad on other pictures. A stupid approximation is used now. | 
|---|
| 93 |  | 
|---|
| 94 | static const int scale[3] = { 8, 4, 6 }; | 
|---|
| 95 |  | 
|---|
| 96 | // maxNumColors should be at least 2x2x2=8, or we lose some color components completely | 
|---|
| 97 | numColors[0] = numColors[1] = numColors[2] = 2; | 
|---|
| 98 |  | 
|---|
| 99 | while (1) { | 
|---|
| 100 | int idx[3] = { 0, 1, 2 }; | 
|---|
| 101 | /* bubble sort the three indexes according to scaled numColors values */ | 
|---|
| 102 | #define SORT(i,j) \ | 
|---|
| 103 | if (numColors[idx[i]]*scale[idx[i]]>numColors[idx[j]]*scale[idx[j]]) \ | 
|---|
| 104 | { int t = idx[i]; idx[i] = idx[j]; idx[j] = t; } | 
|---|
| 105 | SORT(0, 1); | 
|---|
| 106 | SORT(1, 2); | 
|---|
| 107 | SORT(0, 1); | 
|---|
| 108 | /* try increasing numColors for the first color */ | 
|---|
| 109 | if ((numColors[idx[0]] + 1) * numColors[idx[1]] * | 
|---|
| 110 | numColors[idx[2]] <= maxNumColors) { | 
|---|
| 111 | numColors[idx[0]]++; | 
|---|
| 112 | } else if (numColors[idx[0]] * (numColors[idx[1]] + 1) * | 
|---|
| 113 | numColors[idx[2]] <= maxNumColors) { | 
|---|
| 114 | numColors[idx[1]]++; | 
|---|
| 115 | } else if (numColors[idx[0]] * numColors[idx[1]] * | 
|---|
| 116 | (numColors[idx[2]] + 1) <= maxNumColors) { | 
|---|
| 117 | numColors[idx[2]]++; | 
|---|
| 118 | } else { | 
|---|
| 119 | break; | 
|---|
| 120 | } | 
|---|
| 121 | } | 
|---|
| 122 | return numColors[0] * numColors[1] * numColors[2]; | 
|---|
| 123 | } | 
|---|
| 124 |  | 
|---|
| 125 | void | 
|---|
| 126 | initColorCube(int *numColors, rgbquad_t * pColorMap, DitherSettings * pDithers, | 
|---|
| 127 | rgbquad_t * colorIndex) | 
|---|
| 128 | { | 
|---|
| 129 | int r, g, b, n; | 
|---|
| 130 |  | 
|---|
| 131 | n = 0; | 
|---|
| 132 | for (r = 0; r < numColors[2]; r++) { | 
|---|
| 133 | for (g = 0; g < numColors[1]; g++) | 
|---|
| 134 | for (b = 0; b < numColors[0]; b++) { | 
|---|
| 135 | pColorMap[colorIndex[n++]] = | 
|---|
| 136 | scaleColor(b, numColors[0], MAX_COLOR_VALUE) + | 
|---|
| 137 | (scaleColor(g, numColors[1], MAX_COLOR_VALUE) << 8) + | 
|---|
| 138 | (scaleColor(r, numColors[2], MAX_COLOR_VALUE) << 16); | 
|---|
| 139 | } | 
|---|
| 140 | } | 
|---|
| 141 | initDither(pDithers + 0, numColors[0], 1); | 
|---|
| 142 | initDither(pDithers + 1, numColors[1], numColors[0]); | 
|---|
| 143 | initDither(pDithers + 2, numColors[2], numColors[1] * numColors[0]); | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | /* | 
|---|
| 147 | the function below is a line conversion loop | 
|---|
| 148 |  | 
|---|
| 149 | incSrc and incDst are pSrc and pDst increment values for the loop, in bytes | 
|---|
| 150 | mode defines how the pixels should be processed | 
|---|
| 151 |  | 
|---|
| 152 | mode==CVT_COPY means the pixels should be copied as is | 
|---|
| 153 | mode==CVT_ALPHATEST means pixels should be skipped when source pixel alpha is above the threshold | 
|---|
| 154 | mode==CVT_BLEND means alpha blending between source and destination should be performed, while | 
|---|
| 155 | destination alpha should be retained. source alpha is used for blending. | 
|---|
| 156 | */ | 
|---|
| 157 | void | 
|---|
| 158 | convertLine(void *pSrc, int incSrc, void *pDst, int incDst, int numSamples, | 
|---|
| 159 | ImageFormat * srcFormat, ImageFormat * dstFormat, int doAlpha, | 
|---|
| 160 | void *pSrc2, int incSrc2, ImageFormat * srcFormat2, | 
|---|
| 161 | int row, int col) | 
|---|
| 162 | { | 
|---|
| 163 | int i; | 
|---|
| 164 |  | 
|---|
| 165 | switch (doAlpha) { | 
|---|
| 166 | case CVT_COPY: | 
|---|
| 167 | for (i = 0; i < numSamples; ++i) { | 
|---|
| 168 | putRGBADither(getRGBA(pSrc, srcFormat), pDst, dstFormat, | 
|---|
| 169 | row, col++); | 
|---|
| 170 | INCPN(byte_t, pSrc, incSrc); | 
|---|
| 171 | INCPN(byte_t, pDst, incDst); | 
|---|
| 172 | } | 
|---|
| 173 | break; | 
|---|
| 174 | case CVT_ALPHATEST: | 
|---|
| 175 | for (i = 0; i < numSamples; ++i) { | 
|---|
| 176 | rgbquad_t color = getRGBA(pSrc, srcFormat); | 
|---|
| 177 |  | 
|---|
| 178 | if (color >= ALPHA_THRESHOLD) {     // test for alpha component >50%. that's an extra branch, and it's bad... | 
|---|
| 179 | putRGBADither(color, pDst, dstFormat, row, col++); | 
|---|
| 180 | } | 
|---|
| 181 | INCPN(byte_t, pSrc, incSrc); | 
|---|
| 182 | INCPN(byte_t, pDst, incDst); | 
|---|
| 183 | } | 
|---|
| 184 | break; | 
|---|
| 185 | case CVT_BLEND: | 
|---|
| 186 | for (i = 0; i < numSamples; ++i) { | 
|---|
| 187 | rgbquad_t src = getRGBA(pSrc, srcFormat); | 
|---|
| 188 | rgbquad_t src2 = getRGBA(pSrc2, srcFormat); | 
|---|
| 189 |  | 
|---|
| 190 | putRGBADither(blendRGB(src, src2, | 
|---|
| 191 | QUAD_ALPHA(src2)) | (src & QUAD_ALPHA_MASK), pDst, dstFormat, | 
|---|
| 192 | row, col++); | 
|---|
| 193 | INCPN(byte_t, pSrc, incSrc); | 
|---|
| 194 | INCPN(byte_t, pDst, incDst); | 
|---|
| 195 | INCPN(byte_t, pSrc2, incSrc2); | 
|---|
| 196 | } | 
|---|
| 197 | break; | 
|---|
| 198 | } | 
|---|
| 199 | } | 
|---|
| 200 |  | 
|---|
| 201 | /* initialize ImageRect structure according to function arguments */ | 
|---|
| 202 | void | 
|---|
| 203 | initRect(ImageRect * pRect, int x, int y, int width, int height, int jump, | 
|---|
| 204 | int stride, void *pBits, ImageFormat * format) | 
|---|
| 205 | { | 
|---|
| 206 | int depthBytes = format->depthBytes; | 
|---|
| 207 |  | 
|---|
| 208 | pRect->pBits = pBits; | 
|---|
| 209 | INCPN(byte_t, pRect->pBits, y * stride + x * depthBytes); | 
|---|
| 210 | pRect->numLines = height; | 
|---|
| 211 | pRect->numSamples = width; | 
|---|
| 212 | pRect->stride = stride * jump; | 
|---|
| 213 | pRect->depthBytes = depthBytes; | 
|---|
| 214 | pRect->format = format; | 
|---|
| 215 | pRect->row = y; | 
|---|
| 216 | pRect->col = x; | 
|---|
| 217 | pRect->jump = jump; | 
|---|
| 218 | } | 
|---|
| 219 |  | 
|---|
| 220 | /*  copy image rectangle from source to destination, or from two sources with blending */ | 
|---|
| 221 |  | 
|---|
| 222 | int | 
|---|
| 223 | convertRect(ImageRect * pSrcRect, ImageRect * pDstRect, int mode) | 
|---|
| 224 | { | 
|---|
| 225 | return convertRect2(pSrcRect, pDstRect, mode, NULL); | 
|---|
| 226 | } | 
|---|
| 227 |  | 
|---|
| 228 | int | 
|---|
| 229 | convertRect2(ImageRect * pSrcRect, ImageRect * pDstRect, int mode, | 
|---|
| 230 | ImageRect * pSrcRect2) | 
|---|
| 231 | { | 
|---|
| 232 | int numLines = pSrcRect->numLines; | 
|---|
| 233 | int numSamples = pSrcRect->numSamples; | 
|---|
| 234 | void *pSrc = pSrcRect->pBits; | 
|---|
| 235 | void *pDst = pDstRect->pBits; | 
|---|
| 236 | void *pSrc2 = NULL; | 
|---|
| 237 | int j, row; | 
|---|
| 238 |  | 
|---|
| 239 | if (pDstRect->numLines < numLines) | 
|---|
| 240 | numLines = pDstRect->numLines; | 
|---|
| 241 | if (pDstRect->numSamples < numSamples) { | 
|---|
| 242 | numSamples = pDstRect->numSamples; | 
|---|
| 243 | } | 
|---|
| 244 | if (pSrcRect2) { | 
|---|
| 245 | if (pSrcRect2->numLines < numLines) { | 
|---|
| 246 | numLines = pSrcRect2->numLines; | 
|---|
| 247 | } | 
|---|
| 248 | if (pSrcRect2->numSamples < numSamples) { | 
|---|
| 249 | numSamples = pSrcRect2->numSamples; | 
|---|
| 250 | } | 
|---|
| 251 | pSrc2 = pSrcRect2->pBits; | 
|---|
| 252 | } | 
|---|
| 253 | row = pDstRect->row; | 
|---|
| 254 | for (j = 0; j < numLines; j++) { | 
|---|
| 255 | convertLine(pSrc, pSrcRect->depthBytes, pDst, pDstRect->depthBytes, | 
|---|
| 256 | numSamples, pSrcRect->format, pDstRect->format, mode, | 
|---|
| 257 | pSrc2, pSrcRect2 ? pSrcRect2->depthBytes : 0, | 
|---|
| 258 | pSrcRect2 ? pSrcRect2->format : 0, row, pDstRect->col); | 
|---|
| 259 | INCPN(byte_t, pSrc, pSrcRect->stride); | 
|---|
| 260 | INCPN(byte_t, pDst, pDstRect->stride); | 
|---|
| 261 | if (pSrcRect2) { | 
|---|
| 262 | INCPN(byte_t, pSrc2, pSrcRect2->stride); | 
|---|
| 263 | } | 
|---|
| 264 | row += pDstRect->jump; | 
|---|
| 265 | } | 
|---|
| 266 | return numLines * pSrcRect->stride; | 
|---|
| 267 | } | 
|---|
| 268 |  | 
|---|
| 269 | int | 
|---|
| 270 | fillRect(rgbquad_t color, ImageRect * pDstRect) | 
|---|
| 271 | { | 
|---|
| 272 | int numLines = pDstRect->numLines; | 
|---|
| 273 | int numSamples = pDstRect->numSamples; | 
|---|
| 274 | void *pDst = pDstRect->pBits; | 
|---|
| 275 | int j, row; | 
|---|
| 276 |  | 
|---|
| 277 | row = pDstRect->row; | 
|---|
| 278 | for (j = 0; j < numLines; j++) { | 
|---|
| 279 | fillLine(color, pDst, pDstRect->depthBytes, numSamples, | 
|---|
| 280 | pDstRect->format, row, pDstRect->col); | 
|---|
| 281 | INCPN(byte_t, pDst, pDstRect->stride); | 
|---|
| 282 | row += pDstRect->jump; | 
|---|
| 283 | } | 
|---|
| 284 | return numLines * pDstRect->stride; | 
|---|
| 285 | } | 
|---|
| 286 |  | 
|---|
| 287 | /* init the masks; all other parameters are initialized to default values */ | 
|---|
| 288 | void | 
|---|
| 289 | initFormat(ImageFormat * format, int redMask, int greenMask, int blueMask, | 
|---|
| 290 | int alphaMask) | 
|---|
| 291 | { | 
|---|
| 292 | int i, shift, numBits; | 
|---|
| 293 |  | 
|---|
| 294 | format->byteOrder = BYTE_ORDER_NATIVE; | 
|---|
| 295 | format->colorMap = NULL; | 
|---|
| 296 | format->depthBytes = 4; | 
|---|
| 297 | format->fixedBits = 0; | 
|---|
| 298 | format->premultiplied = 0; | 
|---|
| 299 | format->mask[0] = blueMask; | 
|---|
| 300 | format->mask[1] = greenMask; | 
|---|
| 301 | format->mask[2] = redMask; | 
|---|
| 302 | format->mask[3] = alphaMask; | 
|---|
| 303 | for (i = 0; i < 4; i++) { | 
|---|
| 304 | getMaskShift(format->mask[i], &shift, &numBits); | 
|---|
| 305 | format->shift[i] = shift + numBits - i * 8 - 8; | 
|---|
| 306 | } | 
|---|
| 307 | } | 
|---|
| 308 |  | 
|---|
| 309 | /* dump the visual format */ | 
|---|
| 310 | void | 
|---|
| 311 | dumpFormat(ImageFormat * format) | 
|---|
| 312 | { | 
|---|
| 313 | #ifdef _DEBUG | 
|---|
| 314 | int i; | 
|---|
| 315 |  | 
|---|
| 316 | printf( "byteorder=%d colormap=%08x depthBytes=%d fixedBits=%08x transparentColor=%u ", | 
|---|
| 317 | format->byteOrder, (unsigned) format->colorMap, format->depthBytes, | 
|---|
| 318 | (unsigned) format->fixedBits, (unsigned) format->transparentColor); | 
|---|
| 319 | for (i = 0; i < 4; i++) { | 
|---|
| 320 | printf( "mask[%d]=%08x shift[%d]=%d\n", i, (unsigned) format->mask[i], i, | 
|---|
| 321 | format->shift[i]); | 
|---|
| 322 | } | 
|---|
| 323 | printf( "\n"); | 
|---|
| 324 | #endif | 
|---|
| 325 | } | 
|---|
| 326 |  | 
|---|
| 327 | /* optimize the format */ | 
|---|
| 328 | void | 
|---|
| 329 | optimizeFormat(ImageFormat * format) | 
|---|
| 330 | { | 
|---|
| 331 | if (platformByteOrder() == format->byteOrder && format->depthBytes != 3) { | 
|---|
| 332 | format->byteOrder = BYTE_ORDER_NATIVE; | 
|---|
| 333 | } | 
|---|
| 334 | /* FIXME: some advanced optimizations are possible, especially for format pairs */ | 
|---|
| 335 | } | 
|---|
| 336 |  | 
|---|
| 337 | int | 
|---|
| 338 | platformByteOrder() | 
|---|
| 339 | { | 
|---|
| 340 | int test = 1; | 
|---|
| 341 |  | 
|---|
| 342 | *(char *) &test = 0; | 
|---|
| 343 | return test ? BYTE_ORDER_MSBFIRST : BYTE_ORDER_LSBFIRST; | 
|---|
| 344 | } | 
|---|
| 345 |  | 
|---|