1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/* 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file. 7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */ 8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com 98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMovie.h" 118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColor.h" 128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkColorPriv.h" 138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkStream.h" 148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkTemplates.h" 1557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com#include "SkUtils.h" 168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "gif_lib.h" 188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SkGIFMovie : public SkMovie { 208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic: 218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkGIFMovie(SkStream* stream); 228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com virtual ~SkGIFMovie(); 238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprotected: 258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com virtual bool onGetInfo(Info*); 268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com virtual bool onSetTime(SkMSec); 278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com virtual bool onGetBitmap(SkBitmap*); 28d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com 298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate: 308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com GifFileType* fGIF; 3157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int fCurrIndex; 3257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int fLastDrawIndex; 3357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com SkBitmap fBackup; 348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}; 358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic int Decode(GifFileType* fileType, GifByteType* out, int size) { 378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkStream* stream = (SkStream*) fileType->UserData; 388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return (int) stream->read(out, size); 398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkGIFMovie::SkGIFMovie(SkStream* stream) 428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 43bb89613380332065a2abf71b8b229eabcf2c0be8reed@google.com#if GIFLIB_MAJOR < 5 448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fGIF = DGifOpen( stream, Decode ); 45bb89613380332065a2abf71b8b229eabcf2c0be8reed@google.com#else 46bb89613380332065a2abf71b8b229eabcf2c0be8reed@google.com fGIF = DGifOpen( stream, Decode, NULL ); 47bb89613380332065a2abf71b8b229eabcf2c0be8reed@google.com#endif 488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (NULL == fGIF) 498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return; 508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (DGifSlurp(fGIF) != GIF_OK) 528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com DGifCloseFile(fGIF); 548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com fGIF = NULL; 558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 5657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com fCurrIndex = -1; 5757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com fLastDrawIndex = -1; 588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkGIFMovie::~SkGIFMovie() 618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (fGIF) 638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com DGifCloseFile(fGIF); 648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic SkMSec savedimage_duration(const SavedImage* image) 678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int j = 0; j < image->ExtensionBlockCount; j++) 698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (image->ExtensionBlocks[j].Function == GRAPHICS_EXT_FUNC_CODE) 718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 72253ac10622c12df82e0d3955af9e4260ad62b2dereed@google.com SkASSERT(image->ExtensionBlocks[j].ByteCount >= 4); 738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const uint8_t* b = (const uint8_t*)image->ExtensionBlocks[j].Bytes; 748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return ((b[2] << 8) | b[1]) * 10; 758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return 0; 788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkGIFMovie::onGetInfo(Info* info) 818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (NULL == fGIF) 838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMSec dur = 0; 868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < fGIF->ImageCount; i++) 878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dur += savedimage_duration(&fGIF->SavedImages[i]); 888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com info->fDuration = dur; 908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com info->fWidth = fGIF->SWidth; 918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com info->fHeight = fGIF->SHeight; 928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com info->fIsOpaque = false; // how to compute? 938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkGIFMovie::onSetTime(SkMSec time) 978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (NULL == fGIF) 998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com SkMSec dur = 0; 1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com for (int i = 0; i < fGIF->ImageCount; i++) 1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com dur += savedimage_duration(&fGIF->SavedImages[i]); 1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (dur >= time) 1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com { 10757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com fCurrIndex = i; 10857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com return fLastDrawIndex != fCurrIndex; 1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 11157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com fCurrIndex = fGIF->ImageCount - 1; 1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 11557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comstatic void copyLine(uint32_t* dst, const unsigned char* src, const ColorMapObject* cmap, 11657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int transparent, int width) 11757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com{ 11857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com for (; width > 0; width--, src++, dst++) { 11957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (*src != transparent) { 12057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com const GifColorType& col = cmap->Colors[*src]; 12157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com *dst = SkPackARGB32(0xFF, col.Red, col.Green, col.Blue); 12257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 12357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 12457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com} 12557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 12629bf8625152c240311f851a8a0df3e543ed824c9djsollen@google.com#if GIFLIB_MAJOR < 5 12757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comstatic void copyInterlaceGroup(SkBitmap* bm, const unsigned char*& src, 12857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com const ColorMapObject* cmap, int transparent, int copyWidth, 12957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int copyHeight, const GifImageDesc& imageDesc, int rowStep, 13057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int startRow) 13157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com{ 13257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int row; 13357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // every 'rowStep'th row, starting with row 'startRow' 13457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com for (row = startRow; row < copyHeight; row += rowStep) { 13557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com uint32_t* dst = bm->getAddr32(imageDesc.Left, imageDesc.Top + row); 13657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyLine(dst, src, cmap, transparent, copyWidth); 13757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com src += imageDesc.Width; 13857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 13957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 14057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // pad for rest height 14157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com src += imageDesc.Width * ((imageDesc.Height - row + rowStep - 1) / rowStep); 14257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com} 14357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 14457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comstatic void blitInterlace(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap, 14557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int transparent) 14657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com{ 14757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int width = bm->width(); 14857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int height = bm->height(); 14957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com GifWord copyWidth = frame->ImageDesc.Width; 15057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (frame->ImageDesc.Left + copyWidth > width) { 15157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyWidth = width - frame->ImageDesc.Left; 15257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 15357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 15457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com GifWord copyHeight = frame->ImageDesc.Height; 15557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (frame->ImageDesc.Top + copyHeight > height) { 15657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyHeight = height - frame->ImageDesc.Top; 15757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 15857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 15957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // deinterlace 16057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com const unsigned char* src = (unsigned char*)frame->RasterBits; 16157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 16257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // group 1 - every 8th row, starting with row 0 16357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 0); 16457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 16557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // group 2 - every 8th row, starting with row 4 16657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 8, 4); 16757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 16857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // group 3 - every 4th row, starting with row 2 16957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 4, 2); 17057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 17157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyInterlaceGroup(bm, src, cmap, transparent, copyWidth, copyHeight, frame->ImageDesc, 2, 1); 17257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com} 17329bf8625152c240311f851a8a0df3e543ed824c9djsollen@google.com#endif 17457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 17557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comstatic void blitNormal(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap, 17657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int transparent) 17757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com{ 17857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int width = bm->width(); 17957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int height = bm->height(); 18057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com const unsigned char* src = (unsigned char*)frame->RasterBits; 18157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com uint32_t* dst = bm->getAddr32(frame->ImageDesc.Left, frame->ImageDesc.Top); 18257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com GifWord copyWidth = frame->ImageDesc.Width; 18357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (frame->ImageDesc.Left + copyWidth > width) { 18457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyWidth = width - frame->ImageDesc.Left; 18557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 18657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 18757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com GifWord copyHeight = frame->ImageDesc.Height; 18857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (frame->ImageDesc.Top + copyHeight > height) { 18957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyHeight = height - frame->ImageDesc.Top; 19057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 19157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 19257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com for (; copyHeight > 0; copyHeight--) { 19357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyLine(dst, src, cmap, transparent, copyWidth); 19457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com src += frame->ImageDesc.Width; 19557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com dst += width; 19657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 19757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com} 19857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 19957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comstatic void fillRect(SkBitmap* bm, GifWord left, GifWord top, GifWord width, GifWord height, 20057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com uint32_t col) 20157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com{ 20257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int bmWidth = bm->width(); 20357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int bmHeight = bm->height(); 20457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com uint32_t* dst = bm->getAddr32(left, top); 20557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com GifWord copyWidth = width; 20657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (left + copyWidth > bmWidth) { 20757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyWidth = bmWidth - left; 20857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 20957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 21057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com GifWord copyHeight = height; 21157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (top + copyHeight > bmHeight) { 21257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com copyHeight = bmHeight - top; 21357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 21457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 21557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com for (; copyHeight > 0; copyHeight--) { 21657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com sk_memset32(dst, col, copyWidth); 21757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com dst += bmWidth; 21857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 21957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com} 22057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 22157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comstatic void drawFrame(SkBitmap* bm, const SavedImage* frame, const ColorMapObject* cmap) 22257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com{ 22357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int transparent = -1; 22457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 22557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com for (int i = 0; i < frame->ExtensionBlockCount; ++i) { 22657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com ExtensionBlock* eb = frame->ExtensionBlocks + i; 22757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (eb->Function == GRAPHICS_EXT_FUNC_CODE && 22857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com eb->ByteCount == 4) { 22957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com bool has_transparency = ((eb->Bytes[0] & 1) == 1); 23057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (has_transparency) { 23157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com transparent = (unsigned char)eb->Bytes[3]; 23257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 23357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 23457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 23557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 23657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (frame->ImageDesc.ColorMap != NULL) { 23757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // use local color table 23857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com cmap = frame->ImageDesc.ColorMap; 23957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 24057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 24157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (cmap == NULL || cmap->ColorCount != (1 << cmap->BitsPerPixel)) { 2420c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com SkDEBUGFAIL("bad colortable setup"); 24357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com return; 24457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 24557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 24629bf8625152c240311f851a8a0df3e543ed824c9djsollen@google.com#if GIFLIB_MAJOR < 5 24729bf8625152c240311f851a8a0df3e543ed824c9djsollen@google.com // before GIFLIB 5, de-interlacing wasn't done by library at load time 24857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (frame->ImageDesc.Interlace) { 24957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com blitInterlace(bm, frame, cmap, transparent); 25029bf8625152c240311f851a8a0df3e543ed824c9djsollen@google.com return; 25157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 25229bf8625152c240311f851a8a0df3e543ed824c9djsollen@google.com#endif 25329bf8625152c240311f851a8a0df3e543ed824c9djsollen@google.com 25429bf8625152c240311f851a8a0df3e543ed824c9djsollen@google.com blitNormal(bm, frame, cmap, transparent); 25557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com} 25657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 25757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comstatic bool checkIfWillBeCleared(const SavedImage* frame) 25857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com{ 25957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com for (int i = 0; i < frame->ExtensionBlockCount; ++i) { 26057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com ExtensionBlock* eb = frame->ExtensionBlocks + i; 26157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (eb->Function == GRAPHICS_EXT_FUNC_CODE && 26257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com eb->ByteCount == 4) { 26357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // check disposal method 26457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int disposal = ((eb->Bytes[0] >> 2) & 7); 26557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (disposal == 2 || disposal == 3) { 26657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com return true; 26757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 26857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 26957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 27057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com return false; 27157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com} 27257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 27357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comstatic void getTransparencyAndDisposalMethod(const SavedImage* frame, bool* trans, int* disposal) 27457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com{ 27557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com *trans = false; 27657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com *disposal = 0; 27757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com for (int i = 0; i < frame->ExtensionBlockCount; ++i) { 27857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com ExtensionBlock* eb = frame->ExtensionBlocks + i; 27957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (eb->Function == GRAPHICS_EXT_FUNC_CODE && 28057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com eb->ByteCount == 4) { 28157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com *trans = ((eb->Bytes[0] & 1) == 1); 28257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com *disposal = ((eb->Bytes[0] >> 2) & 7); 28357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 28457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 28557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com} 28657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 28757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com// return true if area of 'target' is completely covers area of 'covered' 28857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comstatic bool checkIfCover(const SavedImage* target, const SavedImage* covered) 28957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com{ 29057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (target->ImageDesc.Left <= covered->ImageDesc.Left 29157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com && covered->ImageDesc.Left + covered->ImageDesc.Width <= 29257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com target->ImageDesc.Left + target->ImageDesc.Width 29357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com && target->ImageDesc.Top <= covered->ImageDesc.Top 29457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com && covered->ImageDesc.Top + covered->ImageDesc.Height <= 29557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com target->ImageDesc.Top + target->ImageDesc.Height) { 29657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com return true; 29757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 29857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com return false; 29957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com} 30057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 30157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.comstatic void disposeFrameIfNeeded(SkBitmap* bm, const SavedImage* cur, const SavedImage* next, 30257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com SkBitmap* backup, SkColor color) 30357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com{ 30457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // We can skip disposal process if next frame is not transparent 30557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // and completely covers current area 30657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com bool curTrans; 30757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int curDisposal; 30857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com getTransparencyAndDisposalMethod(cur, &curTrans, &curDisposal); 30957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com bool nextTrans; 31057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int nextDisposal; 31157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com getTransparencyAndDisposalMethod(next, &nextTrans, &nextDisposal); 31257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if ((curDisposal == 2 || curDisposal == 3) 31357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com && (nextTrans || !checkIfCover(next, cur))) { 31457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com switch (curDisposal) { 31557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // restore to background color 31657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // -> 'background' means background under this image. 31757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com case 2: 31857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com fillRect(bm, cur->ImageDesc.Left, cur->ImageDesc.Top, 31957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com cur->ImageDesc.Width, cur->ImageDesc.Height, 32057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com color); 32157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com break; 32257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 32357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // restore to previous 32457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com case 3: 32557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com bm->swap(*backup); 32657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com break; 32757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 32857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 32957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 33057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // Save current image if next frame's disposal method == 3 33157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (nextDisposal == 3) { 33257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com const uint32_t* src = bm->getAddr32(0, 0); 33357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com uint32_t* dst = backup->getAddr32(0, 0); 33457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int cnt = bm->width() * bm->height(); 33557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com memcpy(dst, src, cnt*sizeof(uint32_t)); 33657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 33757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com} 33857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkGIFMovie::onGetBitmap(SkBitmap* bm) 3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{ 34157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com const GifFileType* gif = fGIF; 3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (NULL == gif) 3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 3448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 34557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (gif->ImageCount < 1) { 3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const int width = gif->SWidth; 3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com const int height = gif->SHeight; 3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com if (width <= 0 || height <= 0) { 3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return false; 3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 35557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // no need to draw 35657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (fLastDrawIndex >= 0 && fLastDrawIndex == fCurrIndex) { 35757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com return true; 35857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 36057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int startIndex = fLastDrawIndex + 1; 36157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (fLastDrawIndex < 0 || !bm->readyToDraw()) { 36257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // first time 3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 36457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com startIndex = 0; 3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 36657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // create bitmap 367848250415eddc54075f7eb8795e8db79e749c6abreed if (!bm->tryAllocN32Pixels(width, height)) { 36857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com return false; 3698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 37057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // create bitmap for backup 371848250415eddc54075f7eb8795e8db79e749c6abreed if (!fBackup.tryAllocN32Pixels(width, height)) { 37257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com return false; 37357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 37457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } else if (startIndex > fCurrIndex) { 37557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // rewind to 1st frame for repeat 37657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com startIndex = 0; 3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 37957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int lastIndex = fCurrIndex; 38057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (lastIndex < 0) { 38157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // first time 38257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com lastIndex = 0; 38357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } else if (lastIndex > fGIF->ImageCount - 1) { 38457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // this block must not be reached. 38557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com lastIndex = fGIF->ImageCount - 1; 38657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 38857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com SkColor bgColor = SkPackARGB32(0, 0, 0, 0); 38957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (gif->SColorMap != NULL) { 39057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com const GifColorType& col = gif->SColorMap->Colors[fGIF->SBackGroundColor]; 39157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com bgColor = SkColorSetARGB(0xFF, col.Red, col.Green, col.Blue); 39257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 39457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com static SkColor paintingColor = SkPackARGB32(0, 0, 0, 0); 39557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // draw each frames - not intelligent way 39657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com for (int i = startIndex; i <= lastIndex; i++) { 39757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com const SavedImage* cur = &fGIF->SavedImages[i]; 39857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (i == 0) { 39957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com bool trans; 40057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com int disposal; 40157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com getTransparencyAndDisposalMethod(cur, &trans, &disposal); 40257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (!trans && gif->SColorMap != NULL) { 40357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com paintingColor = bgColor; 40457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } else { 40557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com paintingColor = SkColorSetARGB(0, 0, 0, 0); 40657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 40757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 40857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com bm->eraseColor(paintingColor); 40957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com fBackup.eraseColor(paintingColor); 41057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } else { 41157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // Dispose previous frame before move to next frame. 41257f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com const SavedImage* prev = &fGIF->SavedImages[i-1]; 41357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com disposeFrameIfNeeded(bm, prev, cur, &fBackup, paintingColor); 41457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com 41657f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // Draw frame 41757f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // We can skip this process if this index is not last and disposal 41857f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // method == 2 or method == 3 41957f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com if (i == lastIndex || !checkIfWillBeCleared(cur)) { 42057f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com drawFrame(bm, cur, gif->SColorMap); 42157f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com } 4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com } 42357f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com 42457f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com // save index 42557f4969724a1dd88c8d9ae35a863e6cf621181d5djsollen@google.com fLastDrawIndex = lastIndex; 4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com return true; 4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com} 4288540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com 4298540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com/////////////////////////////////////////////////////////////////////////////// 4308540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com 4318540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com#include "SkTRegistry.h" 4328540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com 433b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comSkMovie* Factory(SkStreamRewindable* stream) { 4348540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com char buf[GIF_STAMP_LEN]; 4358540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) { 4368540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com if (memcmp(GIF_STAMP, buf, GIF_STAMP_LEN) == 0 || 4375df93eada5bf8c977c433c0189df7079fc60509creed@android.com memcmp(GIF87_STAMP, buf, GIF_STAMP_LEN) == 0 || 4385df93eada5bf8c977c433c0189df7079fc60509creed@android.com memcmp(GIF89_STAMP, buf, GIF_STAMP_LEN) == 0) { 439a16cb97c89fedcd521aeaadfa94feddbcb6729b1reed@android.com // must rewind here, since our construct wants to re-read the data 440a16cb97c89fedcd521aeaadfa94feddbcb6729b1reed@android.com stream->rewind(); 4418540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com return SkNEW_ARGS(SkGIFMovie, (stream)); 4428540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com } 4438540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com } 4448540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com return NULL; 4458540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com} 4468540a79396e9fd2d3dbc1c409b4e5cd1b95f018ereed@android.com 447b5571b3324cf18629a255ec85e189447069c9b14scroggo@google.comstatic SkTRegistry<SkMovie*(*)(SkStreamRewindable*)> gReg(Factory); 448