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