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 "SkStream.h"
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h"
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTypes.h"
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkICOImageDecoder : public SkImageDecoder {
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkICOImageDecoder();
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    virtual Format getFormat() const {
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return kICO_Format;
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected:
240a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
271cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerSkImageDecoder* SkCreateICOImageDecoder();
281cab2921ab279367f8206cdadc9259d12e603548Derek SollenbergerSkImageDecoder* SkCreateICOImageDecoder() {
291cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger    return new SkICOImageDecoder;
301cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger}
311cab2921ab279367f8206cdadc9259d12e603548Derek Sollenberger
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/////////////////////////////////////////////////////////////////////////////////////////
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//read bytes starting from the begin-th index in the buffer
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//read in Intel order, and return an integer
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define readByte(buffer,begin) buffer[begin]
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define read2Bytes(buffer,begin) buffer[begin]+(buffer[begin+1]<<8)
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define read4Bytes(buffer,begin) buffer[begin]+(buffer[begin+1]<<8)+(buffer[begin+2]<<16)+(buffer[begin+3]<<24)
400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/////////////////////////////////////////////////////////////////////////////////////////
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source ProjectSkICOImageDecoder::SkICOImageDecoder()
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//helpers - my function pointer will call one of these, depending on the bitCount, each time through the inner loop
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void editPixelBit1(const int pixelNo, const unsigned char* buf,
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int xorOffset, int& x, int y, const int w,
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void editPixelBit4(const int pixelNo, const unsigned char* buf,
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int xorOffset, int& x, int y, const int w,
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void editPixelBit8(const int pixelNo, const unsigned char* buf,
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int xorOffset, int& x, int y, const int w,
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void editPixelBit24(const int pixelNo, const unsigned char* buf,
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int xorOffset, int& x, int y, const int w,
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void editPixelBit32(const int pixelNo, const unsigned char* buf,
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int xorOffset, int& x, int y, const int w,
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors);
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int calculateRowBytesFor8888(int w, int bitCount)
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //  Default rowBytes is w << 2 for kARGB_8888
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //  In the case of a 4 bit image with an odd width, we need to add some
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //  so we can go off the end of the drawn bitmap.
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //  Add 4 to ensure that it is still a multiple of 4.
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (4 == bitCount && (w & 0x1)) {
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return (w + 1) << 2;
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //  Otherwise return 0, which will allow it to be calculated automatically.
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return 0;
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
780a81c953145c77abea5ca1df9e84c62d9da96094Mike Reedbool SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode)
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    size_t length = stream->read(NULL, 0);
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoMalloc autoMal(length);
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unsigned char* buf = (unsigned char*)autoMal.get();
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (stream->read((void*)buf, length) != length) {
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //these should always be the same - should i use for error checking? - what about files that have some
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //incorrect values, but still decode properly?
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int reserved = read2Bytes(buf, 0);    // 0
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int type = read2Bytes(buf, 2);        // 1
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (reserved != 0 || type != 1)
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int count = read2Bytes(buf, 4);
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //need to at least have enough space to hold the initial table of info
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (length < (size_t)(6 + count*16))
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int choice;
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Chooser* chooser = this->getChooser();
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //FIXME:if no chooser, consider providing the largest color image
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //what are the odds that the largest image would be monochrome?
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL == chooser) {
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        choice = 0;
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        chooser->begin(count);
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (int i = 0; i < count; i++)
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        {
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            //need to find out the config, width, and height from the stream
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int width = readByte(buf, 6 + i*16);
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int height = readByte(buf, 7 + i*16);
1120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int offset = read4Bytes(buf, 18 + i*16);
1130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int bitCount = read2Bytes(buf, offset+14);
1140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap::Config c;
1150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            //currently only provide ARGB_8888_, but maybe we want kIndex8_Config for 1 and 4, and possibly 8?
1160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            //or maybe we'll determine this based on the provided config
1170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            switch (bitCount)
1180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            {
1190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                case 1:
1200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                case 4:
1210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    // In reality, at least for the moment, these will be decoded into kARGB_8888 bitmaps.
1220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    // However, this will be used to distinguish between the lower quality 1bpp and 4 bpp
1230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    // images and the higher quality images.
1240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    c = SkBitmap::kIndex8_Config;
1250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    break;
1260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                case 8:
1270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                case 24:
1280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                case 32:
1290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    c = SkBitmap::kARGB_8888_Config;
1300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    break;
1310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                default:
1320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    SkDEBUGF(("Image with %ibpp not supported\n", bitCount));
1330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    continue;
1340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
1350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            chooser->inspect(i, c, width, height);
1360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        choice = chooser->choose();
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //you never know what the chooser is going to supply
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (choice >= count || choice < 0)
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //skip ahead to the correct header
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //commented out lines are not used, but if i switch to other read method, need to know how many to skip
1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //otherwise, they could be used for error checking
1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int w = readByte(buf, 6 + choice*16);
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int h = readByte(buf, 7 + choice*16);
1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int colorCount = readByte(buf, 8 + choice*16);
1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int reservedToo = readByte(buf, 9 + choice*16);   //0
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int planes = read2Bytes(buf, 10 + choice*16);       //1 - but often 0
1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int fakeBitCount = read2Bytes(buf, 12 + choice*16); //should be real - usually 0
1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int size = read4Bytes(buf, 14 + choice*16);           //matters?
1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int offset = read4Bytes(buf, 18 + choice*16);
1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if ((size_t)(offset + size) > length)
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int infoSize = read4Bytes(buf, offset);             //40
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int width = read4Bytes(buf, offset+4);              //should == w
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int height = read4Bytes(buf, offset+8);             //should == 2*h
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int planesToo = read2Bytes(buf, offset+12);         //should == 1 (does it?)
1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int bitCount = read2Bytes(buf, offset+14);
1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    void (*placePixel)(const int pixelNo, const unsigned char* buf,
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const int xorOffset, int& x, int y, const int w,
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors) = NULL;
1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (bitCount)
1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 1:
1690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            placePixel = &editPixelBit1;
1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            colorCount = 2;
1710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 4:
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            placePixel = &editPixelBit4;
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            colorCount = 16;
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 8:
1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            placePixel = &editPixelBit8;
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            colorCount = 256;
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 24:
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            placePixel = &editPixelBit24;
1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            colorCount = 0;
1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case 32:
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            placePixel = &editPixelBit32;
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            colorCount = 0;
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        default:
1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkDEBUGF(("Decoding %ibpp is unimplemented\n", bitCount));
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return false;
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //these should all be zero, but perhaps are not - need to check
1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int compression = read4Bytes(buf, offset+16);       //0
1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int imageSize = read4Bytes(buf, offset+20);         //0 - sometimes has a value
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int xPixels = read4Bytes(buf, offset+24);           //0
1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int yPixels = read4Bytes(buf, offset+28);           //0
1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int colorsUsed = read4Bytes(buf, offset+32)         //0 - might have an actual value though
1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //int colorsImportant = read4Bytes(buf, offset+36);   //0
2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int begin = offset + 40;
2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //this array represents the colortable
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //if i allow other types of bitmaps, it may actually be used as a part of the bitmap
2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPMColor* colors = NULL;
2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int blue, green, red;
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (colorCount)
2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        colors = new SkPMColor[colorCount];
2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (int j = 0; j < colorCount; j++)
2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        {
2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            //should this be a function - maybe a #define?
2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            blue = readByte(buf, begin + 4*j);
2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            green = readByte(buf, begin + 4*j + 1);
2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            red = readByte(buf, begin + 4*j + 2);
2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            colors[j] = SkPackARGB32(0xFF, red & 0xFF, green & 0xFF, blue & 0xFF);
2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int bitWidth = w*bitCount;
2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int test = bitWidth & 0x1F;
2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int mask = -(((test >> 4) | (test >> 3) | (test >> 2) | (test >> 1) | test) & 0x1);    //either 0xFFFFFFFF or 0
2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int lineBitWidth = (bitWidth & 0xFFFFFFE0) + (0x20 & mask);
2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int lineWidth = lineBitWidth/bitCount;
2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int xorOffset = begin + colorCount*4;   //beginning of the color bitmap
2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                            //other read method means we will just be here already
2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int andOffset = xorOffset + ((lineWidth*h*bitCount) >> 3);
2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /*int */test = w & 0x1F;   //the low 5 bits - we are rounding up to the next 32 (2^5)
2290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /*int */mask = -(((test >> 4) | (test >> 3) | (test >> 2) | (test >> 1) | test) & 0x1);    //either 0xFFFFFFFF or 0
2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int andLineWidth = (w & 0xFFFFFFE0) + (0x20 & mask);
2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //if we allow different Configs, everything is the same til here
2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //change the config, and use different address getter, and place index vs color, and add the color table
2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //FIXME: what is the tradeoff in size?
2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //if the andbitmap (mask) is all zeroes, then we can easily do an index bitmap
2350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //however, with small images with large colortables, maybe it's better to still do argb_8888
2360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
238c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase        bm->setConfig(SkBitmap::kARGB_8888_Config, w, h, calculateRowBytesFor8888(w, bitCount));
2390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        delete[] colors;
2400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return true;
2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
242c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase#ifdef SK_BUILD_FOR_ANDROID
243c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase    // No Bitmap reuse supported for this format
244c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase    if (!bm->isNull()) {
245c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase        return false;
246c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase    }
247c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase#endif
248c0b4fa78738acf9ad587eb9fcbc2021be9a3ee77Chet Haase    bm->setConfig(SkBitmap::kARGB_8888_Config, w, h, calculateRowBytesFor8888(w, bitCount));
2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (!this->allocPixelRef(bm, NULL))
2510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
2520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        delete[] colors;
2530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
2540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoLockPixels alp(*bm);
2570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int y = 0; y < h; y++)
2590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
2600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (int x = 0; x < w; x++)
2610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        {
2620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            //U32* address = bm->getAddr32(x, y);
2630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            //check the alpha bit first, but pass it along to the function to figure out how to deal with it
2650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int andPixelNo = andLineWidth*(h-y-1)+x;
2660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            //only need to get a new alphaByte when x %8 == 0
2670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            //but that introduces an if and a mod - probably much slower
2680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            //that's ok, it's just a read of an array, not a stream
2690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int alphaByte = readByte(buf, andOffset + (andPixelNo >> 3));
2700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int shift = 7 - (andPixelNo & 0x7);
2710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int m = 1 << shift;
2720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            int pixelNo = lineWidth*(h-y-1)+x;
2740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            placePixel(pixelNo, buf, xorOffset, x, y, w, bm, alphaByte, m, shift, colors);
2750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    delete [] colors;
2800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //ensure we haven't read off the end?
2810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //of course this doesn't help us if the andOffset was a lie...
2820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //return andOffset + (andLineWidth >> 3) <= length;
2830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
2840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}   //onDecode
2850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//function to place the pixel, determined by the bitCount
2870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void editPixelBit1(const int pixelNo, const unsigned char* buf,
2880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int xorOffset, int& x, int y, const int w,
2890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors)
2900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
2910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // note that this should be the same as/similar to the AND bitmap
2920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPMColor* address = bm->getAddr32(x,y);
2930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int byte = readByte(buf, xorOffset + (pixelNo >> 3));
2940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int colorBit;
2950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int alphaBit;
2960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // Read all of the bits in this byte.
2970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int i = x + 8;
2980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // Pin to the width so we do not write outside the bounds of
2990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // our color table.
3000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    i = i > w ? w : i;
3010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // While loop to check all 8 bits individually.
3020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    while (x < i)
3030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    {
3040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        colorBit = (byte & m) >> shift;
3060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        alphaBit = (alphaByte & m) >> shift;
3070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *address = (alphaBit-1)&(colors[colorBit]);
3080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        x++;
3090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // setup for the next pixel
3100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        address = address + 1;
3110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        m = m >> 1;
3120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        shift -= 1;
3130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    x--;
3150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void editPixelBit4(const int pixelNo, const unsigned char* buf,
3170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int xorOffset, int& x, int y, const int w,
3180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors)
3190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
3200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPMColor* address = bm->getAddr32(x, y);
3210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int byte = readByte(buf, xorOffset + (pixelNo >> 1));
3220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int pixel = (byte >> 4) & 0xF;
3230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int alphaBit = (alphaByte & m) >> shift;
3240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    *address = (alphaBit-1)&(colors[pixel]);
3250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    x++;
3260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //if w is odd, x may be the same as w, which means we are writing to an unused portion of the bitmap
3270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //but that's okay, since i've added an extra rowByte for just this purpose
3280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    address = address + 1;
3290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    pixel = byte & 0xF;
3300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    m = m >> 1;
3310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    alphaBit = (alphaByte & m) >> (shift-1);
3320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //speed up trick here
3330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    *address = (alphaBit-1)&(colors[pixel]);
3340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void editPixelBit8(const int pixelNo, const unsigned char* buf,
3370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int xorOffset, int& x, int y, const int w,
3380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors)
3390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
3400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPMColor* address = bm->getAddr32(x, y);
3410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int pixel = readByte(buf, xorOffset + pixelNo);
3420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int alphaBit = (alphaByte & m) >> shift;
3430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    *address = (alphaBit-1)&(colors[pixel]);
3440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void editPixelBit24(const int pixelNo, const unsigned char* buf,
3470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int xorOffset, int& x, int y, const int w,
3480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors)
3490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
3500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPMColor* address = bm->getAddr32(x, y);
3510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int blue = readByte(buf, xorOffset + 3*pixelNo);
3520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int green = readByte(buf, xorOffset + 3*pixelNo + 1);
3530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int red = readByte(buf, xorOffset + 3*pixelNo + 2);
3540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int alphaBit = (alphaByte & m) >> shift;
3550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //alphaBit == 1 => alpha = 0
3560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int alpha = (alphaBit-1) & 0xFF;
3574c1037238c8ebcef8c75b5d43730ed308a11102cMike Reed    *address = SkPreMultiplyARGB(alpha, red, green, blue);
3580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void editPixelBit32(const int pixelNo, const unsigned char* buf,
3610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const int xorOffset, int& x, int y, const int w,
3620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkBitmap* bm, int alphaByte, int m, int shift, SkPMColor* colors)
3630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project{
3640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPMColor* address = bm->getAddr32(x, y);
3650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int blue = readByte(buf, xorOffset + 4*pixelNo);
3660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int green = readByte(buf, xorOffset + 4*pixelNo + 1);
3670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int red = readByte(buf, xorOffset + 4*pixelNo + 2);
3680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int alphaBit = (alphaByte & m) >> shift;
369d6cd36570b5f18182c711532172cf233a41e643fDerek Sollenberger#if 1 // don't trust the alphaBit for 32bit images <mrr>
370d6cd36570b5f18182c711532172cf233a41e643fDerek Sollenberger    alphaBit = 0;
371d6cd36570b5f18182c711532172cf233a41e643fDerek Sollenberger#endif
3720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int alpha = readByte(buf, xorOffset + 4*pixelNo + 3) & ((alphaBit-1)&0xFF);
3734c1037238c8ebcef8c75b5d43730ed308a11102cMike Reed    *address = SkPreMultiplyARGB(alpha, red, green, blue);
3740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/////////////////////////////////////////////////////////////////////////////////////////
3770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTRegistry.h"
3790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkImageDecoder* Factory(SkStream* stream) {
3810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // Check to see if the first four bytes are 0,0,1,0
3820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // FIXME: Is that required and sufficient?
3830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoMalloc autoMal(4);
3840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    unsigned char* buf = (unsigned char*)autoMal.get();
3850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    stream->read((void*)buf, 4);
3860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int reserved = read2Bytes(buf, 0);
3870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int type = read2Bytes(buf, 2);
3880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (reserved != 0 || type != 1) {
3890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // This stream does not represent an ICO image.
3900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return NULL;
3910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkNEW(SkICOImageDecoder);
3930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
3940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkTRegistry<SkImageDecoder*, SkStream*> gReg(Factory);
3960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
397