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 }