PageRenderTime 105ms CodeModel.GetById 40ms app.highlight 25ms RepoModel.GetById 34ms app.codeStats 1ms

/src/share/native/sun/awt/splashscreen/splashscreen_gif.c

https://bitbucket.org/hamishm/haiku-jdk-jdk
C | 324 lines | 236 code | 46 blank | 42 comment | 39 complexity | c743ad0de0d9d8cb493477d7bd1f3096 MD5 | raw file
  1/*
  2 * Copyright (c) 2005, 2010, 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 "../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, (unsigned)(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
 65/* These macro help to ensure that we only take part of frame that fits into
 66   logical screen. */
 67
 68/* Ensure that p belongs to [pmin, pmax) interval. Returns fixed point (if fix is needed) */
 69#define FIX_POINT(p, pmin, pmax) ( ((p) < (pmin)) ? (pmin) : (((p) > (pmax)) ? (pmax) : (p)))
 70/* Ensures that line starting at point p does not exceed boundary pmax.
 71   Returns fixed length (if fix is needed) */
 72#define FIX_LENGTH(p, len, pmax) ( ((p) + (len)) > (pmax) ? ((pmax) - (p)) : (len))
 73
 74int
 75SplashDecodeGif(Splash * splash, GifFileType * gif)
 76{
 77    int stride;
 78    int bufferSize;
 79    byte_t *pBitmapBits, *pOldBitmapBits;
 80    int i, j;
 81    int imageIndex;
 82    int cx, cy, cw, ch; /* clamped coordinates */
 83    const int interlacedOffset[] = { 0, 4, 2, 1, 0 };   /* The way Interlaced image should. */
 84    const int interlacedJumps[] = { 8, 8, 4, 2, 1 };    /* be read - offsets and jumps... */
 85
 86    if (DGifSlurp(gif) == GIF_ERROR) {
 87        return 0;
 88    }
 89
 90    SplashCleanup(splash);
 91
 92    if (!SAFE_TO_ALLOC(gif->SWidth, splash->imageFormat.depthBytes)) {
 93        return 0;
 94    }
 95    stride = gif->SWidth * splash->imageFormat.depthBytes;
 96    if (splash->byteAlignment > 1)
 97        stride =
 98            (stride + splash->byteAlignment - 1) & ~(splash->byteAlignment - 1);
 99
100    if (!SAFE_TO_ALLOC(gif->SHeight, stride)) {
101        return 0;
102    }
103
104    if (!SAFE_TO_ALLOC(gif->ImageCount, sizeof(SplashImage*))) {
105        return 0;
106    }
107    bufferSize = stride * gif->SHeight;
108    pBitmapBits = (byte_t *) malloc(bufferSize);
109    if (!pBitmapBits) {
110        return 0;
111    }
112    pOldBitmapBits = (byte_t *) malloc(bufferSize);
113    if (!pOldBitmapBits) {
114        free(pBitmapBits);
115        return 0;
116    }
117    memset(pBitmapBits, 0, bufferSize);
118
119    splash->width = gif->SWidth;
120    splash->height = gif->SHeight;
121    splash->frameCount = gif->ImageCount;
122    splash->frames = (SplashImage *)
123        malloc(sizeof(SplashImage) * gif->ImageCount);
124    if (!splash->frames) {
125      free(pBitmapBits);
126      free(pOldBitmapBits);
127      return 0;
128    }
129    memset(splash->frames, 0, sizeof(SplashImage) * gif->ImageCount);
130    splash->loopCount = 1;
131
132    for (imageIndex = 0; imageIndex < gif->ImageCount; imageIndex++) {
133        SavedImage *image = &(gif->SavedImages[imageIndex]);
134        GifImageDesc *desc = &(image->ImageDesc);
135        ColorMapObject *colorMap =
136            desc->ColorMap ? desc->ColorMap : gif->SColorMap;
137
138        int transparentColor = -1;
139        int frameDelay = 100;
140        int disposeMethod = GIF_DISPOSE_RESTORE;
141        int colorCount = 0;
142        rgbquad_t colorMapBuf[SPLASH_COLOR_MAP_SIZE];
143
144        cx = FIX_POINT(desc->Left, 0, gif->SWidth);
145        cy = FIX_POINT(desc->Top, 0, gif->SHeight);
146        cw = FIX_LENGTH(desc->Left, desc->Width, gif->SWidth);
147        ch = FIX_LENGTH(desc->Top, desc->Height, gif->SHeight);
148
149        if (colorMap) {
150            if (colorMap->ColorCount <= SPLASH_COLOR_MAP_SIZE) {
151                colorCount = colorMap->ColorCount;
152            } else  {
153                colorCount = SPLASH_COLOR_MAP_SIZE;
154            }
155        }
156
157        /* the code below is loosely based around gif extension processing from win32 libungif sample */
158
159        for (i = 0; i < image->ExtensionBlockCount; i++) {
160            byte_t *pExtension = (byte_t *) image->ExtensionBlocks[i].Bytes;
161            unsigned size = image->ExtensionBlocks[i].ByteCount;
162
163            switch (image->ExtensionBlocks[i].Function) {
164            case GRAPHICS_EXT_FUNC_CODE:
165                {
166                    int flag = pExtension[0];
167
168                    frameDelay = (((int)pExtension[2]) << 8) | pExtension[1];
169                    if (frameDelay < 10)
170                        frameDelay = 10;
171                    if (flag & GIF_TRANSPARENT) {
172                        transparentColor = pExtension[3];
173                    } else {
174                        transparentColor = GIF_NOT_TRANSPARENT;
175                    }
176                    disposeMethod =
177                        (flag >> GIF_DISPOSE_SHIFT) & GIF_DISPOSE_MASK;
178                    break;
179                }
180            case APPLICATION_EXT_FUNC_CODE:
181                {
182                    if (size == sizeof(szNetscape20ext)
183                        && memcmp(pExtension, szNetscape20ext, size) == 0) {
184                        int iSubCode;
185
186                        if (++i >= image->ExtensionBlockCount)
187                            break;
188                        pExtension = (byte_t *) image->ExtensionBlocks[i].Bytes;
189                        if (image->ExtensionBlocks[i].ByteCount != 3)
190                            break;
191                        iSubCode = pExtension[0] & 0x07;
192                        if (iSubCode == NSEXT_LOOP) {
193                            splash->loopCount =
194                                (pExtension[1] | (((int)pExtension[2]) << 8)) - 1;
195                        }
196                    }
197                    break;
198                }
199            default:
200                break;
201            }
202        }
203
204        if (colorMap) {
205            for (i = 0; i < colorCount; i++) {
206                colorMapBuf[i] = MAKE_QUAD_GIF(colorMap->Colors[i], 0xff);
207            }
208        }
209        {
210
211            byte_t *pSrc = image->RasterBits;
212            ImageFormat srcFormat;
213            ImageRect srcRect, dstRect;
214            int pass, npass;
215
216            if (desc->Interlace) {
217                pass = 0;
218                npass = 4;
219            }
220            else {
221                pass = 4;
222                npass = 5;
223            }
224
225            srcFormat.colorMap = colorMapBuf;
226            srcFormat.depthBytes = 1;
227            srcFormat.byteOrder = BYTE_ORDER_NATIVE;
228            srcFormat.transparentColor = transparentColor;
229            srcFormat.fixedBits = QUAD_ALPHA_MASK;      // fixed 100% alpha
230            srcFormat.premultiplied = 0;
231
232            for (; pass < npass; ++pass) {
233                int jump = interlacedJumps[pass];
234                int ofs = interlacedOffset[pass];
235                /* Number of source lines for current pass */
236                int numPassLines = (desc->Height + jump - ofs - 1) / jump;
237                /* Number of lines that fits to dest buffer */
238                int numLines = (ch + jump - ofs - 1) / jump;
239
240                initRect(&srcRect, 0, 0, desc->Width, numLines, 1,
241                    desc->Width, pSrc, &srcFormat);
242
243                if (numLines > 0) {
244                    initRect(&dstRect, cx, cy + ofs, cw,
245                             numLines , jump, stride, pBitmapBits, &splash->imageFormat);
246
247                    pSrc += convertRect(&srcRect, &dstRect, CVT_ALPHATEST);
248                }
249                // skip extra source data
250                pSrc += (numPassLines - numLines) * srcRect.stride;
251            }
252        }
253
254        // now dispose of the previous frame correctly
255
256        splash->frames[imageIndex].bitmapBits =
257            (rgbquad_t *) malloc(bufferSize);
258        if (!splash->frames[imageIndex].bitmapBits) {
259            free(pBitmapBits);
260            free(pOldBitmapBits);
261            /* Assuming that callee will take care of splash frames we have already allocated */
262            return 0;
263        }
264        memcpy(splash->frames[imageIndex].bitmapBits, pBitmapBits, bufferSize);
265
266        SplashInitFrameShape(splash, imageIndex);
267
268        splash->frames[imageIndex].delay = frameDelay * 10;     // 100ths of second to milliseconds
269        switch (disposeMethod) {
270        case GIF_DISPOSE_LEAVE:
271            memcpy(pOldBitmapBits, pBitmapBits, bufferSize);
272            break;
273        case GIF_DISPOSE_NONE:
274            break;
275        case GIF_DISPOSE_BACKGND:
276            {
277                ImageRect dstRect;
278                rgbquad_t fillColor = 0;                        // 0 is transparent
279
280                if (transparentColor < 0) {
281                    fillColor= MAKE_QUAD_GIF(
282                        colorMap->Colors[gif->SBackGroundColor], 0xff);
283                }
284                initRect(&dstRect,
285                         cx, cy, cw, ch,
286                         1, stride,
287                         pBitmapBits, &splash->imageFormat);
288                fillRect(fillColor, &dstRect);
289            }
290            break;
291        case GIF_DISPOSE_RESTORE:
292            {
293                int lineSize = cw * splash->imageFormat.depthBytes;
294                if (lineSize > 0) {
295                    int lineOffset = cx * splash->imageFormat.depthBytes;
296                    int lineIndex = cy * stride + lineOffset;
297                    for (j=0; j<ch; j++) {
298                        memcpy(pBitmapBits + lineIndex, pOldBitmapBits + lineIndex,
299                               lineSize);
300                        lineIndex += stride;
301                    }
302                }
303            }
304            break;
305        }
306    }
307
308    free(pBitmapBits);
309    free(pOldBitmapBits);
310
311    DGifCloseFile(gif);
312
313    return 1;
314}
315
316int
317SplashDecodeGifStream(Splash * splash, SplashStream * stream)
318{
319    GifFileType *gif = DGifOpen((void *) stream, SplashStreamGifInputFunc);
320
321    if (!gif)
322        return 0;
323    return SplashDecodeGif(splash, gif);
324}