blob: f6d9acb0c36c6f2d256ee2028b21b1ce89cdddad [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26#include "splashscreen_impl.h"
27#include "splashscreen_gfx.h"
28
29#include "../giflib/gif_lib.h"
30
31#define GIF_TRANSPARENT 0x01
32#define GIF_USER_INPUT 0x02
33#define GIF_DISPOSE_MASK 0x07
34#define GIF_DISPOSE_SHIFT 2
35
36#define GIF_NOT_TRANSPARENT -1
37
38#define GIF_DISPOSE_NONE 0 // No disposal specified. The decoder is
39 // not required to take any action.
40#define GIF_DISPOSE_LEAVE 1 // Do not dispose. The graphic is to be left
41 // in place.
42#define GIF_DISPOSE_BACKGND 2 // Restore to background color. The area used by the
43 // graphic must be restored to the background color.
44
45#define GIF_DISPOSE_RESTORE 3 // Restore to previous. The decoder is required to
46 // restore the area overwritten by the graphic with
47 // what was there prior to rendering the graphic.
48
49static const char szNetscape20ext[11] = "NETSCAPE2.0";
50
51#define NSEXT_LOOP 0x01 // Loop Count field code
52
53// convert libungif samples to our ones
54#define MAKE_QUAD_GIF(c,a) MAKE_QUAD((c).Red, (c).Green, (c).Blue, (a))
55
56/* stdio FILE* and memory input functions for libungif */
57int
58SplashStreamGifInputFunc(GifFileType * gif, GifByteType * buf, int n)
59{
60 SplashStream* io = (SplashStream*)gif->UserData;
61 int rc = io->read(io, buf, n);
62 return rc;
63}
64
65int
66SplashDecodeGif(Splash * splash, GifFileType * gif)
67{
68 int stride;
69 int bufferSize;
70 byte_t *pBitmapBits, *pOldBitmapBits;
71 int i, j;
72 int imageIndex;
73 const int interlacedOffset[] = { 0, 4, 2, 1, 0 }; /* The way Interlaced image should. */
74 const int interlacedJumps[] = { 8, 8, 4, 2, 1 }; /* be read - offsets and jumps... */
75
76 if (DGifSlurp(gif) == GIF_ERROR) {
77 return 0;
78 }
79
80 SplashCleanup(splash);
81
82 stride = gif->SWidth * splash->imageFormat.depthBytes;
83 if (splash->byteAlignment > 1)
84 stride =
85 (stride + splash->byteAlignment - 1) & ~(splash->byteAlignment - 1);
86
87 bufferSize = stride * gif->SHeight;
88 pBitmapBits = (byte_t *) malloc(bufferSize);
89 pOldBitmapBits = (byte_t *) malloc(bufferSize);
90 memset(pBitmapBits, 0, bufferSize);
91
92 splash->width = gif->SWidth;
93 splash->height = gif->SHeight;
94 splash->frameCount = gif->ImageCount;
95 splash->frames = (SplashImage *)
96 malloc(sizeof(SplashImage) * gif->ImageCount);
97 memset(splash->frames, 0, sizeof(SplashImage) * gif->ImageCount);
98 splash->loopCount = 1;
99
100 for (imageIndex = 0; imageIndex < gif->ImageCount; imageIndex++) {
101 SavedImage *image = &(gif->SavedImages[imageIndex]);
102 GifImageDesc *desc = &(image->ImageDesc);
103 ColorMapObject *colorMap =
104 desc->ColorMap ? desc->ColorMap : gif->SColorMap;
105
106 int transparentColor = -1;
107 int frameDelay = 100;
108 int disposeMethod = GIF_DISPOSE_RESTORE;
109 int colorCount = 0;
110 rgbquad_t colorMapBuf[SPLASH_COLOR_MAP_SIZE];
111
112 if (colorMap) {
113 if (colorMap->ColorCount <= SPLASH_COLOR_MAP_SIZE) {
114 colorCount = colorMap->ColorCount;
115 } else {
116 colorCount = SPLASH_COLOR_MAP_SIZE;
117 }
118 }
119
120 /* the code below is loosely based around gif extension processing from win32 libungif sample */
121
122 for (i = 0; i < image->ExtensionBlockCount; i++) {
123 byte_t *pExtension = (byte_t *) image->ExtensionBlocks[i].Bytes;
124 unsigned size = image->ExtensionBlocks[i].ByteCount;
125
126 switch (image->ExtensionBlocks[i].Function) {
127 case GRAPHICS_EXT_FUNC_CODE:
128 {
129 int flag = pExtension[0];
130
131 frameDelay = (pExtension[2] << 8) | pExtension[1];
132 if (frameDelay < 10)
133 frameDelay = 10;
134 if (flag & GIF_TRANSPARENT) {
135 transparentColor = pExtension[3];
136 } else {
137 transparentColor = GIF_NOT_TRANSPARENT;
138 }
139 disposeMethod =
140 (flag >> GIF_DISPOSE_SHIFT) & GIF_DISPOSE_MASK;
141 break;
142 }
143 case APPLICATION_EXT_FUNC_CODE:
144 {
145 if (size == sizeof(szNetscape20ext)
146 && memcmp(pExtension, szNetscape20ext, size) == 0) {
147 int iSubCode;
148
149 if (++i >= image->ExtensionBlockCount)
150 break;
151 pExtension = (byte_t *) image->ExtensionBlocks[i].Bytes;
152 if (image->ExtensionBlocks[i].ByteCount != 3)
153 break;
154 iSubCode = pExtension[0] & 0x07;
155 if (iSubCode == NSEXT_LOOP) {
156 splash->loopCount =
157 (pExtension[1] | (pExtension[2] << 8)) - 1;
158 }
159 }
160 break;
161 }
162 default:
163 break;
164 }
165 }
166
167 if (colorMap) {
168 for (i = 0; i < colorCount; i++) {
169 colorMapBuf[i] = MAKE_QUAD_GIF(colorMap->Colors[i], 0xff);
170 }
171 }
172 {
173
174 byte_t *pSrc = image->RasterBits;
175 ImageFormat srcFormat;
176 ImageRect srcRect, dstRect;
177 int pass, npass;
178
179 if (desc->Interlace) {
180 pass = 0;
181 npass = 4;
182 }
183 else {
184 pass = 4;
185 npass = 5;
186 }
187
188 srcFormat.colorMap = colorMapBuf;
189 srcFormat.depthBytes = 1;
190 srcFormat.byteOrder = BYTE_ORDER_NATIVE;
191 srcFormat.transparentColor = transparentColor;
192 srcFormat.fixedBits = QUAD_ALPHA_MASK; // fixed 100% alpha
193 srcFormat.premultiplied = 0;
194
195 for (; pass < npass; ++pass) {
196 int jump = interlacedJumps[pass];
197 int ofs = interlacedOffset[pass];
198 int numLines = (desc->Height + jump - 1 - ofs) / jump;
199
200 initRect(&srcRect, 0, 0, desc->Width, numLines, 1,
201 desc->Width, pSrc, &srcFormat);
202 initRect(&dstRect, desc->Left, desc->Top + ofs, desc->Width,
203 numLines, jump, stride, pBitmapBits, &splash->imageFormat);
204 pSrc += convertRect(&srcRect, &dstRect, CVT_ALPHATEST);
205 }
206 }
207
208 // now dispose of the previous frame correctly
209
210 splash->frames[imageIndex].bitmapBits =
211 (rgbquad_t *) malloc(bufferSize);
212 memcpy(splash->frames[imageIndex].bitmapBits, pBitmapBits, bufferSize);
213
214 SplashInitFrameShape(splash, imageIndex);
215
216 splash->frames[imageIndex].delay = frameDelay * 10; // 100ths of second to milliseconds
217 switch (disposeMethod) {
218 case GIF_DISPOSE_LEAVE:
219 memcpy(pOldBitmapBits, pBitmapBits, bufferSize);
220 break;
221 case GIF_DISPOSE_NONE:
222 break;
223 case GIF_DISPOSE_BACKGND:
224 {
225 ImageRect dstRect;
226 rgbquad_t fillColor = 0; // 0 is transparent
227 if (transparentColor < 0) {
228 fillColor= MAKE_QUAD_GIF(
229 colorMap->Colors[gif->SBackGroundColor], 0xff);
230 }
231 initRect(&dstRect, desc->Left, desc->Top,
232 desc->Width, desc->Height, 1, stride,
233 pBitmapBits, &splash->imageFormat);
234 fillRect(fillColor, &dstRect);
235 }
236 break;
237 case GIF_DISPOSE_RESTORE:
238 {
239
240 int lineSize = desc->Width * splash->imageFormat.depthBytes;
241
242 for (j = 0; j < desc->Height; j++) {
243 int lineIndex = stride * (j + desc->Top) +
244 desc->Left * splash->imageFormat.depthBytes;
245
246 memcpy(pBitmapBits + lineIndex, pOldBitmapBits + lineIndex,
247 lineSize);
248 }
249 }
250 break;
251 }
252 }
253
254 free(pBitmapBits);
255 free(pOldBitmapBits);
256
257 DGifCloseFile(gif);
258
259 return 1;
260}
261
262int
263SplashDecodeGifStream(Splash * splash, SplashStream * stream)
264{
265 GifFileType *gif = DGifOpen((void *) stream, SplashStreamGifInputFunc);
266
267 if (!gif)
268 return 0;
269 return SplashDecodeGif(splash, gif);
270}