pull from android: use registry to build up list of image codecs



git-svn-id: http://skia.googlecode.com/svn/trunk@76 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkTRegistry.h b/include/core/SkTRegistry.h
new file mode 100644
index 0000000..83c08de
--- /dev/null
+++ b/include/core/SkTRegistry.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SkTRegistry_DEFINED
+#define SkTRegistry_DEFINED
+
+#include "SkTypes.h"
+
+/** Template class that registers itself (in the constructor) into a linked-list
+    and provides a function-pointer. This can be used to auto-register a set of
+    services, e.g. a set of image codecs.
+ */
+template <typename T, typename P> class SkTRegistry : SkNoncopyable {
+public:
+    typedef T (*Factory)(P);
+
+    SkTRegistry(Factory fact) {
+        fFact = fact;
+        fChain = gHead;
+        gHead = this;
+    }
+
+    static const SkTRegistry* Head() { return gHead; }
+
+    const SkTRegistry* next() const { return fChain; }
+    Factory factory() const { return fFact; }
+
+private:
+    Factory      fFact;
+    SkTRegistry* fChain;
+
+    static SkTRegistry* gHead;
+};
+
+template <typename T, typename P> SkTRegistry<T, P>* SkTRegistry<T, P>::gHead;
+
+#endif
diff --git a/include/images/SkImageDecoder.h b/include/images/SkImageDecoder.h
index 5b91c51..3ea6198 100644
--- a/include/images/SkImageDecoder.h
+++ b/include/images/SkImageDecoder.h
@@ -199,12 +199,6 @@
                             kDecodePixels_Mode);
     }
     
