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, (intptr_t) 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 }