| File: | jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_gfx_impl.h |
| Warning: | line 236, column 22 Dereference of null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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_VALUE255 + 1) * 2; i++) { | ||||
| 64 | pDither->colorTable[i] = | ||||
| 65 | (((i > MAX_COLOR_VALUE255) ? MAX_COLOR_VALUE255 : i) * | ||||
| 66 | (numColors - 1) / MAX_COLOR_VALUE255) * 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 | INLINEstatic 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)if (numColors[idx[i]]*scale[idx[i]]>numColors[idx[j]]*scale [idx[j]]) { int t = idx[i]; idx[i] = idx[j]; idx[j] = t; } \ | ||||
| 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)if (numColors[idx[0]]*scale[idx[0]]>numColors[idx[1]]*scale [idx[1]]) { int t = idx[0]; idx[0] = idx[1]; idx[1] = t; }; | ||||
| 106 | SORT(1, 2)if (numColors[idx[1]]*scale[idx[1]]>numColors[idx[2]]*scale [idx[2]]) { int t = idx[1]; idx[1] = idx[2]; idx[2] = t; }; | ||||
| 107 | SORT(0, 1)if (numColors[idx[0]]*scale[idx[0]]>numColors[idx[1]]*scale [idx[1]]) { int t = idx[0]; idx[0] = idx[1]; idx[1] = t; }; | ||||
| 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_VALUE255) + | ||||
| 137 | (scaleColor(g, numColors[1], MAX_COLOR_VALUE255) << 8) + | ||||
| 138 | (scaleColor(r, numColors[2], MAX_COLOR_VALUE255) << 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)((pSrc) = (byte_t*)(pSrc)+(incSrc)); | ||||
| 171 | INCPN(byte_t, pDst, incDst)((pDst) = (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_THRESHOLD0x80000000) { // 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)((pSrc) = (byte_t*)(pSrc)+(incSrc)); | ||||
| 182 | INCPN(byte_t, pDst, incDst)((pDst) = (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)(((src2)&0xFF000000)>>24)) | (src & QUAD_ALPHA_MASK0xFF000000), pDst, dstFormat, | ||||
| 192 | row, col++); | ||||
| 193 | INCPN(byte_t, pSrc, incSrc)((pSrc) = (byte_t*)(pSrc)+(incSrc)); | ||||
| 194 | INCPN(byte_t, pDst, incDst)((pDst) = (byte_t*)(pDst)+(incDst)); | ||||
| 195 | INCPN(byte_t, pSrc2, incSrc2)((pSrc2) = (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)((pRect->pBits) = (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((void*)0)); | ||||
| |||||
| 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((void*)0); | ||||
| 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
| ||||
| 258 | pSrcRect2
| ||||
| 259 | INCPN(byte_t, pSrc, pSrcRect->stride)((pSrc) = (byte_t*)(pSrc)+(pSrcRect->stride)); | ||||
| 260 | INCPN(byte_t, pDst, pDstRect->stride)((pDst) = (byte_t*)(pDst)+(pDstRect->stride)); | ||||
| 261 | if (pSrcRect2) { | ||||
| 262 | INCPN(byte_t, pSrc2, pSrcRect2->stride)((pSrc2) = (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)((pDst) = (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((void*)0); | ||||
| 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 ",__printf_chk (2 - 1, "byteorder=%d colormap=%08x depthBytes=%d fixedBits=%08x transparentColor=%u " , format->byteOrder, (unsigned) format->colorMap, format ->depthBytes, (unsigned) format->fixedBits, (unsigned) format ->transparentColor) | ||||
| 317 | format->byteOrder, (unsigned) format->colorMap, format->depthBytes,__printf_chk (2 - 1, "byteorder=%d colormap=%08x depthBytes=%d fixedBits=%08x transparentColor=%u " , format->byteOrder, (unsigned) format->colorMap, format ->depthBytes, (unsigned) format->fixedBits, (unsigned) format ->transparentColor) | ||||
| 318 | (unsigned) format->fixedBits, (unsigned) format->transparentColor)__printf_chk (2 - 1, "byteorder=%d colormap=%08x depthBytes=%d fixedBits=%08x transparentColor=%u " , format->byteOrder, (unsigned) format->colorMap, format ->depthBytes, (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,__printf_chk (2 - 1, "mask[%d]=%08x shift[%d]=%d\n", i, (unsigned ) format->mask[i], i, format->shift[i]) | ||||
| 321 | format->shift[i])__printf_chk (2 - 1, "mask[%d]=%08x shift[%d]=%d\n", i, (unsigned ) format->mask[i], i, format->shift[i]); | ||||
| 322 | } | ||||
| 323 | printf("\n")__printf_chk (2 - 1, "\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 | } |
| 1 | /* | |||
| 2 | * Copyright (c) 2005, 2010, 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 | #ifndef SPLASHSCREEN_GFX_IMPL_H | |||
| 27 | #define SPLASHSCREEN_GFX_IMPL_H | |||
| 28 | ||||
| 29 | #include "splashscreen_gfx.h" | |||
| 30 | ||||
| 31 | /* here come some very simple macros */ | |||
| 32 | ||||
| 33 | /* advance a pointer p by sizeof(type)*n bytes */ | |||
| 34 | #define INCPN(type,p,n)((p) = (type*)(p)+(n)) ((p) = (type*)(p)+(n)) | |||
| 35 | ||||
| 36 | /* advance a pointer by sizeof(type) */ | |||
| 37 | #define INCP(type,p)(((p)) = (type*)((p))+(1)) INCPN(type,(p),1)(((p)) = (type*)((p))+(1)) | |||
| 38 | ||||
| 39 | /* store a typed value to pointed location */ | |||
| 40 | #define PUT(type,p,v)(*(type*)(p) = (type)(v)) (*(type*)(p) = (type)(v)) | |||
| 41 | ||||
| 42 | /* load a typed value from pointed location */ | |||
| 43 | #define GET(type,p)(*(type*)p) (*(type*)p) | |||
| 44 | ||||
| 45 | /* same as cond<0?-1:0 */ | |||
| 46 | enum | |||
| 47 | { | |||
| 48 | IFNEG_SHIFT_BITS = sizeof(int) * 8 - 1 | |||
| 49 | }; | |||
| 50 | ||||
| 51 | #define IFNEG(cond)((int)(cond)>>IFNEG_SHIFT_BITS) ((int)(cond)>>IFNEG_SHIFT_BITS) | |||
| 52 | ||||
| 53 | /* same as cond<0?n1:n2 */ | |||
| 54 | #define IFNEGPOS(cond,n1,n2)((((int)(cond)>>IFNEG_SHIFT_BITS)&(n1))|((~((int)(cond )>>IFNEG_SHIFT_BITS))&(n2))) ((IFNEG(cond)((int)(cond)>>IFNEG_SHIFT_BITS)&(n1))|((~IFNEG(cond)((int)(cond)>>IFNEG_SHIFT_BITS))&(n2))) | |||
| 55 | ||||
| 56 | /* value shifted left by n bits, negative n is allowed */ | |||
| 57 | #define LSHIFT(value,n)((((int)((n))>>IFNEG_SHIFT_BITS)&((value)>>-( n)))|((~((int)((n))>>IFNEG_SHIFT_BITS))&((value)<< (n)))) IFNEGPOS((n),(value)>>-(n),(value)<<(n))((((int)((n))>>IFNEG_SHIFT_BITS)&((value)>>-( n)))|((~((int)((n))>>IFNEG_SHIFT_BITS))&((value)<< (n)))) | |||
| 58 | ||||
| 59 | /* value shifted right by n bits, negative n is allowed */ | |||
| 60 | #define RSHIFT(value,n)((((int)(n)>>IFNEG_SHIFT_BITS)&((value)<<-(n) ))|((~((int)(n)>>IFNEG_SHIFT_BITS))&((value)>> (n)))) IFNEGPOS(n,(value)<<-(n),(value)>>(n))((((int)(n)>>IFNEG_SHIFT_BITS)&((value)<<-(n) ))|((~((int)(n)>>IFNEG_SHIFT_BITS))&((value)>> (n)))) | |||
| 61 | ||||
| 62 | /* converts a single i'th component to the specific format defined by format->shift[i] and format->mask[i] */ | |||
| 63 | #define CONVCOMP(quad,format,i)(((((int)(((format)->shift[i]))>>IFNEG_SHIFT_BITS)& (((quad))>>-((format)->shift[i])))|((~((int)(((format )->shift[i]))>>IFNEG_SHIFT_BITS))&(((quad))<< ((format)->shift[i]))))&(format)->mask[i]) \ | |||
| 64 | (LSHIFT((quad),(format)->shift[i])((((int)(((format)->shift[i]))>>IFNEG_SHIFT_BITS)& (((quad))>>-((format)->shift[i])))|((~((int)(((format )->shift[i]))>>IFNEG_SHIFT_BITS))&(((quad))<< ((format)->shift[i]))))&(format)->mask[i]) | |||
| 65 | ||||
| 66 | /* extracts the component defined by format->shift[i] and format->mask[i] from a specific-format value */ | |||
| 67 | #define UNCONVCOMP(value,format,i)(((((int)((format)->shift[i])>>IFNEG_SHIFT_BITS)& (((value)&(format)->mask[i])<<-((format)->shift [i])))|((~((int)((format)->shift[i])>>IFNEG_SHIFT_BITS ))&(((value)&(format)->mask[i])>>((format)-> shift[i]))))) \ | |||
| 68 | (RSHIFT((value)&(format)->mask[i],(format)->shift[i])((((int)((format)->shift[i])>>IFNEG_SHIFT_BITS)& (((value)&(format)->mask[i])<<-((format)->shift [i])))|((~((int)((format)->shift[i])>>IFNEG_SHIFT_BITS ))&(((value)&(format)->mask[i])>>((format)-> shift[i]))))) | |||
| 69 | ||||
| 70 | /* dithers the color using the dither matrices and colormap from format | |||
| 71 | indices to dither matrices are passed as arguments */ | |||
| 72 | INLINEstatic unsigned | |||
| 73 | ditherColor(rgbquad_t value, ImageFormat * format, int row, int col) | |||
| 74 | { | |||
| 75 | int blue = QUAD_BLUE(value)(((value)&0x000000FF)>>0); | |||
| 76 | int green = QUAD_GREEN(value)(((value)&0x0000FF00)>>8); | |||
| 77 | int red = QUAD_RED(value)(((value)&0x00FF0000)>>16); | |||
| 78 | ||||
| 79 | blue = format->dithers[0].colorTable[blue + | |||
| 80 | format->dithers[0].matrix[col & DITHER_MASK][row & DITHER_MASK]]; | |||
| 81 | green = format->dithers[1].colorTable[green + | |||
| 82 | format->dithers[1].matrix[col & DITHER_MASK][row & DITHER_MASK]]; | |||
| 83 | red = format->dithers[2].colorTable[red + | |||
| 84 | format->dithers[2].matrix[col & DITHER_MASK][row & DITHER_MASK]]; | |||
| 85 | return red + green + blue; | |||
| 86 | } | |||
| 87 | ||||
| 88 | /* blend (lerp between) two rgb quads | |||
| 89 | src and dst alpha is ignored | |||
| 90 | the algorithm: src*alpha+dst*(1-alpha)=(src-dst)*alpha+dst, rb and g are done separately | |||
| 91 | */ | |||
| 92 | INLINEstatic rgbquad_t | |||
| 93 | blendRGB(rgbquad_t dst, rgbquad_t src, rgbquad_t alpha) | |||
| 94 | { | |||
| 95 | const rgbquad_t a = alpha; | |||
| 96 | const rgbquad_t a1 = 0xFF - alpha; | |||
| 97 | ||||
| 98 | return MAKE_QUAD((((0)<<24)&0xFF000000)| ((((rgbquad_t)(((((src)& 0x00FF0000)>>16) * a + (((dst)&0x00FF0000)>>16 ) * a1) / 0xFF))<<16)&0x00FF0000)| ((((rgbquad_t)(( (((src)&0x0000FF00)>>8) * a + (((dst)&0x0000FF00 )>>8) * a1) / 0xFF))<<8)&0x0000FF00)| ((((rgbquad_t )(((((src)&0x000000FF)>>0) * a + (((dst)&0x000000FF )>>0) * a1) / 0xFF))<<0)&0x000000FF) | |||
| 99 | (rgbquad_t)((QUAD_RED(src) * a + QUAD_RED(dst) * a1) / 0xFF),(((0)<<24)&0xFF000000)| ((((rgbquad_t)(((((src)& 0x00FF0000)>>16) * a + (((dst)&0x00FF0000)>>16 ) * a1) / 0xFF))<<16)&0x00FF0000)| ((((rgbquad_t)(( (((src)&0x0000FF00)>>8) * a + (((dst)&0x0000FF00 )>>8) * a1) / 0xFF))<<8)&0x0000FF00)| ((((rgbquad_t )(((((src)&0x000000FF)>>0) * a + (((dst)&0x000000FF )>>0) * a1) / 0xFF))<<0)&0x000000FF) | |||
| 100 | (rgbquad_t)((QUAD_GREEN(src) * a + QUAD_GREEN(dst) * a1) / 0xFF),(((0)<<24)&0xFF000000)| ((((rgbquad_t)(((((src)& 0x00FF0000)>>16) * a + (((dst)&0x00FF0000)>>16 ) * a1) / 0xFF))<<16)&0x00FF0000)| ((((rgbquad_t)(( (((src)&0x0000FF00)>>8) * a + (((dst)&0x0000FF00 )>>8) * a1) / 0xFF))<<8)&0x0000FF00)| ((((rgbquad_t )(((((src)&0x000000FF)>>0) * a + (((dst)&0x000000FF )>>0) * a1) / 0xFF))<<0)&0x000000FF) | |||
| 101 | (rgbquad_t)((QUAD_BLUE(src) * a + QUAD_BLUE(dst) * a1) / 0xFF),(((0)<<24)&0xFF000000)| ((((rgbquad_t)(((((src)& 0x00FF0000)>>16) * a + (((dst)&0x00FF0000)>>16 ) * a1) / 0xFF))<<16)&0x00FF0000)| ((((rgbquad_t)(( (((src)&0x0000FF00)>>8) * a + (((dst)&0x0000FF00 )>>8) * a1) / 0xFF))<<8)&0x0000FF00)| ((((rgbquad_t )(((((src)&0x000000FF)>>0) * a + (((dst)&0x000000FF )>>0) * a1) / 0xFF))<<0)&0x000000FF) | |||
| 102 | 0)(((0)<<24)&0xFF000000)| ((((rgbquad_t)(((((src)& 0x00FF0000)>>16) * a + (((dst)&0x00FF0000)>>16 ) * a1) / 0xFF))<<16)&0x00FF0000)| ((((rgbquad_t)(( (((src)&0x0000FF00)>>8) * a + (((dst)&0x0000FF00 )>>8) * a1) / 0xFF))<<8)&0x0000FF00)| ((((rgbquad_t )(((((src)&0x000000FF)>>0) * a + (((dst)&0x000000FF )>>0) * a1) / 0xFF))<<0)&0x000000FF); | |||
| 103 | } | |||
| 104 | ||||
| 105 | /* scales rgb quad by alpha. basically similar to what's above. src alpha is retained. | |||
| 106 | used for premultiplying alpha | |||
| 107 | ||||
| 108 | btw: braindead MSVC6 generates _three_ mul instructions for this function */ | |||
| 109 | ||||
| 110 | INLINEstatic rgbquad_t | |||
| 111 | premultiplyRGBA(rgbquad_t src) | |||
| 112 | { | |||
| 113 | rgbquad_t srb = src & 0xFF00FF; | |||
| 114 | rgbquad_t sg = src & 0xFF00; | |||
| 115 | rgbquad_t alpha = src >> QUAD_ALPHA_SHIFT24; | |||
| 116 | ||||
| 117 | alpha += 1; | |||
| 118 | ||||
| 119 | srb *= alpha; | |||
| 120 | sg *= alpha; | |||
| 121 | srb >>= 8; | |||
| 122 | sg >>= 8; | |||
| 123 | ||||
| 124 | return (src & 0xFF000000) | (srb & 0xFF00FF) | (sg & 0xFF00); | |||
| 125 | } | |||
| 126 | ||||
| 127 | /* The functions below are inherently ineffective, but the performance seems to be | |||
| 128 | more or less adequate for the case of splash screens. They can be optimized later | |||
| 129 | if needed. The idea of optimization is to provide inlineable form of putRGBADither and | |||
| 130 | getRGBA at least for certain most frequently used visuals. Something like this is | |||
| 131 | done in Java 2D ("loops"). This would be possible with C++ templates, but making it | |||
| 132 | clean for C would require ugly preprocessor tricks. Leaving it out for later. | |||
| 133 | */ | |||
| 134 | ||||
| 135 | /* convert a single pixel color value from rgbquad according to visual format | |||
| 136 | and place it to pointed location | |||
| 137 | ordered dithering used when necessary */ | |||
| 138 | INLINEstatic void | |||
| 139 | putRGBADither(rgbquad_t value, void *ptr, ImageFormat * format, | |||
| 140 | int row, int col) | |||
| 141 | { | |||
| 142 | if (format->premultiplied) { | |||
| 143 | value = premultiplyRGBA(value); | |||
| 144 | } | |||
| 145 | if (format->dithers) { | |||
| 146 | value = format->colorIndex[ditherColor(value, format, row, col)]; | |||
| 147 | } | |||
| 148 | else { | |||
| 149 | value = CONVCOMP(value, format, 0)(((((int)(((format)->shift[0]))>>IFNEG_SHIFT_BITS)& (((value))>>-((format)->shift[0])))|((~((int)(((format )->shift[0]))>>IFNEG_SHIFT_BITS))&(((value))<< ((format)->shift[0]))))&(format)->mask[0]) | CONVCOMP(value, format, 1)(((((int)(((format)->shift[1]))>>IFNEG_SHIFT_BITS)& (((value))>>-((format)->shift[1])))|((~((int)(((format )->shift[1]))>>IFNEG_SHIFT_BITS))&(((value))<< ((format)->shift[1]))))&(format)->mask[1]) | | |||
| 150 | CONVCOMP(value, format, 2)(((((int)(((format)->shift[2]))>>IFNEG_SHIFT_BITS)& (((value))>>-((format)->shift[2])))|((~((int)(((format )->shift[2]))>>IFNEG_SHIFT_BITS))&(((value))<< ((format)->shift[2]))))&(format)->mask[2]) | CONVCOMP(value, format, 3)(((((int)(((format)->shift[3]))>>IFNEG_SHIFT_BITS)& (((value))>>-((format)->shift[3])))|((~((int)(((format )->shift[3]))>>IFNEG_SHIFT_BITS))&(((value))<< ((format)->shift[3]))))&(format)->mask[3]); | |||
| 151 | } | |||
| 152 | switch (format->byteOrder) { | |||
| 153 | case BYTE_ORDER_LSBFIRST: | |||
| 154 | switch (format->depthBytes) { /* lack of *break*'s is intentional */ | |||
| 155 | case 4: | |||
| 156 | PUT(byte_t, ptr, value & 0xff)(*(byte_t*)(ptr) = (byte_t)(value & 0xff)); | |||
| 157 | value >>= 8; | |||
| 158 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 159 | case 3: | |||
| 160 | PUT(byte_t, ptr, value & 0xff)(*(byte_t*)(ptr) = (byte_t)(value & 0xff)); | |||
| 161 | value >>= 8; | |||
| 162 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 163 | case 2: | |||
| 164 | PUT(byte_t, ptr, value & 0xff)(*(byte_t*)(ptr) = (byte_t)(value & 0xff)); | |||
| 165 | value >>= 8; | |||
| 166 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 167 | case 1: | |||
| 168 | PUT(byte_t, ptr, value & 0xff)(*(byte_t*)(ptr) = (byte_t)(value & 0xff)); | |||
| 169 | } | |||
| 170 | break; | |||
| 171 | case BYTE_ORDER_MSBFIRST: | |||
| 172 | switch (format->depthBytes) { /* lack of *break*'s is intentional */ | |||
| 173 | case 4: | |||
| 174 | PUT(byte_t, ptr, (value >> 24) & 0xff)(*(byte_t*)(ptr) = (byte_t)((value >> 24) & 0xff)); | |||
| 175 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 176 | case 3: | |||
| 177 | PUT(byte_t, ptr, (value >> 16) & 0xff)(*(byte_t*)(ptr) = (byte_t)((value >> 16) & 0xff)); | |||
| 178 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 179 | case 2: | |||
| 180 | PUT(byte_t, ptr, (value >> 8) & 0xff)(*(byte_t*)(ptr) = (byte_t)((value >> 8) & 0xff)); | |||
| 181 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 182 | case 1: | |||
| 183 | PUT(byte_t, ptr, value & 0xff)(*(byte_t*)(ptr) = (byte_t)(value & 0xff)); | |||
| 184 | } | |||
| 185 | break; | |||
| 186 | case BYTE_ORDER_NATIVE: | |||
| 187 | switch (format->depthBytes) { | |||
| 188 | case 4: | |||
| 189 | PUT(rgbquad_t, ptr, value)(*(rgbquad_t*)(ptr) = (rgbquad_t)(value)); | |||
| 190 | break; | |||
| 191 | case 3: /* not supported, LSB or MSB should always be specified */ | |||
| 192 | PUT(byte_t, ptr, 0xff)(*(byte_t*)(ptr) = (byte_t)(0xff)); /* Put a stub value */ | |||
| 193 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 194 | PUT(byte_t, ptr, 0xff)(*(byte_t*)(ptr) = (byte_t)(0xff)); | |||
| 195 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 196 | PUT(byte_t, ptr, 0xff)(*(byte_t*)(ptr) = (byte_t)(0xff)); | |||
| 197 | break; | |||
| 198 | case 2: | |||
| 199 | PUT(word_t, ptr, value)(*(word_t*)(ptr) = (word_t)(value)); | |||
| 200 | break; | |||
| 201 | case 1: | |||
| 202 | PUT(byte_t, ptr, value)(*(byte_t*)(ptr) = (byte_t)(value)); | |||
| 203 | break; | |||
| 204 | } | |||
| 205 | } | |||
| 206 | } | |||
| 207 | ||||
| 208 | /* load a single pixel color value and un-convert it to rgbquad according to visual format */ | |||
| 209 | INLINEstatic rgbquad_t | |||
| 210 | getRGBA(void *ptr, ImageFormat * format) | |||
| 211 | { | |||
| 212 | /* | |||
| 213 | FIXME: color is not un-alpha-premultiplied on get | |||
| 214 | this is not required by current code, but it makes the implementation inconsistent | |||
| 215 | i.e. put(get) will not work right for alpha-premultiplied images */ | |||
| 216 | ||||
| 217 | /* get the value basing on depth and byte order */ | |||
| 218 | rgbquad_t value = 0; | |||
| 219 | ||||
| 220 | switch (format->byteOrder) { | |||
| 221 | case BYTE_ORDER_LSBFIRST: | |||
| 222 | switch (format->depthBytes) { | |||
| 223 | case 4: | |||
| 224 | value |= GET(byte_t, ptr)(*(byte_t*)ptr); | |||
| 225 | value <<= 8; | |||
| 226 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 227 | case 3: | |||
| 228 | value |= GET(byte_t, ptr)(*(byte_t*)ptr); | |||
| 229 | value <<= 8; | |||
| 230 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 231 | case 2: | |||
| 232 | value |= GET(byte_t, ptr)(*(byte_t*)ptr); | |||
| 233 | value <<= 8; | |||
| 234 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 235 | case 1: | |||
| 236 | value |= GET(byte_t, ptr)(*(byte_t*)ptr); | |||
| ||||
| 237 | } | |||
| 238 | break; | |||
| 239 | case BYTE_ORDER_MSBFIRST: | |||
| 240 | switch (format->depthBytes) { /* lack of *break*'s is intentional */ | |||
| 241 | case 4: | |||
| 242 | value |= (GET(byte_t, ptr)(*(byte_t*)ptr) << 24); | |||
| 243 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 244 | case 3: | |||
| 245 | value |= (GET(byte_t, ptr)(*(byte_t*)ptr) << 16); | |||
| 246 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 247 | case 2: | |||
| 248 | value |= (GET(byte_t, ptr)(*(byte_t*)ptr) << 8); | |||
| 249 | INCP(byte_t, ptr)(((ptr)) = (byte_t*)((ptr))+(1)); | |||
| 250 | case 1: | |||
| 251 | value |= GET(byte_t, ptr)(*(byte_t*)ptr); | |||
| 252 | } | |||
| 253 | break; | |||
| 254 | case BYTE_ORDER_NATIVE: | |||
| 255 | switch (format->depthBytes) { | |||
| 256 | case 4: | |||
| 257 | value = GET(rgbquad_t, ptr)(*(rgbquad_t*)ptr); | |||
| 258 | break; | |||
| 259 | case 3: /* not supported, LSB or MSB should always be specified */ | |||
| 260 | value = 0xFFFFFFFF; /*return a stub value */ | |||
| 261 | break; | |||
| 262 | case 2: | |||
| 263 | value = (rgbquad_t) GET(word_t, ptr)(*(word_t*)ptr); | |||
| 264 | break; | |||
| 265 | case 1: | |||
| 266 | value = (rgbquad_t) GET(byte_t, ptr)(*(byte_t*)ptr); | |||
| 267 | break; | |||
| 268 | } | |||
| 269 | break; | |||
| 270 | } | |||
| 271 | /* now un-convert the value */ | |||
| 272 | if (format->colorMap) { | |||
| 273 | if (value == format->transparentColor) | |||
| 274 | return 0; | |||
| 275 | else | |||
| 276 | return format->colorMap[value]; | |||
| 277 | } | |||
| 278 | else { | |||
| 279 | return UNCONVCOMP(value, format, 0)(((((int)((format)->shift[0])>>IFNEG_SHIFT_BITS)& (((value)&(format)->mask[0])<<-((format)->shift [0])))|((~((int)((format)->shift[0])>>IFNEG_SHIFT_BITS ))&(((value)&(format)->mask[0])>>((format)-> shift[0]))))) | UNCONVCOMP(value, format, 1)(((((int)((format)->shift[1])>>IFNEG_SHIFT_BITS)& (((value)&(format)->mask[1])<<-((format)->shift [1])))|((~((int)((format)->shift[1])>>IFNEG_SHIFT_BITS ))&(((value)&(format)->mask[1])>>((format)-> shift[1]))))) | | |||
| 280 | UNCONVCOMP(value, format, 2)(((((int)((format)->shift[2])>>IFNEG_SHIFT_BITS)& (((value)&(format)->mask[2])<<-((format)->shift [2])))|((~((int)((format)->shift[2])>>IFNEG_SHIFT_BITS ))&(((value)&(format)->mask[2])>>((format)-> shift[2]))))) | UNCONVCOMP(value, format, 3)(((((int)((format)->shift[3])>>IFNEG_SHIFT_BITS)& (((value)&(format)->mask[3])<<-((format)->shift [3])))|((~((int)((format)->shift[3])>>IFNEG_SHIFT_BITS ))&(((value)&(format)->mask[3])>>((format)-> shift[3]))))) | | |||
| 281 | format->fixedBits; | |||
| 282 | } | |||
| 283 | } | |||
| 284 | ||||
| 285 | /* fill the line with the specified color according to visual format */ | |||
| 286 | INLINEstatic void | |||
| 287 | fillLine(rgbquad_t color, void *pDst, int incDst, int n, | |||
| 288 | ImageFormat * dstFormat, int row, int col) | |||
| 289 | { | |||
| 290 | int i; | |||
| 291 | ||||
| 292 | for (i = 0; i < n; ++i) { | |||
| 293 | putRGBADither(color, pDst, dstFormat, row, col++); | |||
| 294 | INCPN(byte_t, pDst, incDst)((pDst) = (byte_t*)(pDst)+(incDst)); | |||
| 295 | } | |||
| 296 | } | |||
| 297 | ||||
| 298 | /* find the shift for specified mask, also verify the mask is valid */ | |||
| 299 | INLINEstatic int | |||
| 300 | getMaskShift(rgbquad_t mask, int *pShift, int *pnumBits) | |||
| 301 | { | |||
| 302 | int shift = 0, numBits = 0; | |||
| 303 | ||||
| 304 | /* check the mask is not empty */ | |||
| 305 | if (!mask) | |||
| 306 | return 0; | |||
| 307 | /* calculate the shift */ | |||
| 308 | while ((mask & 1) == 0) { | |||
| 309 | ++shift; | |||
| 310 | mask >>= 1; | |||
| 311 | } | |||
| 312 | /* check the mask is contigious */ | |||
| 313 | if ((mask & (mask + 1)) != 0) | |||
| 314 | return 0; | |||
| 315 | /* calculate the number of bits */ | |||
| 316 | do { | |||
| 317 | ++numBits; | |||
| 318 | mask >>= 1; | |||
| 319 | } while ((mask & 1) != 0); | |||
| 320 | *pShift = shift; | |||
| 321 | *pnumBits = numBits; | |||
| 322 | return 1; | |||
| 323 | } | |||
| 324 | ||||
| 325 | #endif |