1 /* 2 * Copyright (c) 2005, 2006, 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_impl.h" 27 #include "splashscreen_gfx_impl.h" 28 29 int splashIsVisible = 0; 30 31 Splash * 32 SplashGetInstance() 33 { 34 static Splash splash; 35 static int preInitialized = 0; 36 if (!preInitialized) { 37 memset(&splash, 0, sizeof(Splash)); 38 splash.currentFrame = -1; 39 preInitialized = 1; 40 } 41 return &splash; 42 } 43 44 SPLASHEXPORT void 45 SplashSetFileJarName(const char* fileName, const char* jarName) { 46 Splash *splash = SplashGetInstance(); 47 48 free(splash->fileName); 49 splash->fileName = SplashConvertStringAlloc(fileName, &splash->fileNameLen); 50 51 free(splash->jarName); 52 splash->jarName = SplashConvertStringAlloc(jarName, &splash->jarNameLen); 53 } 54 55 SPLASHEXPORT void 56 SplashInit() 57 { 58 Splash *splash = SplashGetInstance(); 59 60 memset(splash, 0, sizeof(Splash)); 61 splash->currentFrame = -1; 62 splash->scaleFactor = 1; 63 initFormat(&splash->imageFormat, QUAD_RED_MASK, QUAD_GREEN_MASK, 64 QUAD_BLUE_MASK, QUAD_ALPHA_MASK); 65 SplashInitPlatform(splash); 66 } 67 68 SPLASHEXPORT void 69 SplashClose() 70 { 71 Splash *splash = SplashGetInstance(); 72 73 if (splash->isVisible > 0) { 74 SplashLock(splash); 75 splash->isVisible = -1; 76 SplashClosePlatform(splash); 77 SplashUnlock(splash); 78 } 79 } 80 81 void 82 SplashCleanup(Splash * splash) 83 { 84 int i; 85 86 splash->currentFrame = -1; 87 SplashCleanupPlatform(splash); 88 if (splash->frames) { 89 for (i = 0; i < splash->frameCount; i++) { 90 if (splash->frames[i].bitmapBits) { 91 free(splash->frames[i].bitmapBits); 92 splash->frames[i].bitmapBits = NULL; 93 } 94 } 95 free(splash->frames); 96 splash->frames = NULL; 97 } 98 if (splash->overlayData) { 99 free(splash->overlayData); 100 splash->overlayData = NULL; 101 } 102 SplashSetFileJarName(NULL, NULL); 103 } 104 105 SPLASHEXPORT void 106 SplashSetScaleFactor(float scaleFactor) 107 { 108 Splash *splash = SplashGetInstance(); 109 splash->scaleFactor = scaleFactor; 110 } 111 112 void 113 SplashDone(Splash * splash) 114 { 115 SplashCleanup(splash); 116 SplashDonePlatform(splash); 117 } 118 119 int 120 SplashIsStillLooping(Splash * splash) 121 { 122 if (splash->currentFrame < 0) { 123 return 0; 124 } 125 return splash->loopCount != 1 || 126 splash->currentFrame + 1 < splash->frameCount; 127 } 128 129 void 130 SplashUpdateScreenData(Splash * splash) 131 { 132 ImageRect srcRect, dstRect; 133 if (splash->currentFrame < 0) { 134 return; 135 } 136 137 initRect(&srcRect, 0, 0, splash->width, splash->height, 1, 138 splash->width * sizeof(rgbquad_t), 139 splash->frames[splash->currentFrame].bitmapBits, &splash->imageFormat); 140 if (splash->screenData) { 141 free(splash->screenData); 142 } 143 splash->screenStride = splash->width * splash->screenFormat.depthBytes; 144 if (splash->byteAlignment > 1) { 145 splash->screenStride = 146 (splash->screenStride + splash->byteAlignment - 1) & 147 ~(splash->byteAlignment - 1); 148 } 149 splash->screenData = malloc(splash->height * splash->screenStride); 150 initRect(&dstRect, 0, 0, splash->width, splash->height, 1, 151 splash->screenStride, splash->screenData, &splash->screenFormat); 152 if (splash->overlayData) { 153 convertRect2(&srcRect, &dstRect, CVT_BLEND, &splash->overlayRect); 154 } 155 else { 156 convertRect(&srcRect, &dstRect, CVT_COPY); 157 } 158 } 159 160 void 161 SplashNextFrame(Splash * splash) 162 { 163 if (splash->currentFrame < 0) { 164 return; 165 } 166 do { 167 if (!SplashIsStillLooping(splash)) { 168 return; 169 } 170 splash->time += splash->frames[splash->currentFrame].delay; 171 if (++splash->currentFrame >= splash->frameCount) { 172 splash->currentFrame = 0; 173 if (splash->loopCount > 0) { 174 splash->loopCount--; 175 } 176 } 177 } while (splash->time + splash->frames[splash->currentFrame].delay - 178 SplashTime() <= 0); 179 } 180 181 int 182 BitmapToYXBandedRectangles(ImageRect * pSrcRect, RECT_T * out) 183 { 184 RECT_T *pPrevLine = NULL, *pFirst = out, *pThis = pFirst; 185 int i, j, i0; 186 int length; 187 188 for (j = 0; j < pSrcRect->numLines; j++) { 189 190 /* generate data for a scanline */ 191 192 byte_t *pSrc = (byte_t *) pSrcRect->pBits + j * pSrcRect->stride; 193 RECT_T *pLine = pThis; 194 195 i = 0; 196 197 do { 198 while (i < pSrcRect->numSamples && 199 getRGBA(pSrc, pSrcRect->format) < ALPHA_THRESHOLD) { 200 pSrc += pSrcRect->depthBytes; 201 ++i; 202 } 203 if (i >= pSrcRect->numSamples) { 204 break; 205 } 206 i0 = i; 207 while (i < pSrcRect->numSamples && 208 getRGBA(pSrc, pSrcRect->format) >= ALPHA_THRESHOLD) { 209 pSrc += pSrcRect->depthBytes; 210 ++i; 211 } 212 RECT_SET(*pThis, i0, j, i - i0, 1); 213 ++pThis; 214 } while (i < pSrcRect->numSamples); 215 216 /* check if the previous scanline is exactly the same, merge if so 217 (this is the only optimization we can use for YXBanded rectangles, and win32 supports 218 YXBanded only */ 219 220 length = pThis - pLine; 221 if (pPrevLine && pLine - pPrevLine == length) { 222 for (i = 0; i < length && RECT_EQ_X(pPrevLine[i], pLine[i]); ++i) { 223 } 224 if (i == pLine - pPrevLine) { 225 // do merge 226 for (i = 0; i < length; i++) { 227 RECT_INC_HEIGHT(pPrevLine[i]); 228 } 229 pThis = pLine; 230 continue; 231 } 232 } 233 /* or else use the generated scanline */ 234 235 pPrevLine = pLine; 236 } 237 return pThis - pFirst; 238 } 239 240 typedef struct FILEFORMAT 241 { 242 int sign; 243 int (*decodeStream) (Splash * splash, SplashStream * stream); 244 } FILEFORMAT; 245 246 static const FILEFORMAT formats[] = { 247 {0x47, SplashDecodeGifStream}, 248 {0x89, SplashDecodePngStream}, 249 {0xFF, SplashDecodeJpegStream} 250 }; 251 252 static int 253 SplashLoadStream(SplashStream * stream) 254 { 255 int success = 0; 256 int c; 257 size_t i; 258 259 Splash *splash = SplashGetInstance(); 260 if (splash->isVisible < 0) { 261 return 0; 262 } 263 264 SplashLock(splash); 265 266 /* the formats we support can be easily distinguished by the first byte */ 267 c = stream->peek(stream); 268 if (c != -1) { 269 for (i = 0; i < sizeof(formats) / sizeof(FILEFORMAT); i++) { 270 if (c == formats[i].sign) { 271 success = formats[i].decodeStream(splash, stream); 272 break; 273 } 274 } 275 } 276 stream->close(stream); 277 278 if (!success) { // failed to decode 279 if (splash->isVisible == 0) { 280 SplashCleanup(splash); 281 } 282 SplashUnlock(splash); // SplashClose locks 283 if (splash->isVisible == 0) { 284 SplashClose(); 285 } 286 } 287 else { 288 splash->currentFrame = 0; 289 if (splash->isVisible == 0) { 290 SplashStart(splash); 291 } else { 292 SplashReconfigure(splash); 293 splash->time = SplashTime(); 294 } 295 SplashUnlock(splash); 296 } 297 return success; 298 } 299 300 SPLASHEXPORT int 301 SplashLoadFile(const char *filename) 302 { 303 SplashStream stream; 304 return SplashStreamInitFile(&stream, filename) && 305 SplashLoadStream(&stream); 306 } 307 308 SPLASHEXPORT int 309 SplashLoadMemory(void *data, int size) 310 { 311 SplashStream stream; 312 return SplashStreamInitMemory(&stream, data, size) && 313 SplashLoadStream(&stream); 314 } 315 316 /* SplashStart MUST be called from under the lock */ 317 318 void 319 SplashStart(Splash * splash) 320 { 321 if (splash->isVisible == 0) { 322 SplashCreateThread(splash); 323 splash->isVisible = 1; 324 } 325 } 326 327 /* SplashStream functions */ 328 329 static int readFile(void* pStream, void* pData, int nBytes) { 330 FILE* f = ((SplashStream*)pStream)->arg.stdio.f; 331 return fread(pData, 1, nBytes, f); 332 } 333 static int peekFile(void* pStream) { 334 FILE* f = ((SplashStream*)pStream)->arg.stdio.f; 335 int c = fgetc(f); 336 if (c != EOF) { 337 ungetc(c, f); 338 return c; 339 } else { 340 return -1; 341 } 342 } 343 344 static void closeFile(void* pStream) { 345 FILE* f = ((SplashStream*)pStream)->arg.stdio.f; 346 fclose(f); 347 } 348 349 static int readMem(void* pStream, void* pData, int nBytes) { 350 unsigned char* pSrc = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pData); 351 unsigned char* pSrcEnd = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pDataEnd); 352 if (nBytes > pSrcEnd - pSrc) { 353 nBytes = pSrcEnd - pSrc; 354 } 355 if (nBytes>0) { 356 memcpy(pData, pSrc, nBytes); 357 pSrc += nBytes; 358 ((SplashStream*)pStream)->arg.mem.pData = (void*)pSrc; 359 } 360 return nBytes; 361 } 362 363 static int peekMem(void* pStream) { 364 unsigned char* pSrc = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pData); 365 unsigned char* pSrcEnd = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pDataEnd); 366 if (pSrc >= pSrcEnd) { 367 return -1; 368 } else { 369 return (int)*pSrc; 370 } 371 } 372 373 static void closeMem(void* pStream) { 374 } 375 376 int SplashStreamInitFile(SplashStream * pStream, const char* filename) { 377 pStream->arg.stdio.f = fopen(filename, "rb"); 378 pStream->read = readFile; 379 pStream->peek = peekFile; 380 pStream->close = closeFile; 381 return pStream->arg.stdio.f != 0; 382 } 383 384 int SplashStreamInitMemory(SplashStream * pStream, void* pData, int size) { 385 pStream->arg.mem.pData = (unsigned char*)pData; 386 pStream->arg.mem.pDataEnd = (unsigned char*)pData + size; 387 pStream->read = readMem; 388 pStream->peek = peekMem; 389 pStream->close = closeMem; 390 return 1; 391 } 392 393 SPLASHEXPORT int 394 SplashGetScaledImgNameMaxPstfixLen(const char *fileName){ 395 return strlen(fileName) + strlen(".java-scale-200") + 1; 396 }