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