/src/share/native/sun/awt/splashscreen/splashscreen_gif.c
C | 324 lines | 236 code | 46 blank | 42 comment | 39 complexity | c743ad0de0d9d8cb493477d7bd1f3096 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause-No-Nuclear-License-2014, LGPL-3.0
- /*
- * Copyright (c) 2005, 2010, 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 "../giflib/gif_lib.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 *)
- 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);
- 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);
- }