jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_gif.c
changeset 25859 3317bb8137f4
parent 23010 6dadb192ad81
child 30496 aac453851104
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.desktop/share/native/libsplashscreen/splashscreen_gif.c	Sun Aug 17 15:54:13 2014 +0100
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "splashscreen_impl.h"
+#include "splashscreen_gfx.h"
+
+#include <gif_lib.h>
+
+#include "sizecalc.h"
+
+#define GIF_TRANSPARENT     0x01
+#define GIF_USER_INPUT      0x02
+#define GIF_DISPOSE_MASK    0x07
+#define GIF_DISPOSE_SHIFT   2
+
+#define GIF_NOT_TRANSPARENT -1
+
+#define GIF_DISPOSE_NONE    0   // No disposal specified. The decoder is
+                                // not required to take any action.
+#define GIF_DISPOSE_LEAVE   1   // Do not dispose. The graphic is to be left
+                                // in place.
+#define GIF_DISPOSE_BACKGND 2   // Restore to background color. The area used by the
+                                // graphic must be restored to the background color.
+
+#define GIF_DISPOSE_RESTORE 3   // Restore to previous. The decoder is required to
+                                // restore the area overwritten by the graphic with
+                                // what was there prior to rendering the graphic.
+
+static const char szNetscape20ext[11] = "NETSCAPE2.0";
+
+#define NSEXT_LOOP      0x01    // Loop Count field code
+
+// convert libungif samples to our ones
+#define MAKE_QUAD_GIF(c,a) MAKE_QUAD((c).Red, (c).Green, (c).Blue, (unsigned)(a))
+
+/* stdio FILE* and memory input functions for libungif */
+int
+SplashStreamGifInputFunc(GifFileType * gif, GifByteType * buf, int n)
+{
+    SplashStream* io = (SplashStream*)gif->UserData;
+    int rc = io->read(io, buf, n);
+    return rc;
+}
+
+/* These macro help to ensure that we only take part of frame that fits into
+   logical screen. */
+
+/* Ensure that p belongs to [pmin, pmax) interval. Returns fixed point (if fix is needed) */
+#define FIX_POINT(p, pmin, pmax) ( ((p) < (pmin)) ? (pmin) : (((p) > (pmax)) ? (pmax) : (p)))
+/* Ensures that line starting at point p does not exceed boundary pmax.
+   Returns fixed length (if fix is needed) */
+#define FIX_LENGTH(p, len, pmax) ( ((p) + (len)) > (pmax) ? ((pmax) - (p)) : (len))
+
+int
+SplashDecodeGif(Splash * splash, GifFileType * gif)
+{
+    int stride;
+    int bufferSize;
+    byte_t *pBitmapBits, *pOldBitmapBits;
+    int i, j;
+    int imageIndex;
+    int cx, cy, cw, ch; /* clamped coordinates */
+    const int interlacedOffset[] = { 0, 4, 2, 1, 0 };   /* The way Interlaced image should. */
+    const int interlacedJumps[] = { 8, 8, 4, 2, 1 };    /* be read - offsets and jumps... */
+
+    if (DGifSlurp(gif) == GIF_ERROR) {
+        return 0;
+    }
+
+    SplashCleanup(splash);
+
+    if (!SAFE_TO_ALLOC(gif->SWidth, splash->imageFormat.depthBytes)) {
+        return 0;
+    }
+    stride = gif->SWidth * splash->imageFormat.depthBytes;
+    if (splash->byteAlignment > 1)
+        stride =
+            (stride + splash->byteAlignment - 1) & ~(splash->byteAlignment - 1);
+
+    if (!SAFE_TO_ALLOC(gif->SHeight, stride)) {
+        return 0;
+    }
+
+    if (!SAFE_TO_ALLOC(gif->ImageCount, sizeof(SplashImage*))) {
+        return 0;
+    }
+    bufferSize = stride * gif->SHeight;
+    pBitmapBits = (byte_t *) malloc(bufferSize);
+    if (!pBitmapBits) {
+        return 0;
+    }
+    pOldBitmapBits = (byte_t *) malloc(bufferSize);
+    if (!pOldBitmapBits) {
+        free(pBitmapBits);
+        return 0;
+    }
+    memset(pBitmapBits, 0, bufferSize);
+
+    splash->width = gif->SWidth;
+    splash->height = gif->SHeight;
+    splash->frameCount = gif->ImageCount;
+    splash->frames = (SplashImage *)
+        SAFE_SIZE_ARRAY_ALLOC(malloc, sizeof(SplashImage), gif->ImageCount);
+    if (!splash->frames) {
+      free(pBitmapBits);
+      free(pOldBitmapBits);
+      return 0;
+    }
+    memset(splash->frames, 0, sizeof(SplashImage) * gif->ImageCount);
+    splash->loopCount = 1;
+
+    for (imageIndex = 0; imageIndex < gif->ImageCount; imageIndex++) {
+        SavedImage *image = &(gif->SavedImages[imageIndex]);
+        GifImageDesc *desc = &(image->ImageDesc);
+        ColorMapObject *colorMap =
+            desc->ColorMap ? desc->ColorMap : gif->SColorMap;
+
+        int transparentColor = -1;
+        int frameDelay = 100;
+        int disposeMethod = GIF_DISPOSE_RESTORE;
+        int colorCount = 0;
+        rgbquad_t colorMapBuf[SPLASH_COLOR_MAP_SIZE];
+
+        cx = FIX_POINT(desc->Left, 0, gif->SWidth);
+        cy = FIX_POINT(desc->Top, 0, gif->SHeight);
+        cw = FIX_LENGTH(desc->Left, desc->Width, gif->SWidth);
+        ch = FIX_LENGTH(desc->Top, desc->Height, gif->SHeight);
+
+        if (colorMap) {
+            if (colorMap->ColorCount <= SPLASH_COLOR_MAP_SIZE) {
+                colorCount = colorMap->ColorCount;
+            } else  {
+                colorCount = SPLASH_COLOR_MAP_SIZE;
+            }
+        }
+
+        /* the code below is loosely based around gif extension processing from win32 libungif sample */
+
+        for (i = 0; i < image->ExtensionBlockCount; i++) {
+            byte_t *pExtension = (byte_t *) image->ExtensionBlocks[i].Bytes;
+            unsigned size = image->ExtensionBlocks[i].ByteCount;
+
+            switch (image->ExtensionBlocks[i].Function) {
+            case GRAPHICS_EXT_FUNC_CODE:
+                {
+                    int flag = pExtension[0];
+
+                    frameDelay = (((int)pExtension[2]) << 8) | pExtension[1];
+                    if (frameDelay < 10)
+                        frameDelay = 10;
+                    if (flag & GIF_TRANSPARENT) {
+                        transparentColor = pExtension[3];
+                    } else {
+                        transparentColor = GIF_NOT_TRANSPARENT;
+                    }
+                    disposeMethod =
+                        (flag >> GIF_DISPOSE_SHIFT) & GIF_DISPOSE_MASK;
+                    break;
+                }
+            case APPLICATION_EXT_FUNC_CODE:
+                {
+                    if (size == sizeof(szNetscape20ext)
+                        && memcmp(pExtension, szNetscape20ext, size) == 0) {
+                        int iSubCode;
+
+                        if (++i >= image->ExtensionBlockCount)
+                            break;
+                        pExtension = (byte_t *) image->ExtensionBlocks[i].Bytes;
+                        if (image->ExtensionBlocks[i].ByteCount != 3)
+                            break;
+                        iSubCode = pExtension[0] & 0x07;
+                        if (iSubCode == NSEXT_LOOP) {
+                            splash->loopCount =
+                                (pExtension[1] | (((int)pExtension[2]) << 8)) - 1;
+                        }
+                    }
+                    break;
+                }
+            default:
+                break;
+            }
+        }
+
+        if (colorMap) {
+            for (i = 0; i < colorCount; i++) {
+                colorMapBuf[i] = MAKE_QUAD_GIF(colorMap->Colors[i], 0xff);
+            }
+        }
+        {
+
+            byte_t *pSrc = image->RasterBits;
+            ImageFormat srcFormat;
+            ImageRect srcRect, dstRect;
+            int pass, npass;
+
+            if (desc->Interlace) {
+                pass = 0;
+                npass = 4;
+            }
+            else {
+                pass = 4;
+                npass = 5;
+            }
+
+            srcFormat.colorMap = colorMapBuf;
+            srcFormat.depthBytes = 1;
+            srcFormat.byteOrder = BYTE_ORDER_NATIVE;
+            srcFormat.transparentColor = transparentColor;
+            srcFormat.fixedBits = QUAD_ALPHA_MASK;      // fixed 100% alpha
+            srcFormat.premultiplied = 0;
+
+            for (; pass < npass; ++pass) {
+                int jump = interlacedJumps[pass];
+                int ofs = interlacedOffset[pass];
+                /* Number of source lines for current pass */
+                int numPassLines = (desc->Height + jump - ofs - 1) / jump;
+                /* Number of lines that fits to dest buffer */
+                int numLines = (ch + jump - ofs - 1) / jump;
+
+                initRect(&srcRect, 0, 0, desc->Width, numLines, 1,
+                    desc->Width, pSrc, &srcFormat);
+
+                if (numLines > 0) {
+                    initRect(&dstRect, cx, cy + ofs, cw,
+                             numLines , jump, stride, pBitmapBits, &splash->imageFormat);
+
+                    pSrc += convertRect(&srcRect, &dstRect, CVT_ALPHATEST);
+                }
+                // skip extra source data
+                pSrc += (numPassLines - numLines) * srcRect.stride;
+            }
+        }
+
+        // now dispose of the previous frame correctly
+
+        splash->frames[imageIndex].bitmapBits =
+            (rgbquad_t *) malloc(bufferSize); // bufferSize is safe (checked above)
+        if (!splash->frames[imageIndex].bitmapBits) {
+            free(pBitmapBits);
+            free(pOldBitmapBits);
+            /* Assuming that callee will take care of splash frames we have already allocated */
+            return 0;
+        }
+        memcpy(splash->frames[imageIndex].bitmapBits, pBitmapBits, bufferSize);
+
+        SplashInitFrameShape(splash, imageIndex);
+
+        splash->frames[imageIndex].delay = frameDelay * 10;     // 100ths of second to milliseconds
+        switch (disposeMethod) {
+        case GIF_DISPOSE_LEAVE:
+            memcpy(pOldBitmapBits, pBitmapBits, bufferSize);
+            break;
+        case GIF_DISPOSE_NONE:
+            break;
+        case GIF_DISPOSE_BACKGND:
+            {
+                ImageRect dstRect;
+                rgbquad_t fillColor = 0;                        // 0 is transparent
+
+                if (transparentColor < 0) {
+                    fillColor= MAKE_QUAD_GIF(
+                        colorMap->Colors[gif->SBackGroundColor], 0xff);
+                }
+                initRect(&dstRect,
+                         cx, cy, cw, ch,
+                         1, stride,
+                         pBitmapBits, &splash->imageFormat);
+                fillRect(fillColor, &dstRect);
+            }
+            break;
+        case GIF_DISPOSE_RESTORE:
+            {
+                int lineSize = cw * splash->imageFormat.depthBytes;
+                if (lineSize > 0) {
+                    int lineOffset = cx * splash->imageFormat.depthBytes;
+                    int lineIndex = cy * stride + lineOffset;
+                    for (j=0; j<ch; j++) {
+                        memcpy(pBitmapBits + lineIndex, pOldBitmapBits + lineIndex,
+                               lineSize);
+                        lineIndex += stride;
+                    }
+                }
+            }
+            break;
+        }
+    }
+
+    free(pBitmapBits);
+    free(pOldBitmapBits);
+
+    DGifCloseFile(gif);
+
+    return 1;
+}
+
+int
+SplashDecodeGifStream(Splash * splash, SplashStream * stream)
+{
+    GifFileType *gif = DGifOpen((void *) stream, SplashStreamGifInputFunc);
+
+    if (!gif)
+        return 0;
+    return SplashDecodeGif(splash, gif);
+}