Path: blob/master/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c
41149 views
/*1* Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include "splashscreen_impl.h"26#include "splashscreen_gfx_impl.h"27#define BUFF_SIZE 102428#ifdef _MSC_VER29# ifndef snprintf30# define snprintf _snprintf31# endif32#endif33int splashIsVisible = 0;3435Splash *36SplashGetInstance()37{38static Splash splash;39static int preInitialized = 0;40if (!preInitialized) {41memset(&splash, 0, sizeof(Splash));42splash.currentFrame = -1;43preInitialized = 1;44}45return &splash;46}4748JNIEXPORT void49SplashSetFileJarName(const char* fileName, const char* jarName) {50Splash *splash = SplashGetInstance();5152free(splash->fileName);53splash->fileName = SplashConvertStringAlloc(fileName, &splash->fileNameLen);5455free(splash->jarName);56splash->jarName = SplashConvertStringAlloc(jarName, &splash->jarNameLen);57}5859JNIEXPORT int60SplashInit()61{62Splash *splash = SplashGetInstance();6364memset(splash, 0, sizeof(Splash));65splash->currentFrame = -1;66splash->scaleFactor = 1;67initFormat(&splash->imageFormat, QUAD_RED_MASK, QUAD_GREEN_MASK,68QUAD_BLUE_MASK, QUAD_ALPHA_MASK);69return SplashInitPlatform(splash);70}7172JNIEXPORT void73SplashClose()74{75Splash *splash = SplashGetInstance();7677if (splash->isVisible > 0) {78SplashLock(splash);79splash->isVisible = -1;80SplashClosePlatform(splash);81SplashUnlock(splash);82}83}8485void86SplashCleanup(Splash * splash)87{88int i;8990splash->currentFrame = -1;91SplashCleanupPlatform(splash);92if (splash->frames) {93for (i = 0; i < splash->frameCount; i++) {94if (splash->frames[i].bitmapBits) {95free(splash->frames[i].bitmapBits);96splash->frames[i].bitmapBits = NULL;97}98}99free(splash->frames);100splash->frames = NULL;101}102if (splash->overlayData) {103free(splash->overlayData);104splash->overlayData = NULL;105}106SplashSetFileJarName(NULL, NULL);107}108109JNIEXPORT void110SplashSetScaleFactor(float scaleFactor)111{112Splash *splash = SplashGetInstance();113splash->scaleFactor = scaleFactor;114}115116void117SplashDone(Splash * splash)118{119SplashCleanup(splash);120SplashDonePlatform(splash);121}122123int124SplashIsStillLooping(Splash * splash)125{126if (splash->currentFrame < 0) {127return 0;128}129return splash->loopCount != 1 ||130splash->currentFrame + 1 < splash->frameCount;131}132133void134SplashUpdateScreenData(Splash * splash)135{136ImageRect srcRect, dstRect;137if (splash->currentFrame < 0) {138return;139}140141initRect(&srcRect, 0, 0, splash->width, splash->height, 1,142splash->width * sizeof(rgbquad_t),143splash->frames[splash->currentFrame].bitmapBits, &splash->imageFormat);144if (splash->screenData) {145free(splash->screenData);146}147splash->screenStride = splash->width * splash->screenFormat.depthBytes;148if (splash->byteAlignment > 1) {149splash->screenStride =150(splash->screenStride + splash->byteAlignment - 1) &151~(splash->byteAlignment - 1);152}153splash->screenData = malloc(splash->height * splash->screenStride);154initRect(&dstRect, 0, 0, splash->width, splash->height, 1,155splash->screenStride, splash->screenData, &splash->screenFormat);156if (splash->overlayData) {157convertRect2(&srcRect, &dstRect, CVT_BLEND, &splash->overlayRect);158}159else {160convertRect(&srcRect, &dstRect, CVT_COPY);161}162}163164void165SplashNextFrame(Splash * splash)166{167if (splash->currentFrame < 0) {168return;169}170do {171if (!SplashIsStillLooping(splash)) {172return;173}174splash->time += splash->frames[splash->currentFrame].delay;175if (++splash->currentFrame >= splash->frameCount) {176splash->currentFrame = 0;177if (splash->loopCount > 0) {178splash->loopCount--;179}180}181} while (splash->time + splash->frames[splash->currentFrame].delay -182SplashTime() <= 0);183}184185int186BitmapToYXBandedRectangles(ImageRect * pSrcRect, RECT_T * out)187{188RECT_T *pPrevLine = NULL, *pFirst = out, *pThis = pFirst;189int i, j, i0;190int length;191192for (j = 0; j < pSrcRect->numLines; j++) {193194/* generate data for a scanline */195196byte_t *pSrc = (byte_t *) pSrcRect->pBits + j * pSrcRect->stride;197RECT_T *pLine = pThis;198199i = 0;200201do {202while (i < pSrcRect->numSamples &&203getRGBA(pSrc, pSrcRect->format) < ALPHA_THRESHOLD) {204pSrc += pSrcRect->depthBytes;205++i;206}207if (i >= pSrcRect->numSamples) {208break;209}210i0 = i;211while (i < pSrcRect->numSamples &&212getRGBA(pSrc, pSrcRect->format) >= ALPHA_THRESHOLD) {213pSrc += pSrcRect->depthBytes;214++i;215}216RECT_SET(*pThis, i0, j, i - i0, 1);217++pThis;218} while (i < pSrcRect->numSamples);219220/* check if the previous scanline is exactly the same, merge if so221(this is the only optimization we can use for YXBanded rectangles, and win32 supports222YXBanded only */223224length = pThis - pLine;225if (pPrevLine && pLine - pPrevLine == length) {226for (i = 0; i < length && RECT_EQ_X(pPrevLine[i], pLine[i]); ++i) {227}228if (i == pLine - pPrevLine) {229// do merge230for (i = 0; i < length; i++) {231RECT_INC_HEIGHT(pPrevLine[i]);232}233pThis = pLine;234continue;235}236}237/* or else use the generated scanline */238239pPrevLine = pLine;240}241return pThis - pFirst;242}243244typedef struct FILEFORMAT245{246int sign;247int (*decodeStream) (Splash * splash, SplashStream * stream);248} FILEFORMAT;249250static const FILEFORMAT formats[] = {251{0x47, SplashDecodeGifStream},252{0x89, SplashDecodePngStream},253{0xFF, SplashDecodeJpegStream}254};255256static int257SplashLoadStream(SplashStream * stream)258{259int success = 0;260int c;261size_t i;262263Splash *splash = SplashGetInstance();264if (splash->isVisible < 0) {265stream->close(stream);266return 0;267}268269SplashLock(splash);270271/* the formats we support can be easily distinguished by the first byte */272c = stream->peek(stream);273if (c != -1) {274for (i = 0; i < sizeof(formats) / sizeof(FILEFORMAT); i++) {275if (c == formats[i].sign) {276success = formats[i].decodeStream(splash, stream);277break;278}279}280}281stream->close(stream);282283if (!success) { // failed to decode284if (splash->isVisible == 0) {285SplashCleanup(splash);286}287SplashUnlock(splash); // SplashClose locks288if (splash->isVisible == 0) {289SplashClose();290}291}292else {293splash->currentFrame = 0;294if (splash->isVisible == 0) {295SplashStart(splash);296} else {297SplashReconfigure(splash);298splash->time = SplashTime();299}300SplashUnlock(splash);301}302return success;303}304305JNIEXPORT int306SplashLoadFile(const char *filename)307{308SplashStream stream;309return SplashStreamInitFile(&stream, filename) &&310SplashLoadStream(&stream);311}312313JNIEXPORT int314SplashLoadMemory(void *data, int size)315{316SplashStream stream;317return SplashStreamInitMemory(&stream, data, size) &&318SplashLoadStream(&stream);319}320321/* SplashStart MUST be called from under the lock */322323void324SplashStart(Splash * splash)325{326if (splash->isVisible == 0) {327SplashCreateThread(splash);328splash->isVisible = 1;329}330}331332/* SplashStream functions */333334static int readFile(void* pStream, void* pData, int nBytes) {335FILE* f = ((SplashStream*)pStream)->arg.stdio.f;336return fread(pData, 1, nBytes, f);337}338static int peekFile(void* pStream) {339FILE* f = ((SplashStream*)pStream)->arg.stdio.f;340int c = fgetc(f);341if (c != EOF) {342ungetc(c, f);343return c;344} else {345return -1;346}347}348349static void closeFile(void* pStream) {350FILE* f = ((SplashStream*)pStream)->arg.stdio.f;351fclose(f);352}353354static int readMem(void* pStream, void* pData, int nBytes) {355unsigned char* pSrc = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pData);356unsigned char* pSrcEnd = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pDataEnd);357if (nBytes > pSrcEnd - pSrc) {358nBytes = pSrcEnd - pSrc;359}360if (nBytes>0) {361memcpy(pData, pSrc, nBytes);362pSrc += nBytes;363((SplashStream*)pStream)->arg.mem.pData = (void*)pSrc;364}365return nBytes;366}367368static int peekMem(void* pStream) {369unsigned char* pSrc = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pData);370unsigned char* pSrcEnd = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pDataEnd);371if (pSrc >= pSrcEnd) {372return -1;373} else {374return (int)*pSrc;375}376}377378static void closeMem(void* pStream) {379}380381int SplashStreamInitFile(SplashStream * pStream, const char* filename) {382pStream->arg.stdio.f = fopen(filename, "rb");383pStream->read = readFile;384pStream->peek = peekFile;385pStream->close = closeFile;386return pStream->arg.stdio.f != 0;387}388389int SplashStreamInitMemory(SplashStream * pStream, void* pData, int size) {390pStream->arg.mem.pData = (unsigned char*)pData;391pStream->arg.mem.pDataEnd = (unsigned char*)pData + size;392pStream->read = readMem;393pStream->peek = peekMem;394pStream->close = closeMem;395return 1;396}397398JNIEXPORT int399SplashGetScaledImgNameMaxPstfixLen(const char *fileName){400return strlen(fileName) + strlen("@100pct") + 1;401}402403jboolean GetScaledImageName(const char *fileName, char *scaleImageName,404float *scaleFactor, const size_t scaledImageLength) {405if (*scaleFactor > 1.0) {406FILE *fp = NULL;407char scaledImgPct[BUFF_SIZE];408char scaledImgX[BUFF_SIZE];409char *scaledImageXName = NULL;410char *scaledImagePctName = malloc(scaledImageLength);411char *dupFileName = strdup(fileName);412char *fileExtension = strrchr(dupFileName, '.');413size_t lengthPct = 0;414size_t lengthX = 0;415int retValPct = 0;416int retValX = 0;417jboolean isPctScaledImage = (*scaleFactor * 100) != ((int) (*scaleFactor)) *100;418snprintf(scaledImgPct, BUFF_SIZE, "%s%d%s", "@",419(int) (*scaleFactor * 100), "pct");420if (!isPctScaledImage) {421scaledImageXName = malloc(scaledImageLength);422snprintf(scaledImgX, BUFF_SIZE, "%s%d%s", "@", (int) (*scaleFactor), "x");423}424/*File is missing extension */425if (fileExtension == NULL) {426lengthPct = strlen(dupFileName) +427strlen(scaledImgPct) + 1;428if (!isPctScaledImage) {429lengthX = strlen(dupFileName) +430strlen(scaledImgX) + 1;431}432if (lengthPct > scaledImageLength || lengthX > scaledImageLength) {433cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor);434return JNI_FALSE;435}436retValPct = snprintf(scaledImagePctName, lengthPct, "%s%s", dupFileName,437scaledImgPct);438if (!isPctScaledImage) {439retValX = snprintf(scaledImageXName, lengthX, "%s%s", dupFileName,440scaledImgX);441}442if ((retValPct < 0 || (retValPct > lengthPct - 1)) ||443(retValX < 0 || (retValX > lengthX - 1))) {444cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor);445return JNI_FALSE;446}447} else {448int length_Without_Ext = fileExtension - dupFileName;449lengthPct = length_Without_Ext + strlen(scaledImgPct) +450strlen(fileExtension) + 1;451if (!isPctScaledImage) {452lengthX = length_Without_Ext + strlen(scaledImgX) +453strlen(fileExtension) + 1;454}455if (lengthPct > scaledImageLength || lengthX > scaledImageLength) {456cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor);457return JNI_FALSE;458}459retValPct = snprintf(scaledImagePctName, lengthPct, "%.*s%s%s",460length_Without_Ext, dupFileName, scaledImgPct, fileExtension);461if (!isPctScaledImage) {462retValX = snprintf(scaledImageXName, lengthX, "%.*s%s%s",463length_Without_Ext, dupFileName, scaledImgX, fileExtension);464}465if ((retValPct < 0 || (retValPct > lengthPct - 1)) ||466(retValX < 0 || (retValX > lengthX - 1))) {467cleanUp(dupFileName, scaledImageXName, scaledImagePctName, scaleFactor);468return JNI_FALSE;469}470}471free(dupFileName);472if (!(fp = fopen(scaledImagePctName, "r"))) {473if (!isPctScaledImage && (fp = fopen(scaledImageXName, "r"))) {474fclose(fp);475strcpy(scaleImageName, scaledImageXName);476free(scaledImageXName);477free(scaledImagePctName);478return JNI_TRUE;479}480cleanUp(NULL, scaledImageXName, scaledImagePctName, scaleFactor);481return JNI_FALSE;482}483fclose(fp);484strcpy(scaleImageName, scaledImagePctName);485free(scaledImageXName);486free(scaledImagePctName);487return JNI_TRUE;488}489return JNI_FALSE;490}491492void cleanUp(char *fName, char *xName, char *pctName, float *scaleFactor) {493*scaleFactor = 1;494free(fName);495free(xName);496free(pctName);497}498499500