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
initDither(DitherSettings * pDither,int numColors,int scale)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
scaleColor(int color,int numColorsIn,int numColorsOut)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
quantizeColors(int maxNumColors,int * numColors)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
initColorCube(int * numColors,rgbquad_t * pColorMap,DitherSettings * pDithers,rgbquad_t * colorIndex)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
convertLine(void * pSrc,int incSrc,void * pDst,int incDst,int numSamples,ImageFormat * srcFormat,ImageFormat * dstFormat,int doAlpha,void * pSrc2,int incSrc2,ImageFormat * srcFormat2,int row,int col)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
initRect(ImageRect * pRect,int x,int y,int width,int height,int jump,int stride,void * pBits,ImageFormat * format)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
convertRect(ImageRect * pSrcRect,ImageRect * pDstRect,int mode)223 convertRect(ImageRect * pSrcRect, ImageRect * pDstRect, int mode)
224 {
225     return convertRect2(pSrcRect, pDstRect, mode, NULL);
226 }
227 
228 int
convertRect2(ImageRect * pSrcRect,ImageRect * pDstRect,int mode,ImageRect * pSrcRect2)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
fillRect(rgbquad_t color,ImageRect * pDstRect)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
initFormat(ImageFormat * format,int redMask,int greenMask,int blueMask,int alphaMask)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
dumpFormat(ImageFormat * format)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
optimizeFormat(ImageFormat * format)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
platformByteOrder()338 platformByteOrder()
339 {
340     int test = 1;
341 
342     *(char *) &test = 0;
343     return test ? BYTE_ORDER_MSBFIRST : BYTE_ORDER_LSBFIRST;
344 }
345