Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/libsplashscreen/splashscreen_gif.c
41152 views
1
/*
2
* Copyright (c) 2005, 2013, 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.h"
28
29
#include <gif_lib.h>
30
31
#include "sizecalc.h"
32
33
#define GIF_TRANSPARENT 0x01
34
#define GIF_USER_INPUT 0x02
35
#define GIF_DISPOSE_MASK 0x07
36
#define GIF_DISPOSE_SHIFT 2
37
38
#define GIF_NOT_TRANSPARENT -1
39
40
#define GIF_DISPOSE_NONE 0 // No disposal specified. The decoder is
41
// not required to take any action.
42
#define GIF_DISPOSE_LEAVE 1 // Do not dispose. The graphic is to be left
43
// in place.
44
#define GIF_DISPOSE_BACKGND 2 // Restore to background color. The area used by the
45
// graphic must be restored to the background color.
46
47
#define GIF_DISPOSE_RESTORE 3 // Restore to previous. The decoder is required to
48
// restore the area overwritten by the graphic with
49
// what was there prior to rendering the graphic.
50
51
static const char szNetscape20ext[11] = "NETSCAPE2.0";
52
53
#define NSEXT_LOOP 0x01 // Loop Count field code
54
55
// convert libungif samples to our ones
56
#define MAKE_QUAD_GIF(c,a) MAKE_QUAD((c).Red, (c).Green, (c).Blue, (unsigned)(a))
57
58
/* stdio FILE* and memory input functions for libungif */
59
int
60
SplashStreamGifInputFunc(GifFileType * gif, GifByteType * buf, int n)
61
{
62
SplashStream* io = (SplashStream*)gif->UserData;
63
int rc = io->read(io, buf, n);
64
return rc;
65
}
66
67
/* These macro help to ensure that we only take part of frame that fits into
68
logical screen. */
69
70
/* Ensure that p belongs to [pmin, pmax) interval. Returns fixed point (if fix is needed) */
71
#define FIX_POINT(p, pmin, pmax) ( ((p) < (pmin)) ? (pmin) : (((p) > (pmax)) ? (pmax) : (p)))
72
/* Ensures that line starting at point p does not exceed boundary pmax.
73
Returns fixed length (if fix is needed) */
74
#define FIX_LENGTH(p, len, pmax) ( ((p) + (len)) > (pmax) ? ((pmax) - (p)) : (len))
75
76
int
77
SplashDecodeGif(Splash * splash, GifFileType * gif)
78
{
79
int stride;
80
int bufferSize;
81
byte_t *pBitmapBits, *pOldBitmapBits;
82
int i, j;
83
int imageIndex;
84
int cx, cy, cw, ch; /* clamped coordinates */
85
const int interlacedOffset[] = { 0, 4, 2, 1, 0 }; /* The way Interlaced image should. */
86
const int interlacedJumps[] = { 8, 8, 4, 2, 1 }; /* be read - offsets and jumps... */
87
88
if (DGifSlurp(gif) == GIF_ERROR) {
89
return 0;
90
}
91
92
SplashCleanup(splash);
93
94
if (!SAFE_TO_ALLOC(gif->SWidth, splash->imageFormat.depthBytes)) {
95
return 0;
96
}
97
stride = gif->SWidth * splash->imageFormat.depthBytes;
98
if (splash->byteAlignment > 1)
99
stride =
100
(stride + splash->byteAlignment - 1) & ~(splash->byteAlignment - 1);
101
102
if (!SAFE_TO_ALLOC(gif->SHeight, stride)) {
103
return 0;
104
}
105
106
if (!SAFE_TO_ALLOC(gif->ImageCount, sizeof(SplashImage*))) {
107
return 0;
108
}
109
bufferSize = stride * gif->SHeight;
110
pBitmapBits = (byte_t *) malloc(bufferSize);
111
if (!pBitmapBits) {
112
return 0;
113
}
114
pOldBitmapBits = (byte_t *) malloc(bufferSize);
115
if (!pOldBitmapBits) {
116
free(pBitmapBits);
117
return 0;
118
}
119
memset(pBitmapBits, 0, bufferSize);
120
121
splash->width = gif->SWidth;
122
splash->height = gif->SHeight;
123
splash->frameCount = gif->ImageCount;
124
splash->frames = (SplashImage *)
125
SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(SplashImage), gif->ImageCount);
126
if (!splash->frames) {
127
free(pBitmapBits);
128
free(pOldBitmapBits);
129
return 0;
130
}
131
memset(splash->frames, 0, sizeof(SplashImage) * gif->ImageCount);
132
splash->loopCount = 1;
133
134
for (imageIndex = 0; imageIndex < gif->ImageCount; imageIndex++) {
135
SavedImage *image = &(gif->SavedImages[imageIndex]);
136
GifImageDesc *desc = &(image->ImageDesc);
137
ColorMapObject *colorMap =
138
desc->ColorMap ? desc->ColorMap : gif->SColorMap;
139
140
int transparentColor = -1;
141
int frameDelay = 100;
142
int disposeMethod = GIF_DISPOSE_RESTORE;
143
int colorCount = 0;
144
rgbquad_t colorMapBuf[SPLASH_COLOR_MAP_SIZE];
145
146
cx = FIX_POINT(desc->Left, 0, gif->SWidth);
147
cy = FIX_POINT(desc->Top, 0, gif->SHeight);
148
cw = FIX_LENGTH(desc->Left, desc->Width, gif->SWidth);
149
ch = FIX_LENGTH(desc->Top, desc->Height, gif->SHeight);
150
151
if (colorMap) {
152
if (colorMap->ColorCount <= SPLASH_COLOR_MAP_SIZE) {
153
colorCount = colorMap->ColorCount;
154
} else {
155
colorCount = SPLASH_COLOR_MAP_SIZE;
156
}
157
}
158
159
/* the code below is loosely based around gif extension processing from win32 libungif sample */
160
161
for (i = 0; i < image->ExtensionBlockCount; i++) {
162
byte_t *pExtension = (byte_t *) image->ExtensionBlocks[i].Bytes;
163
unsigned size = image->ExtensionBlocks[i].ByteCount;
164
165
switch (image->ExtensionBlocks[i].Function) {
166
case GRAPHICS_EXT_FUNC_CODE:
167
{
168
int flag = pExtension[0];
169
170
frameDelay = (((int)pExtension[2]) << 8) | pExtension[1];
171
if (frameDelay < 10)
172
frameDelay = 10;
173
if (flag & GIF_TRANSPARENT) {
174
transparentColor = pExtension[3];
175
} else {
176
transparentColor = GIF_NOT_TRANSPARENT;
177
}
178
disposeMethod =
179
(flag >> GIF_DISPOSE_SHIFT) & GIF_DISPOSE_MASK;
180
break;
181
}
182
case APPLICATION_EXT_FUNC_CODE:
183
{
184
if (size == sizeof(szNetscape20ext)
185
&& memcmp(pExtension, szNetscape20ext, size) == 0) {
186
int iSubCode;
187
188
if (++i >= image->ExtensionBlockCount)
189
break;
190
pExtension = (byte_t *) image->ExtensionBlocks[i].Bytes;
191
if (image->ExtensionBlocks[i].ByteCount != 3)
192
break;
193
iSubCode = pExtension[0] & 0x07;
194
if (iSubCode == NSEXT_LOOP) {
195
splash->loopCount =
196
(pExtension[1] | (((int)pExtension[2]) << 8)) - 1;
197
}
198
}
199
break;
200
}
201
default:
202
break;
203
}
204
}
205
206
if (colorMap) {
207
for (i = 0; i < colorCount; i++) {
208
colorMapBuf[i] = MAKE_QUAD_GIF(colorMap->Colors[i], 0xff);
209
}
210
}
211
{
212
213
byte_t *pSrc = image->RasterBits;
214
ImageFormat srcFormat;
215
ImageRect srcRect, dstRect;
216
int pass = 4, npass = 5;
217
218
#if GIFLIB_MAJOR < 5
219
/* Interlaced gif support is broken in giflib < 5
220
so we need to work around this */
221
if (desc->Interlace) {
222
pass = 0;
223
npass = 4;
224
}
225
#endif
226
227
srcFormat.colorMap = colorMapBuf;
228
srcFormat.depthBytes = 1;
229
srcFormat.byteOrder = BYTE_ORDER_NATIVE;
230
srcFormat.transparentColor = transparentColor;
231
srcFormat.fixedBits = QUAD_ALPHA_MASK; // fixed 100% alpha
232
srcFormat.premultiplied = 0;
233
234
for (; pass < npass; ++pass) {
235
int jump = interlacedJumps[pass];
236
int ofs = interlacedOffset[pass];
237
/* Number of source lines for current pass */
238
int numPassLines = (desc->Height + jump - ofs - 1) / jump;
239
/* Number of lines that fits to dest buffer */
240
int numLines = (ch + jump - ofs - 1) / jump;
241
242
initRect(&srcRect, 0, 0, desc->Width, numLines, 1,
243
desc->Width, pSrc, &srcFormat);
244
245
if (numLines > 0) {
246
initRect(&dstRect, cx, cy + ofs, cw,
247
numLines , jump, stride, pBitmapBits, &splash->imageFormat);
248
249
pSrc += convertRect(&srcRect, &dstRect, CVT_ALPHATEST);
250
}
251
// skip extra source data
252
pSrc += (numPassLines - numLines) * srcRect.stride;
253
}
254
}
255
256
// now dispose of the previous frame correctly
257
258
splash->frames[imageIndex].bitmapBits =
259
(rgbquad_t *) malloc(bufferSize); // bufferSize is safe (checked above)
260
if (!splash->frames[imageIndex].bitmapBits) {
261
free(pBitmapBits);
262
free(pOldBitmapBits);
263
/* Assuming that callee will take care of splash frames we have already allocated */
264
return 0;
265
}
266
memcpy(splash->frames[imageIndex].bitmapBits, pBitmapBits, bufferSize);
267
268
SplashInitFrameShape(splash, imageIndex);
269
270
splash->frames[imageIndex].delay = frameDelay * 10; // 100ths of second to milliseconds
271
switch (disposeMethod) {
272
case GIF_DISPOSE_LEAVE:
273
memcpy(pOldBitmapBits, pBitmapBits, bufferSize);
274
break;
275
case GIF_DISPOSE_NONE:
276
break;
277
case GIF_DISPOSE_BACKGND:
278
{
279
ImageRect dstRect;
280
rgbquad_t fillColor = 0; // 0 is transparent
281
282
if (transparentColor < 0) {
283
fillColor= MAKE_QUAD_GIF(
284
colorMap->Colors[gif->SBackGroundColor], 0xff);
285
}
286
initRect(&dstRect,
287
cx, cy, cw, ch,
288
1, stride,
289
pBitmapBits, &splash->imageFormat);
290
fillRect(fillColor, &dstRect);
291
}
292
break;
293
case GIF_DISPOSE_RESTORE:
294
{
295
int lineSize = cw * splash->imageFormat.depthBytes;
296
if (lineSize > 0) {
297
int lineOffset = cx * splash->imageFormat.depthBytes;
298
int lineIndex = cy * stride + lineOffset;
299
for (j=0; j<ch; j++) {
300
memcpy(pBitmapBits + lineIndex, pOldBitmapBits + lineIndex,
301
lineSize);
302
lineIndex += stride;
303
}
304
}
305
}
306
break;
307
}
308
}
309
310
free(pBitmapBits);
311
free(pOldBitmapBits);
312
313
#if GIFLIB_MAJOR > 5 || (GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1)
314
if (DGifCloseFile(gif, NULL) == GIF_ERROR) {
315
return 0;
316
}
317
#else
318
DGifCloseFile(gif);
319
#endif
320
321
return 1;
322
}
323
324
int
325
SplashDecodeGifStream(Splash * splash, SplashStream * stream)
326
{
327
#if GIFLIB_MAJOR >= 5
328
GifFileType *gif = DGifOpen((void *) stream, SplashStreamGifInputFunc, NULL);
329
#else
330
GifFileType *gif = DGifOpen((void *) stream, SplashStreamGifInputFunc);
331
#endif
332
333
if (!gif)
334
return 0;
335
return SplashDecodeGif(splash, gif);
336
}
337
338