11cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
21cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger/*
31cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Copyright 2006 The Android Open Source Project
41cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger *
51cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
61cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger * found in the LICENSE file.
71cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger */
81cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkImageDecoder.h"
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColor.h"
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h"
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkStream.h"
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTemplates.h"
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkPackBits.h"
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "gif_lib.h"
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkGIFImageDecoder : public SkImageDecoder {
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    virtual Format getFormat() const {
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return kGIF_Format;
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected:
260a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic const uint8_t gStartingIterlaceYValue[] = {
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    0, 4, 2, 1
310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic const uint8_t gDeltaIterlaceYValue[] = {
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    8, 8, 4, 2
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*  Implement the GIF interlace algorithm in an iterator.
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    1) grab every 8th line beginning at 0
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    2) grab every 8th line beginning at 4
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    3) grab every 4th line beginning at 2
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    4) grab every 2nd line beginning at 1
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass GifInterlaceIter {
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    GifInterlaceIter(int height) : fHeight(height) {
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fStartYPtr = gStartingIterlaceYValue;
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fDeltaYPtr = gDeltaIterlaceYValue;
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fCurrY = *fStartYPtr++;
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fDeltaY = *fDeltaYPtr++;
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int currY() const {
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(fStartYPtr);
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(fDeltaYPtr);
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return fCurrY;
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void next() {
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(fStartYPtr);
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkASSERT(fDeltaYPtr);
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int y = fCurrY + fDeltaY;
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // We went from an if statement to a while loop so that we iterate
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // through fStartYPtr until a valid row is found. This is so that images
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // that are smaller than 5x5 will not trash memory.
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        while (y >= fHeight) {
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (gStartingIterlaceYValue +
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SK_ARRAY_COUNT(gStartingIterlaceYValue) == fStartYPtr) {
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // we done
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDEBUGCODE(fStartYPtr = NULL;)
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkDEBUGCODE(fDeltaYPtr = NULL;)
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                y = 0;
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } else {
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                y = *fStartYPtr++;
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fDeltaY = *fDeltaYPtr++;
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        fCurrY = y;
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const int fHeight;
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int fCurrY;
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int fDeltaY;
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t* fStartYPtr;
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint8_t* fDeltaYPtr;
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//#define GIF_STAMP       "GIF"    /* First chars in file - GIF stamp. */
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//#define GIF_STAMP_LEN   (sizeof(GIF_STAMP) - 1)
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int DecodeCallBackProc(GifFileType* fileType, GifByteType* out,
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              int size) {
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkStream* stream = (SkStream*) fileType->UserData;
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return (int) stream->read(out, size);
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectvoid CheckFreeExtension(SavedImage* Image) {
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (Image->ExtensionBlocks) {
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        FreeExtension(Image);
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// return NULL on failure
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic const ColorMapObject* find_colormap(const GifFileType* gif) {
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const ColorMapObject* cmap = gif->Image.ColorMap;
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL == cmap) {
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        cmap = gif->SColorMap;
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
112adc53e42d2aba7cd06ace07858049b6e17454e08Fredrik Lanker
113adc53e42d2aba7cd06ace07858049b6e17454e08Fredrik Lanker    if (NULL == cmap) {
114adc53e42d2aba7cd06ace07858049b6e17454e08Fredrik Lanker        // no colormap found
115adc53e42d2aba7cd06ace07858049b6e17454e08Fredrik Lanker        return NULL;
116adc53e42d2aba7cd06ace07858049b6e17454e08Fredrik Lanker    }
1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // some sanity checks
118f43ecde805dd6f15f555afcc523c1f36df0f4897Mike Reed    if (cmap && ((unsigned)cmap->ColorCount > 256 ||
119f43ecde805dd6f15f555afcc523c1f36df0f4897Mike Reed                 cmap->ColorCount != (1 << cmap->BitsPerPixel))) {
1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        cmap = NULL;
1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return cmap;
1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// return -1 if not found (i.e. we're completely opaque)
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int find_transpIndex(const SavedImage& image, int colorCount) {
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int transpIndex = -1;
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < image.ExtensionBlockCount; ++i) {
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const ExtensionBlock* eb = image.ExtensionBlocks + i;
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (eb->Function == 0xF9 && eb->ByteCount == 4) {
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (eb->Bytes[0] & 1) {
1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                transpIndex = (unsigned char)eb->Bytes[3];
1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // check for valid transpIndex
1340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (transpIndex >= colorCount) {
1350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    transpIndex = -1;
1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return transpIndex;
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool error_return(GifFileType* gif, const SkBitmap& bm,
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                         const char msg[]) {
1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0
1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDebugf("libgif error <%s> bitmap [%d %d] pixels %p colortable %p\n",
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project             msg, bm.width(), bm.height(), bm.getPixels(), bm.getColorTable());
1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return false;
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1530a81c953145c77abea5ca1df9e84c62d9da96094Mike Reedbool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) {
1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc);
1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL == gif) {
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return error_return(gif, *bm, "DGifOpen");
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoTCallIProc<GifFileType, DGifCloseFile> acp(gif);
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SavedImage temp_save;
1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    temp_save.ExtensionBlocks=NULL;
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    temp_save.ExtensionBlockCount=0;
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoTCallVProc<SavedImage, CheckFreeExtension> acp2(&temp_save);
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int width, height;
1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    GifRecordType recType;
1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    GifByteType *extData;
169eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed    int transpIndex = -1;   // -1 means we don't have it (yet)
1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    do {
1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (DGifGetRecordType(gif, &recType) == GIF_ERROR) {
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return error_return(gif, *bm, "DGifGetRecordType");
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        switch (recType) {
1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case IMAGE_DESC_RECORD_TYPE: {
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (DGifGetImageDesc(gif) == GIF_ERROR) {
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return error_return(gif, *bm, "IMAGE_DESC_RECORD_TYPE");
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (gif->ImageCount < 1) {    // sanity check
1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return error_return(gif, *bm, "ImageCount < 1");
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            width = gif->SWidth;
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            height = gif->SHeight;
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (width <= 0 || height <= 0 ||
1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                !this->chooseFromOneChoice(SkBitmap::kIndex8_Config,
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                           width, height)) {
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return error_return(gif, *bm, "chooseFromOneChoice");
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
194c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase            if (SkImageDecoder::kDecodeBounds_Mode == mode) {
195c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase                bm->setConfig(SkBitmap::kIndex8_Config, width, height);
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return true;
197c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase            }
198c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase#ifdef SK_BUILD_FOR_ANDROID
199c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase            // No Bitmap reuse supported for this format
200c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase            if (!bm->isNull()) {
201c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase                return false;
202c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase            }
203c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase#endif
2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
205c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase            bm->setConfig(SkBitmap::kIndex8_Config, width, height);
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SavedImage* image = &gif->SavedImages[gif->ImageCount-1];
2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const GifImageDesc& desc = image->ImageDesc;
2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // check for valid descriptor
2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (   (desc.Top | desc.Left) < 0 ||
2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    desc.Left + desc.Width > width ||
2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    desc.Top + desc.Height > height) {
2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return error_return(gif, *bm, "TopLeft");
2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // now we decode the colortable
2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int colorCount = 0;
2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            {
2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                const ColorMapObject* cmap = find_colormap(gif);
2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (NULL == cmap) {
2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    return error_return(gif, *bm, "null cmap");
2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                colorCount = cmap->ColorCount;
2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkColorTable* ctable = SkNEW_ARGS(SkColorTable, (colorCount));
2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkPMColor* colorPtr = ctable->lockColors();
2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                for (int index = 0; index < colorCount; index++)
2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    colorPtr[index] = SkPackARGB32(0xFF,
2290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                                   cmap->Colors[index].Red,
2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                                   cmap->Colors[index].Green,
2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                                   cmap->Colors[index].Blue);
2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
233eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed                transpIndex = find_transpIndex(temp_save, colorCount);
2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (transpIndex < 0)
2350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    ctable->setFlags(ctable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
2360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                else
2370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    colorPtr[transpIndex] = 0; // ram in a transparent SkPMColor
2380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                ctable->unlockColors(true);
2390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                SkAutoUnref aurts(ctable);
2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (!this->allocPixelRef(bm, ctable)) {
2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    return error_return(gif, *bm, "allocPixelRef");
2430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
2440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkAutoLockPixels alp(*bm);
2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // time to decode the scanlines
2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            //
2500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            uint8_t*  scanline = bm->getAddr8(0, 0);
2510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int rowBytes = bm->rowBytes();
2520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int innerWidth = desc.Width;
2530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int innerHeight = desc.Height;
2540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // abort if either inner dimension is <= 0
2560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (innerWidth <= 0 || innerHeight <= 0) {
2570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return error_return(gif, *bm, "non-pos inner width/height");
2580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // are we only a subset of the total bounds?
2610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if ((desc.Top | desc.Left) > 0 ||
2620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                 innerWidth < width || innerHeight < height)
2630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            {
264eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed                int fill;
265eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed                if (transpIndex >= 0) {
266eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed                    fill = transpIndex;
267eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed                } else {
268eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed                    fill = gif->SBackGroundColor;
269eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed                }
2700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // check for valid fill index/color
271eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed                if (static_cast<unsigned>(fill) >=
272eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed                        static_cast<unsigned>(colorCount)) {
2730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    fill = 0;
2740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
275eba9f316916f3381d6a5dd5c1300fea6ec6da8dcMike Reed                memset(scanline, fill, bm->getSize());
2760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // bump our starting address
2770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                scanline += desc.Top * rowBytes + desc.Left;
2780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // now decode each scanline
2810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (gif->Image.Interlace)
2820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            {
2830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                GifInterlaceIter iter(innerHeight);
2840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                for (int y = 0; y < innerHeight; y++)
2850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                {
2860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    uint8_t* row = scanline + iter.currY() * rowBytes;
2870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    if (DGifGetLine(gif, row, innerWidth) == GIF_ERROR) {
2880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        return error_return(gif, *bm, "interlace DGifGetLine");
2890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    }
2900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    iter.next();
2910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
2920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            else
2940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            {
2950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                // easy, non-interlace case
2960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                for (int y = 0; y < innerHeight; y++) {
2970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    if (DGifGetLine(gif, scanline, innerWidth) == GIF_ERROR) {
2980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        return error_return(gif, *bm, "DGifGetLine");
2990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    }
3000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    scanline += rowBytes;
3010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
3020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            goto DONE;
3040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } break;
3050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case EXTENSION_RECORD_TYPE:
3070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (DGifGetExtension(gif, &temp_save.Function,
3080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                 &extData) == GIF_ERROR) {
3090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                return error_return(gif, *bm, "DGifGetExtension");
3100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            while (extData != NULL) {
3130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                /* Create an extension block with our data */
3140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (AddExtensionBlock(&temp_save, extData[0],
3150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                      &extData[1]) == GIF_ERROR) {
3160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    return error_return(gif, *bm, "AddExtensionBlock");
3170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
3180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (DGifGetExtensionNext(gif, &extData) == GIF_ERROR) {
3190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    return error_return(gif, *bm, "DGifGetExtensionNext");
3200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
3210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                temp_save.Function = 0;
3220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
3230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
3240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case TERMINATE_RECORD_TYPE:
3260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
3270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        default:	/* Should be trapped by DGifGetRecordType */
3290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
3300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } while (recType != TERMINATE_RECORD_TYPE);
3320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectDONE:
3340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
3350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
3380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTRegistry.h"
3400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkImageDecoder* Factory(SkStream* stream) {
3420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    char buf[GIF_STAMP_LEN];
3430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
3440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (memcmp(GIF_STAMP,   buf, GIF_STAMP_LEN) == 0 ||
3450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 ||
3460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) {
3470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return SkNEW(SkGIFImageDecoder);
3480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return NULL;
3510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkTRegistry<SkImageDecoder*, SkStream*> gReg(Factory);
354