-    /*  Given a format, return true if there is a currently installed decoder
-        for that format. Since a given build may not include all codecs (to save
-        code-size), this may return false.
-    */
-    static bool SupportsFormat(Format);
-
     /** Return the default config for the running device.
         Currently this used as a suggestion to image decoders that need to guess
         what config they should decode into.
diff --git a/src/images/SkImageDecoder_libbmp.cpp b/src/images/SkImageDecoder_libbmp.cpp
index 32a7a6d..a4dcbf6 100644
--- a/src/images/SkImageDecoder_libbmp.cpp
+++ b/src/images/SkImageDecoder_libbmp.cpp
@@ -20,6 +20,7 @@
 #include "SkStream.h"
 #include "SkColorPriv.h"
 #include "SkTDArray.h"
+#include "SkTRegistry.h"
 
 class SkBMPImageDecoder : public SkImageDecoder {
 public:
@@ -34,8 +35,7 @@
                           SkBitmap::Config pref, Mode mode);
 };
 
-SkImageDecoder* SkImageDecoder_BMP_Factory(SkStream*);
-SkImageDecoder* SkImageDecoder_BMP_Factory(SkStream* stream) {
+static SkImageDecoder* Factory(SkStream* stream) {
     static const char kBmpMagic[] = { 'B', 'M' };
     
     size_t len = stream->getLength();
@@ -49,6 +49,8 @@
     return NULL;
 }
 
+static SkTRegistry<SkImageDecoder*, SkStream*> gReg(Factory);
+
 ///////////////////////////////////////////////////////////////////////////////
 
 class SkBmpDecoderCallback : public image_codec::BmpDecoderCallback {
diff --git a/src/images/SkImageDecoder_libgif.cpp b/src/images/SkImageDecoder_libgif.cpp
index 519366a..ed8817a 100644
--- a/src/images/SkImageDecoder_libgif.cpp
+++ b/src/images/SkImageDecoder_libgif.cpp
@@ -326,7 +326,9 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkImageDecoder* SkImageDecoder_GIF_Factory(SkStream* stream) {
+#include "SkTRegistry.h"
+
+static SkImageDecoder* Factory(SkStream* stream) {
     char buf[GIF_STAMP_LEN];
     if (stream->read(buf, GIF_STAMP_LEN) == GIF_STAMP_LEN) {
         if (memcmp(GIF_STAMP,   buf, GIF_STAMP_LEN) == 0 ||
@@ -338,3 +340,4 @@
     return NULL;
 }
 
+static SkTRegistry<SkImageDecoder*, SkStream*> gReg(Factory);
diff --git a/src/images/SkImageDecoder_libico.cpp b/src/images/SkImageDecoder_libico.cpp
index b179a6b..9f21e13 100644
--- a/src/images/SkImageDecoder_libico.cpp
+++ b/src/images/SkImageDecoder_libico.cpp
@@ -44,23 +44,6 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
-SkImageDecoder* SkImageDecoder_ICO_Factory(SkStream*);
-SkImageDecoder* SkImageDecoder_ICO_Factory(SkStream* stream)
-{
-    //i'm going to check if we basically have 0,0,1,0 (reserved = 0, type = 1)
-    //is that required and sufficient?
-    SkAutoMalloc autoMal(4);
-    unsigned char* buf = (unsigned char*)autoMal.get();
-    stream->read((void*)buf, 4);
-    int reserved = read2Bytes(buf, 0);
-    int type = read2Bytes(buf, 2);
-    if (reserved != 0 || type != 1) //it's not an ico
-        return NULL;
-    return SkNEW(SkICOImageDecoder);
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-
 SkICOImageDecoder::SkICOImageDecoder()
 {
 }
@@ -386,3 +369,24 @@
     *address = SkPackARGB32(alpha, red & alpha, green & alpha, blue & alpha);
 }
 
+/////////////////////////////////////////////////////////////////////////////////////////
+
+#include "SkTRegistry.h"
+
+static SkImageDecoder* Factory(SkStream* stream) {
+    // Check to see if the first four bytes are 0,0,1,0
+    // FIXME: Is that required and sufficient?
+    SkAutoMalloc autoMal(4);
+    unsigned char* buf = (unsigned char*)autoMal.get();
+    stream->read((void*)buf, 4);
+    int reserved = read2Bytes(buf, 0);
+    int type = read2Bytes(buf, 2);
+    if (reserved != 0 || type != 1) {
+        // This stream does not represent an ICO image.
+        return NULL;
+    }
+    return SkNEW(SkICOImageDecoder);
+}
+
+static SkTRegistry<SkImageDecoder*, SkStream*> gReg(Factory);
+
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index 5133997..018c96c 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -51,24 +51,6 @@
                           SkBitmap::Config pref, Mode);
 };
 
-SkImageDecoder* SkImageDecoder_JPEG_Factory(SkStream* stream) {
-    static const char gHeader[] = { 0xFF, 0xD8, 0xFF };
-    static const size_t HEADER_SIZE = sizeof(gHeader);
-
-    char buffer[HEADER_SIZE];
-    size_t len = stream->read(buffer, HEADER_SIZE);
-
-    if (len != HEADER_SIZE) {
-        return NULL;   // can't read enough
-    }
-    
-    if (memcmp(buffer, gHeader, HEADER_SIZE)) {
-        return NULL;
-    }
-
-    return SkNEW(SkJPEGImageDecoder);
-}
-
 //////////////////////////////////////////////////////////////////////////
 
 #include "SkTime.h"
@@ -789,20 +771,30 @@
     }
 };
 
-SkImageEncoder* SkImageEncoder_JPEG_Factory();
-SkImageEncoder* SkImageEncoder_JPEG_Factory() {
-    return SkNEW(SkJPEGImageEncoder);
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkTRegistry.h"
+
+static SkImageDecoder* DFactory(SkStream* stream) {
+    static const char gHeader[] = { 0xFF, 0xD8, 0xFF };
+    static const size_t HEADER_SIZE = sizeof(gHeader);
+
+    char buffer[HEADER_SIZE];
+    size_t len = stream->read(buffer, HEADER_SIZE);
+
+    if (len != HEADER_SIZE) {
+        return NULL;   // can't read enough
+    }
+    if (memcmp(buffer, gHeader, HEADER_SIZE)) {
+        return NULL;
+    }
+    return SkNEW(SkJPEGImageDecoder);
 }
 
-//////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////
-
-#ifdef SK_DEBUG
-
-void SkImageDecoder::UnitTest() {
-    SkBitmap    bm;
-
-    (void)SkImageDecoder::DecodeFile("logo.jpg", &bm);
+static SkImageEncoder* EFactory(SkImageEncoder::Type t) {
+    return (SkImageEncoder::kJPEG_Type == t) ? SkNEW(SkJPEGImageEncoder) : NULL;
 }
 
-#endif
+static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
+static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
+
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index fedb8df..b616eee 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -58,15 +58,6 @@
     png_infop info_ptr;
 };
 
-SkImageDecoder* SkImageDecoder_PNG_Factory(SkStream* stream) {
-    char buf[PNG_BYTES_TO_CHECK];
-    if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
-            !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
-        return SkNEW(SkPNGImageDecoder);
-    }
-    return NULL;
-}
-
 static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
     SkStream* sk_stream = (SkStream*) png_ptr->io_ptr;
     size_t bytes = sk_stream->read(data, length);
@@ -787,8 +778,22 @@
     return true;
 }
 
-SkImageEncoder* SkImageEncoder_PNG_Factory();
-SkImageEncoder* SkImageEncoder_PNG_Factory() {
-    return SkNEW(SkPNGImageEncoder);
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkTRegistry.h"
+
+static SkImageDecoder* DFactory(SkStream* stream) {
+    char buf[PNG_BYTES_TO_CHECK];
+    if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
+        !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
+        return SkNEW(SkPNGImageDecoder);
+    }
+    return NULL;
 }
 
+static SkImageEncoder* EFactory(SkImageEncoder::Type t) {
+    return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL;
+}
+
+static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
+static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
diff --git a/src/images/SkImageDecoder_wbmp.cpp b/src/images/SkImageDecoder_wbmp.cpp
index 9d188f6..ac242ea 100644
--- a/src/images/SkImageDecoder_wbmp.cpp
+++ b/src/images/SkImageDecoder_wbmp.cpp
@@ -77,16 +77,6 @@
     }
 };
     
-SkImageDecoder* SkImageDecoder_WBMP_Factory(SkStream* stream)
-{
-    wbmp_head   head;
-
-    if (head.init(stream)) {
-        return SkNEW(SkWBMPImageDecoder);
-    }
-    return NULL;
-}
-
 static void expand_bits_to_bytes(uint8_t dst[], const uint8_t src[], int bits)
 {
     int bytes = bits >> 3;
@@ -165,3 +155,18 @@
     return true;
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkTRegistry.h"
+
+static SkImageDecoder* Factory(SkStream* stream) {
+    wbmp_head   head;
+
+    if (head.init(stream)) {
+        return SkNEW(SkWBMPImageDecoder);
+    }
+    return NULL;
+}
+
+static SkTRegistry<SkImageDecoder*, SkStream*> gReg(Factory);
+
diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp
index 5594eac..7f8b26c 100644
--- a/src/ports/SkImageDecoder_CG.cpp
+++ b/src/ports/SkImageDecoder_CG.cpp
@@ -94,10 +94,6 @@
     return SkNEW(SkImageDecoder_CG);
 }
 
-bool SkImageDecoder::SupportsFormat(Format format) {
-    return true;
-}
-
 /////////////////////////////////////////////////////////////////////////
 
 SkMovie* SkMovie::DecodeStream(SkStream* stream) {
diff --git a/src/ports/SkImageDecoder_Factory.cpp b/src/ports/SkImageDecoder_Factory.cpp
index 5c45a43..3300981 100644
--- a/src/ports/SkImageDecoder_Factory.cpp
+++ b/src/ports/SkImageDecoder_Factory.cpp
@@ -18,67 +18,36 @@
 #include "SkImageDecoder.h"
 #include "SkMovie.h"
 #include "SkStream.h"
+#include "SkTRegistry.h"
 
-extern SkImageDecoder* SkImageDecoder_GIF_Factory(SkStream*);
-extern SkImageDecoder* SkImageDecoder_BMP_Factory(SkStream*);
-extern SkImageDecoder* SkImageDecoder_ICO_Factory(SkStream*);
-extern SkImageDecoder* SkImageDecoder_PNG_Factory(SkStream*);
-extern SkImageDecoder* SkImageDecoder_WBMP_Factory(SkStream*);
-extern SkImageDecoder* SkImageDecoder_JPEG_Factory(SkStream*);
-
-typedef SkImageDecoder* (*SkImageDecoderFactoryProc)(SkStream*);
-
-struct CodecFormat {
-    SkImageDecoderFactoryProc   fProc;
-    SkImageDecoder::Format      fFormat;
-};
-
-static const CodecFormat gPairs[] = {
-    { SkImageDecoder_GIF_Factory,   SkImageDecoder::kGIF_Format },
-    { SkImageDecoder_PNG_Factory,   SkImageDecoder::kPNG_Format },
-    { SkImageDecoder_ICO_Factory,   SkImageDecoder::kICO_Format },
-    { SkImageDecoder_WBMP_Factory,  SkImageDecoder::kWBMP_Format },
-    { SkImageDecoder_BMP_Factory,   SkImageDecoder::kBMP_Format },
-    { SkImageDecoder_JPEG_Factory,  SkImageDecoder::kJPEG_Format }
-};
+typedef SkTRegistry<SkImageDecoder*, SkStream*> DecodeReg;
 
 SkImageDecoder* SkImageDecoder::Factory(SkStream* stream) {
-    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
-        SkImageDecoder* codec = gPairs[i].fProc(stream);
+    const DecodeReg* curr = DecodeReg::Head();
+    while (curr) {
+        SkImageDecoder* codec = curr->factory()(stream);
         stream->rewind();
-        if (NULL != codec) {
+        if (codec) {
             return codec;
         }
+        curr = curr->next();
     }
     return NULL;
 }
 
-bool SkImageDecoder::SupportsFormat(Format format) {
-    for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) {
-        if (gPairs[i].fFormat == format) {
-            return true;
-        }
-    }
-    return false;
-}
-
 /////////////////////////////////////////////////////////////////////////
 
-typedef SkMovie* (*SkMovieFactoryProc)(SkStream*);
-
-extern SkMovie* SkMovie_GIF_Factory(SkStream*);
-
-static const SkMovieFactoryProc gMovieProcs[] = {
-    SkMovie_GIF_Factory
-};
+typedef SkTRegistry<SkMovie*, SkStream*> MovieReg;
 
 SkMovie* SkMovie::DecodeStream(SkStream* stream) {
-    for (unsigned i = 0; i < SK_ARRAY_COUNT(gMovieProcs); i++) {
-        SkMovie* movie = gMovieProcs[i](stream);
-        if (NULL != movie) {
+    const MovieReg* curr = MovieReg::Head();
+    while (curr) {
+        SkMovie* movie = curr->factory()(stream);
+        if (movie) {
             return movie;
         }
         stream->rewind();
+        curr = curr->next();
     }
     return NULL;
 }
diff --git a/src/ports/SkImageEncoder_Factory.cpp b/src/ports/SkImageEncoder_Factory.cpp
index cdd7c04..f44cd8f 100644
--- a/src/ports/SkImageEncoder_Factory.cpp
+++ b/src/ports/SkImageEncoder_Factory.cpp
@@ -15,18 +15,19 @@
  */
 
 #include "SkImageEncoder.h"
+#include "SkTRegistry.h"
 
-extern SkImageEncoder* SkImageEncoder_JPEG_Factory();
-extern SkImageEncoder* SkImageEncoder_PNG_Factory();
+typedef SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> EncodeReg;
 
 SkImageEncoder* SkImageEncoder::Create(Type t) {
-    switch (t) {
-        case kJPEG_Type:
-            return SkImageEncoder_JPEG_Factory();
-        case kPNG_Type:
-            return SkImageEncoder_PNG_Factory();
-        default:
-            return NULL;
+    const EncodeReg* curr = EncodeReg::Head();
+    while (curr) {
+        SkImageEncoder* codec = curr->factory()(t);
+        if (codec) {
+            return codec;
+        }
+        curr = curr->next();
     }
+    return NULL;
 }