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 #define BUFF_SIZE 1024 29 #ifdef _MSC_VER 30 # ifndef snprintf 31 # define snprintf _snprintf 32 # endif 33 #endif 34 int splashIsVisible = 0; 35 36 Splash * 37 SplashGetInstance() 38 { 39 static Splash splash; 40 static int preInitialized = 0; 41 if (!preInitialized) { 42 memset(&splash, 0, sizeof(Splash)); 43 splash.currentFrame = -1; 44 preInitialized = 1; 45 } 46 return &splash; 47 } 48 49 SPLASHEXPORT void 50 SplashSetFileJarName(const char* fileName, const char* jarName) { 51 Splash *splash = SplashGetInstance(); 52 53 free(splash->fileName); 54 splash->fileName = SplashConvertStringAlloc(fileName, &splash->fileNameLen); 55 56 free(splash->jarName); 57 splash->jarName = SplashConvertStringAlloc(jarName, &splash->jarNameLen); 58 } 59 60 SPLASHEXPORT void 61 SplashInit() 62 { 63 Splash *splash = SplashGetInstance(); 64 65 memset(splash, 0, sizeof(Splash)); 66 splash->currentFrame = -1; 67 splash->scaleFactor = 1; 68 initFormat(&splash->imageFormat, QUAD_RED_MASK, QUAD_GREEN_MASK, 69 QUAD_BLUE_MASK, QUAD_ALPHA_MASK); 70 SplashInitPlatform(splash); 71 } 72 73 SPLASHEXPORT void 74 SplashClose() 75 { 76 Splash *splash = SplashGetInstance(); 77 78 if (splash->isVisible > 0) { 79 SplashLock(splash); 80 splash->isVisible = -1; 81 SplashClosePlatform(splash); 82 SplashUnlock(splash); 83 } 84 } 85 86 void 87 SplashCleanup(Splash * splash) 88 { 89 int i; 90 91 splash->currentFrame = -1; 92 SplashCleanupPlatform(splash); 93 if (splash->frames) { 94 for (i = 0; i < splash->frameCount; i++) { 95 if (splash->frames[i].bitmapBits) { 96 free(splash->frames[i].bitmapBits); 97 splash->frames[i].bitmapBits = NULL; 98 } 99 } 100 free(splash->frames); 101 splash->frames = NULL; 102 } 103 if (splash->overlayData) { 104 free(splash->overlayData); 105 splash->overlayData = NULL; 106 } 107 SplashSetFileJarName(NULL, NULL); 108 } 109 110 SPLASHEXPORT void 111 SplashSetScaleFactor(float scaleFactor) 112 { 113 Splash *splash = SplashGetInstance(); 114 splash->scaleFactor = scaleFactor; 115 } 116 117 void 118 SplashDone(Splash * splash) 119 { 120 SplashCleanup(splash); 121 SplashDonePlatform(splash); 122 } 123 124 int 125 SplashIsStillLooping(Splash * splash) 126 { 127 if (splash->currentFrame < 0) { 128 return 0; 129 } 130 return splash->loopCount != 1 || 131 splash->currentFrame + 1 < splash->frameCount; 132 } 133 134 void 135 SplashUpdateScreenData(Splash * splash) 136 { 137 ImageRect srcRect, dstRect; 138 if (splash->currentFrame < 0) { 139 return; 140 } 141 142 initRect(&srcRect, 0, 0, splash->width, splash->height, 1, 143 splash->width * sizeof(rgbquad_t), 144 splash->frames[splash->currentFrame].bitmapBits, &splash->imageFormat); 145 if (splash->screenData) { 146 free(splash->screenData); 147 } 148 splash->screenStride = splash->width * splash->screenFormat.depthBytes; 149 if (splash->byteAlignment > 1) { 150 splash->screenStride = 151 (splash->screenStride + splash->byteAlignment - 1) & 152 ~(splash->byteAlignment - 1); 153 } 154 splash->screenData = malloc(splash->height * splash->screenStride); 155 initRect(&dstRect, 0, 0, splash->width, splash->height, 1, 156 splash->screenStride, splash->screenData, &splash->screenFormat); 157 if (splash->overlayData) { 158 convertRect2(&srcRect, &dstRect, CVT_BLEND, &splash->overlayRect); 159 } 160 else { 161 convertRect(&srcRect, &dstRect, CVT_COPY); 162 } 163 } 164 165 void 166 SplashNextFrame(Splash * splash) 167 { 168 if (splash->currentFrame < 0) { 169 return; 170 } 171 do { 172 if (!SplashIsStillLooping(splash)) { 173 return; 174 } 175 splash->time += splash->frames[splash->currentFrame].delay; 176 if (++splash->currentFrame >= splash->frameCount) { 177 splash->currentFrame = 0; 178 if (splash->loopCount > 0) { 179 splash->loopCount--; 180 } 181 } 182 } while (splash->time + splash->frames[splash->currentFrame].delay - 183 SplashTime() <= 0); 184 } 185 186 int 187 BitmapToYXBandedRectangles(ImageRect * pSrcRect, RECT_T * out) 188 { 189 RECT_T *pPrevLine = NULL, *pFirst = out, *pThis = pFirst; 190 int i, j, i0; 191 int length; 192 193 for (j = 0; j < pSrcRect->numLines; j++) { 194 195 /* generate data for a scanline */ 196 197 byte_t *pSrc = (byte_t *) pSrcRect->pBits + j * pSrcRect->stride; 198 RECT_T *pLine = pThis; 199 200 i = 0; 201 202 do { 203 while (i < pSrcRect->numSamples && 204 getRGBA(pSrc, pSrcRect->format) < ALPHA_THRESHOLD) { 205 pSrc += pSrcRect->depthBytes; 206 ++i; 207 } 208 if (i >= pSrcRect->numSamples) { 209 break; 210 } 211 i0 = i; 212 while (i < pSrcRect->numSamples && 213 getRGBA(pSrc, pSrcRect->format) >= ALPHA_THRESHOLD) { 214 pSrc += pSrcRect->depthBytes; 215 ++i; 216 } 217 RECT_SET(*pThis, i0, j, i - i0, 1); 218 ++pThis; 219 } while (i < pSrcRect->numSamples); 220 221 /* check if the previous scanline is exactly the same, merge if so 222 (this is the only optimization we can use for YXBanded rectangles, and win32 supports 223 YXBanded only */ 224 225 length = pThis - pLine; 226 if (pPrevLine && pLine - pPrevLine == length) { 227 for (i = 0; i < length && RECT_EQ_X(pPrevLine[i], pLine[i]); ++i) { 228 } 229 if (i == pLine - pPrevLine) { 230 // do merge 231 for (i = 0; i < length; i++) { 232 RECT_INC_HEIGHT(pPrevLine[i]); 233 } 234 pThis = pLine; 235 continue; 236 } 237 } 238 /* or else use the generated scanline */ 239 240 pPrevLine = pLine; 241 } 242 return pThis - pFirst; 243 } 244 245 typedef struct FILEFORMAT 246 { 247 int sign; 248 int (*decodeStream) (Splash * splash, SplashStream * stream); 249 } FILEFORMAT; 250 251 static const FILEFORMAT formats[] = { 252 {0x47, SplashDecodeGifStream}, 253 {0x89, SplashDecodePngStream}, 254 {0xFF, SplashDecodeJpegStream} 255 }; 256 257 static int 258 SplashLoadStream(SplashStream * stream) 259 { 260 int success = 0; 261 int c; 262 size_t i; 263 264 Splash *splash = SplashGetInstance(); 265 if (splash->isVisible < 0) { 266 return 0; 267 } 268 269 SplashLock(splash); 270 271 /* the formats we support can be easily distinguished by the first byte */ 272 c = stream->peek(stream); 273 if (c != -1) { 274 for (i = 0; i < sizeof(formats) / sizeof(FILEFORMAT); i++) { 275 if (c == formats[i].sign) { 276 success = formats[i].decodeStream(splash, stream); 277 break; 278 } 279 } 280 } 281 stream->close(stream); 282 283 if (!success) { // failed to decode 284 if (splash->isVisible == 0) { 285 SplashCleanup(splash); 286 } 287 SplashUnlock(splash); // SplashClose locks 288 if (splash->isVisible == 0) { 289 SplashClose(); 290 } 291 } 292 else { 293 splash->currentFrame = 0; 294 if (splash->isVisible == 0) { 295 SplashStart(splash); 296 } else { 297 SplashReconfigure(splash); 298 splash->time = SplashTime(); 299 } 300 SplashUnlock(splash); 301 } 302 return success; 303 } 304 305 SPLASHEXPORT int 306 SplashLoadFile(const char *filename) 307 { 308 SplashStream stream; 309 return SplashStreamInitFile(&stream, filename) && 310 SplashLoadStream(&stream); 311 } 312 313 SPLASHEXPORT int 314 SplashLoadMemory(void *data, int size) 315 { 316 SplashStream stream; 317 return SplashStreamInitMemory(&stream, data, size) && 318 SplashLoadStream(&stream); 319 } 320 321 /* SplashStart MUST be called from under the lock */ 322 323 void 324 SplashStart(Splash * splash) 325 { 326 if (splash->isVisible == 0) { 327 SplashCreateThread(splash); 328 splash->isVisible = 1; 329 } 330 } 331 332 /* SplashStream functions */ 333 334 static int readFile(void* pStream, void* pData, int nBytes) { 335 FILE* f = ((SplashStream*)pStream)->arg.stdio.f; 336 return fread(pData, 1, nBytes, f); 337 } 338 static int peekFile(void* pStream) { 339 FILE* f = ((SplashStream*)pStream)->arg.stdio.f; 340 int c = fgetc(f); 341 if (c != EOF) { 342 ungetc(c, f); 343 return c; 344 } else { 345 return -1; 346 } 347 } 348 349 static void closeFile(void* pStream) { 350 FILE* f = ((SplashStream*)pStream)->arg.stdio.f; 351 fclose(f); 352 } 353 354 static int readMem(void* pStream, void* pData, int nBytes) { 355 unsigned char* pSrc = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pData); 356 unsigned char* pSrcEnd = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pDataEnd); 357 if (nBytes > pSrcEnd - pSrc) { 358 nBytes = pSrcEnd - pSrc; 359 } 360 if (nBytes>0) { 361 memcpy(pData, pSrc, nBytes); 362 pSrc += nBytes; 363 ((SplashStream*)pStream)->arg.mem.pData = (void*)pSrc; 364 } 365 return nBytes; 366 } 367 368 static int peekMem(void* pStream) { 369 unsigned char* pSrc = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pData); 370 unsigned char* pSrcEnd = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pDataEnd); 371 if (pSrc >= pSrcEnd) { 372 return -1; 373 } else { 374 return (int)*pSrc; 375 } 376 } 377 378 static void closeMem(void* pStream) { 379 } 380 381 int SplashStreamInitFile(SplashStream * pStream, const char* filename) { 382 pStream->arg.stdio.f = fopen(filename, "rb"); 383 pStream->read = readFile; 384 pStream->peek = peekFile; 385 pStream->close = closeFile; 386 return pStream->arg.stdio.f != 0; 387 } 388 389 int SplashStreamInitMemory(SplashStream * pStream, void* pData, int size) { 390 pStream->arg.mem.pData = (unsigned char*)pData; 391 pStream->arg.mem.pDataEnd = (unsigned char*)pData + size; 392 pStream->read = readMem; 393 pStream->peek = peekMem; 394 pStream->close = closeMem; 395 return 1; 396 } 397 398 SPLASHEXPORT int 399 SplashGetScaledImgNameMaxPstfixLen(const char *fileName){ 400 return strlen(fileName) + strlen("@100pct") + 1; 401 } 402 403 jboolean GetScaledImageName(const char *fileName, char *scaleImageName, 404 float *scaleFactor, const size_t scaledImageLength) { 405 if (*scaleFactor > 1.0) { 406 FILE *fp = NULL; 407 char scaledImgPct[BUFF_SIZE]; 408 char scaledImgX[BUFF_SIZE]; 409 char *scaledImageXName = NULL; 410 char *scaledImagePctName = malloc(scaledImageLength); 411 char *dupFileName = strdup(fileName); 412 char *fileExtension = strrchr(dupFileName, '.'); 413 size_t lengthPct = 0; 414 size_t lengthX = 0; 415 int retValPct = 0; 416 int retValX = 0; 417 jboolean isPctScaledImage = (*scaleFactor * 100) != ((int) (*scaleFactor)) *100; 418 snprintf(scaledImgPct, BUFF_SIZE, "%s%d%s", "@", (int) (*scaleFactor * 100), "pct"); 419 if (!isPctScaledImage) { 420 scaledImageXName = malloc(scaledImageLength); 421 snprintf(scaledImgX, BUFF_SIZE, "%s%d%s", "@", (int) (*scaleFactor), "x"); 422 } 423 /*File is missing extension */ 424 if (fileExtension == NULL) { 425 lengthPct = strlen(dupFileName) + 426 strlen(scaledImgPct) + 1; 427 if (!isPctScaledImage) { 428 lengthX = strlen(dupFileName) + 429 strlen(scaledImgX) + 1; 430 } 431 if (lengthPct > scaledImageLength || lengthX > scaledImageLength) { 432 cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor); 433 return JNI_FALSE; 434 } 435 retValPct = snprintf(scaledImagePctName, lengthPct, "%s%s", dupFileName, 436 scaledImgPct); 437 if (!isPctScaledImage) { 438 retValX = snprintf(scaledImageXName, lengthX, "%s%s", dupFileName, 439 scaledImgX); 440 } 441 if ((retValPct < 0 || (retValPct > lengthPct - 1)) || 442 (retValX < 0 || (retValX > lengthX - 1))) { 443 cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor); 444 return JNI_FALSE; 445 } 446 } else { 447 int length_Without_Ext = fileExtension - dupFileName; 448 lengthPct = length_Without_Ext + strlen(scaledImgPct) + 449 strlen(fileExtension) + 1; 450 if (!isPctScaledImage) { 451 lengthX = length_Without_Ext + strlen(scaledImgX) + 452 strlen(fileExtension) + 1; 453 } 454 if (lengthPct > scaledImageLength || lengthX > scaledImageLength) { 455 cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor); 456 return JNI_FALSE; 457 } 458 retValPct = snprintf(scaledImagePctName, lengthPct, "%.*s%s%s", 459 length_Without_Ext, dupFileName, scaledImgPct, fileExtension); 460 if(!isPctScaledImage) { 461 retValX = snprintf(scaledImageXName, lengthX, "%.*s%s%s", 462 length_Without_Ext, dupFileName, scaledImgX, fileExtension); 463 } 464 if ((retValPct < 0 || (retValPct > lengthPct - 1)) || 465 (retValX < 0 || (retValX > lengthX - 1))) { 466 cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor); 467 return JNI_FALSE; 468 } 469 } 470 free(dupFileName); 471 if (!(fp = fopen(scaledImagePctName, "r"))) { 472 if (!isPctScaledImage && (fp = fopen(scaledImageXName, "r"))) { 473 fclose(fp); 474 strcpy(scaleImageName, scaledImageXName); 475 free(scaledImageXName); 476 free(scaledImagePctName); 477 return JNI_TRUE; 478 } 479 cleanUp(NULL,scaledImageXName, scaledImagePctName, scaleFactor); 480 return JNI_FALSE; 481 } 482 fclose(fp); 483 strcpy(scaleImageName, scaledImagePctName); 484 free(scaledImageXName); 485 free(scaledImagePctName); 486 return JNI_TRUE; 487 } 488 return JNI_FALSE; 489 } 490 491 void cleanUp(char *fName, char *xName, char *pctName, float *scaleFactor) { 492 *scaleFactor = 1; 493 free(fName); 494 free(xName); 495 free(pctName); 496 } 497