325N/A/*
325N/A * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
325N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
325N/A *
325N/A * This code is free software; you can redistribute it and/or modify it
325N/A * under the terms of the GNU General Public License version 2 only, as
325N/A * published by the Free Software Foundation. Oracle designates this
325N/A * particular file as subject to the "Classpath" exception as provided
325N/A * by Oracle in the LICENSE file that accompanied this code.
325N/A *
325N/A * This code is distributed in the hope that it will be useful, but WITHOUT
325N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
325N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
325N/A * version 2 for more details (a copy is included in the LICENSE file that
325N/A * accompanied this code).
325N/A *
325N/A * You should have received a copy of the GNU General Public License version
325N/A * 2 along with this work; if not, write to the Free Software Foundation,
325N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
325N/A *
325N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
325N/A * or visit www.oracle.com if you need additional information or have any
325N/A * questions.
325N/A */
325N/A
325N/A#include "splashscreen_impl.h"
325N/A#include "splashscreen_gfx_impl.h"
325N/A
325N/Aint splashIsVisible = 0;
325N/A
325N/ASplash *
325N/ASplashGetInstance()
325N/A{
325N/A static Splash splash;
325N/A static int preInitialized = 0;
325N/A if (!preInitialized) {
325N/A memset(&splash, 0, sizeof(Splash));
325N/A splash.currentFrame = -1;
325N/A preInitialized = 1;
325N/A }
325N/A return &splash;
325N/A}
325N/A
325N/ASPLASHEXPORT void
325N/ASplashSetFileJarName(const char* fileName, const char* jarName) {
325N/A Splash *splash = SplashGetInstance();
325N/A
325N/A free(splash->fileName);
325N/A splash->fileName = SplashConvertStringAlloc(fileName, &splash->fileNameLen);
325N/A
325N/A free(splash->jarName);
325N/A splash->jarName = SplashConvertStringAlloc(jarName, &splash->jarNameLen);
325N/A}
325N/A
325N/ASPLASHEXPORT void
325N/ASplashInit()
325N/A{
325N/A Splash *splash = SplashGetInstance();
325N/A
325N/A memset(splash, 0, sizeof(Splash));
325N/A splash->currentFrame = -1;
325N/A initFormat(&splash->imageFormat, QUAD_RED_MASK, QUAD_GREEN_MASK,
325N/A QUAD_BLUE_MASK, QUAD_ALPHA_MASK);
325N/A SplashInitPlatform(splash);
325N/A}
325N/A
325N/ASPLASHEXPORT void
325N/ASplashClose()
325N/A{
325N/A Splash *splash = SplashGetInstance();
325N/A
325N/A if (splash->isVisible > 0) {
325N/A SplashLock(splash);
325N/A splash->isVisible = -1;
325N/A SplashClosePlatform(splash);
325N/A SplashUnlock(splash);
325N/A }
325N/A}
325N/A
325N/Avoid
325N/ASplashCleanup(Splash * splash)
325N/A{
325N/A int i;
325N/A
325N/A splash->currentFrame = -1;
325N/A SplashCleanupPlatform(splash);
325N/A if (splash->frames) {
325N/A for (i = 0; i < splash->frameCount; i++) {
325N/A if (splash->frames[i].bitmapBits) {
325N/A free(splash->frames[i].bitmapBits);
325N/A splash->frames[i].bitmapBits = NULL;
325N/A }
325N/A }
325N/A free(splash->frames);
325N/A splash->frames = NULL;
325N/A }
325N/A if (splash->overlayData) {
325N/A free(splash->overlayData);
325N/A splash->overlayData = NULL;
325N/A }
325N/A SplashSetFileJarName(NULL, NULL);
325N/A}
325N/A
325N/Avoid
325N/ASplashDone(Splash * splash)
325N/A{
325N/A SplashCleanup(splash);
325N/A SplashDonePlatform(splash);
325N/A}
325N/A
325N/Aint
325N/ASplashIsStillLooping(Splash * splash)
325N/A{
325N/A if (splash->currentFrame < 0)
325N/A return 0;
325N/A return splash->loopCount != 1 ||
325N/A splash->currentFrame + 1 < splash->frameCount;
325N/A}
325N/A
325N/Avoid
325N/ASplashUpdateScreenData(Splash * splash)
325N/A{
325N/A ImageRect srcRect, dstRect;
325N/A
325N/A initRect(&srcRect, 0, 0, splash->width, splash->height, 1,
325N/A splash->width * sizeof(rgbquad_t),
325N/A splash->frames[splash->currentFrame].bitmapBits, &splash->imageFormat);
325N/A if (splash->screenData)
325N/A free(splash->screenData);
325N/A splash->screenStride = splash->width * splash->screenFormat.depthBytes;
325N/A if (splash->byteAlignment > 1)
325N/A splash->screenStride =
325N/A (splash->screenStride + splash->byteAlignment - 1) &
325N/A ~(splash->byteAlignment - 1);
325N/A splash->screenData = malloc(splash->height * splash->screenStride);
325N/A initRect(&dstRect, 0, 0, splash->width, splash->height, 1,
325N/A splash->screenStride, splash->screenData, &splash->screenFormat);
325N/A if (splash->overlayData) {
325N/A convertRect2(&srcRect, &dstRect, CVT_BLEND, &splash->overlayRect);
325N/A }
325N/A else {
325N/A convertRect(&srcRect, &dstRect, CVT_COPY);
325N/A }
325N/A}
325N/A
325N/Avoid
325N/ASplashNextFrame(Splash * splash)
325N/A{
325N/A if (splash->currentFrame < 0)
325N/A return;
325N/A do {
325N/A if (!SplashIsStillLooping(splash))
325N/A return;
splash->time += splash->frames[splash->currentFrame].delay;
if (++splash->currentFrame >= splash->frameCount) {
splash->currentFrame = 0;
if (splash->loopCount > 0)
splash->loopCount--;
}
} while (splash->time + splash->frames[splash->currentFrame].delay -
SplashTime() <= 0);
}
int
BitmapToYXBandedRectangles(ImageRect * pSrcRect, RECT_T * out)
{
RECT_T *pPrevLine = NULL, *pFirst = out, *pThis = pFirst;
int i, j, i0;
int length;
for (j = 0; j < pSrcRect->numLines; j++) {
/* generate data for a scanline */
byte_t *pSrc = (byte_t *) pSrcRect->pBits + j * pSrcRect->stride;
RECT_T *pLine = pThis;
i = 0;
do {
while (i < pSrcRect->numSamples &&
getRGBA(pSrc, pSrcRect->format) < ALPHA_THRESHOLD) {
pSrc += pSrcRect->depthBytes;
++i;
}
if (i >= pSrcRect->numSamples)
break;
i0 = i;
while (i < pSrcRect->numSamples &&
getRGBA(pSrc, pSrcRect->format) >= ALPHA_THRESHOLD) {
pSrc += pSrcRect->depthBytes;
++i;
}
RECT_SET(*pThis, i0, j, i - i0, 1);
++pThis;
} while (i < pSrcRect->numSamples);
/* check if the previous scanline is exactly the same, merge if so
(this is the only optimization we can use for YXBanded rectangles, and win32 supports
YXBanded only */
length = pThis - pLine;
if (pPrevLine && pLine - pPrevLine == length) {
for (i = 0; i < length && RECT_EQ_X(pPrevLine[i], pLine[i]); ++i) {
}
if (i == pLine - pPrevLine) {
// do merge
for (i = 0; i < length; i++) {
RECT_INC_HEIGHT(pPrevLine[i]);
}
pThis = pLine;
continue;
}
}
/* or else use the generated scanline */
pPrevLine = pLine;
}
return pThis - pFirst;
}
typedef struct FILEFORMAT
{
int sign;
int (*decodeStream) (Splash * splash, SplashStream * stream);
} FILEFORMAT;
static const FILEFORMAT formats[] = {
{0x47, SplashDecodeGifStream},
{0x89, SplashDecodePngStream},
{0xFF, SplashDecodeJpegStream}
};
static int
SplashLoadStream(SplashStream * stream)
{
int success = 0;
int c;
size_t i;
Splash *splash = SplashGetInstance();
if (splash->isVisible < 0) {
return 0;
}
SplashLock(splash);
/* the formats we support can be easily distinguished by the first byte */
c = stream->peek(stream);
if (c != -1) {
for (i = 0; i < sizeof(formats) / sizeof(FILEFORMAT); i++) {
if (c == formats[i].sign) {
success = formats[i].decodeStream(splash, stream);
break;
}
}
}
stream->close(stream);
if (!success) { // failed to decode
if (splash->isVisible == 0) {
SplashCleanup(splash);
}
SplashUnlock(splash); // SplashClose locks
if (splash->isVisible == 0) {
SplashClose();
}
}
else {
splash->currentFrame = 0;
if (splash->isVisible == 0) {
SplashStart(splash);
} else {
SplashReconfigure(splash);
splash->time = SplashTime();
}
SplashUnlock(splash);
}
return success;
}
SPLASHEXPORT int
SplashLoadFile(const char *filename)
{
SplashStream stream;
return SplashStreamInitFile(&stream, filename) &&
SplashLoadStream(&stream);
}
SPLASHEXPORT int
SplashLoadMemory(void *data, int size)
{
SplashStream stream;
return SplashStreamInitMemory(&stream, data, size) &&
SplashLoadStream(&stream);
}
/* SplashStart MUST be called from under the lock */
void
SplashStart(Splash * splash)
{
if (splash->isVisible == 0) {
SplashCreateThread(splash);
splash->isVisible = 1;
}
}
/* SplashStream functions */
static int readFile(void* pStream, void* pData, int nBytes) {
FILE* f = ((SplashStream*)pStream)->arg.stdio.f;
return fread(pData, 1, nBytes, f);
}
static int peekFile(void* pStream) {
FILE* f = ((SplashStream*)pStream)->arg.stdio.f;
int c = fgetc(f);
if (c != EOF) {
ungetc(c, f);
return c;
} else {
return -1;
}
}
static void closeFile(void* pStream) {
FILE* f = ((SplashStream*)pStream)->arg.stdio.f;
fclose(f);
}
static int readMem(void* pStream, void* pData, int nBytes) {
unsigned char* pSrc = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pData);
unsigned char* pSrcEnd = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pDataEnd);
if (nBytes > pSrcEnd - pSrc) {
nBytes = pSrcEnd - pSrc;
}
if (nBytes>0) {
memcpy(pData, pSrc, nBytes);
pSrc += nBytes;
((SplashStream*)pStream)->arg.mem.pData = (void*)pSrc;
}
return nBytes;
}
static int peekMem(void* pStream) {
unsigned char* pSrc = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pData);
unsigned char* pSrcEnd = (unsigned char*)(((SplashStream*)pStream)->arg.mem.pDataEnd);
if (pSrc >= pSrcEnd) {
return -1;
} else {
return (int)*pSrc;
}
}
static void closeMem(void* pStream) {
}
int SplashStreamInitFile(SplashStream * pStream, const char* filename) {
pStream->arg.stdio.f = fopen(filename, "rb");
pStream->read = readFile;
pStream->peek = peekFile;
pStream->close = closeFile;
return pStream->arg.stdio.f != 0;
}
int SplashStreamInitMemory(SplashStream * pStream, void* pData, int size) {
pStream->arg.mem.pData = (unsigned char*)pData;
pStream->arg.mem.pDataEnd = (unsigned char*)pData + size;
pStream->read = readMem;
pStream->peek = peekMem;
pStream->close = closeMem;
return 1;
}