add optional pref-config table to codecs



git-svn-id: http://skia.googlecode.com/svn/trunk@519 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/include/core/SkFontHost.h b/include/core/SkFontHost.h
index d706e4e..ec34583 100644
--- a/include/core/SkFontHost.h
+++ b/include/core/SkFontHost.h
@@ -254,7 +254,7 @@
 
         Note, if you change this after startup, you'll need to flush the glyph
         cache because it'll have the wrong type of masks cached.
-     
+
         kNONE_LCDOrder means that the subpixel elements are not spatially
         separated in any usable fashion.
      */
@@ -263,7 +263,7 @@
         kBGR_LCDOrder = 1,
         kNONE_LCDOrder = 2,
     };
-    
+
     static void SetSubpixelOrder(LCDOrder order);
     static LCDOrder GetSubpixelOrder();
 };
diff --git a/include/images/SkImageDecoder.h b/include/images/SkImageDecoder.h
index de63345..f8a941f 100644
--- a/include/images/SkImageDecoder.h
+++ b/include/images/SkImageDecoder.h
@@ -89,6 +89,33 @@
     Chooser* getChooser() const { return fChooser; }
     Chooser* setChooser(Chooser*);
 
+    /** This optional table describes the caller's preferred config based on
+        information about the src data. For this table, the src attributes are
+        described in terms of depth (index (8), 16, 32/24) and if there is
+        per-pixel alpha. These inputs combine to create an index into the
+        pref[] table, which contains the caller's preferred config for that
+        input, or kNo_Config if there is no preference.
+
+        To specify no preferrence, call setPrefConfigTable(NULL), which is
+        the default.
+
+        Note, it is still at the discretion of the codec as to what output
+        config is actually returned, as it may not be able to support the
+        caller's preference.
+
+        Here is how the index into the table is computed from the src:
+            depth [8, 16, 32/24] -> 0, 2, 4
+            alpha [no, yes] -> 0, 1
+        The two index values are OR'd together.
+            src: 8-index, no-alpha  -> 0
+            src: 8-index, yes-alpha -> 1
+            src: 16bit,   no-alpha  -> 2    // e.g. 565
+            src: 16bit,   yes-alpha -> 3    // e.g. 1555
+            src: 32/24,   no-alpha  -> 4
+            src: 32/24,   yes-alpha -> 5
+     */
+    void setPrefConfigTable(const SkBitmap::Config pref[6]);
+
     SkBitmap::Allocator* getAllocator() const { return fAllocator; }
     SkBitmap::Allocator* setAllocator(SkBitmap::Allocator*);
 
@@ -145,6 +172,9 @@
         note: document use of Allocator, Peeker and Chooser
     */
     bool decode(SkStream*, SkBitmap* bitmap, SkBitmap::Config pref, Mode);
+    bool decode(SkStream* stream, SkBitmap* bitmap, Mode mode) {
+        return this->decode(stream, bitmap, SkBitmap::kNo_Config, mode);
+    }
 
     /** Given a stream, this will try to find an appropriate decoder object.
         If none is found, the method returns NULL.
@@ -232,8 +262,7 @@
 
 protected:
     // must be overridden in subclasses. This guy is called by decode(...)
-    virtual bool onDecode(SkStream*, SkBitmap* bitmap, SkBitmap::Config pref,
-                          Mode) = 0;
+    virtual bool onDecode(SkStream*, SkBitmap* bitmap, Mode) = 0;
 
     /** Can be queried from within onDecode, to see if the user (possibly in
         a different thread) has requested the decode to cancel. If this returns
@@ -260,12 +289,30 @@
     */
     bool allocPixelRef(SkBitmap*, SkColorTable*) const;
 
+    enum SrcDepth {
+        kIndex_SrcDepth,
+        k16Bit_SrcDepth,
+        k32Bit_SrcDepth
+    };
+    /** The subclass, inside onDecode(), calls this to determine the config of
+        the returned bitmap. SrcDepth and hasAlpha reflect the raw data of the
+        src image. This routine returns the caller's preference given
+        srcDepth and hasAlpha, or kNo_Config if there is no preference.
+
+        Note: this also takes into account GetDeviceConfig(), so the subclass
+        need not call that.
+     */
+    SkBitmap::Config getPrefConfig(SrcDepth, bool hasAlpha) const;
+
 private:
     Peeker*                 fPeeker;
     Chooser*                fChooser;
     SkBitmap::Allocator*    fAllocator;
     int                     fSampleSize;
+    SkBitmap::Config        fDefaultPref;   // use if fUsePrefTable is false
+    SkBitmap::Config        fPrefTable[6];  // use if fUsePrefTable is true
     bool                    fDitherImage;
+    bool                    fUsePrefTable;
     mutable bool            fShouldCancelDecode;
 
     // illegal
diff --git a/src/images/SkImageDecoder.cpp b/src/images/SkImageDecoder.cpp
index 4711f89..768d671 100644
--- a/src/images/SkImageDecoder.cpp
+++ b/src/images/SkImageDecoder.cpp
@@ -37,7 +37,8 @@
 
 SkImageDecoder::SkImageDecoder()
     : fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1),
-      fDitherImage(true) {
+      fDefaultPref(SkBitmap::kNo_Config), fDitherImage(true),
+      fUsePrefTable(false) {
 }
 
 SkImageDecoder::~SkImageDecoder() {
@@ -91,6 +92,46 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+void SkImageDecoder::setPrefConfigTable(const SkBitmap::Config pref[6]) {
+    if (NULL == pref) {
+        fUsePrefTable = false;
+    } else {
+        fUsePrefTable = true;
+        memcpy(fPrefTable, pref, sizeof(fPrefTable));
+    }
+}
+
+SkBitmap::Config SkImageDecoder::getPrefConfig(SrcDepth srcDepth,
+                                               bool srcHasAlpha) const {
+    SkBitmap::Config config;
+
+    if (fUsePrefTable) {
+        int index = 0;
+        switch (srcDepth) {
+            case kIndex_SrcDepth:
+                index = 0;
+                break;
+            case k16Bit_SrcDepth:
+                index = 2;
+                break;
+            case k32Bit_SrcDepth:
+                index = 4;
+                break;
+        }
+        if (srcHasAlpha) {
+            index += 1;
+        }
+        config = fPrefTable[index];
+    } else {
+        config = fDefaultPref;
+    }
+
+    if (SkBitmap::kNo_Config == config) {
+        config = SkImageDecoder::GetDeviceConfig();
+    }
+    return config;
+}
+
 bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
                             SkBitmap::Config pref, Mode mode) {
     // pass a temporary bitmap, so that if we return false, we are assured of
@@ -99,8 +140,10 @@
 
     // we reset this to false before calling onDecode
     fShouldCancelDecode = false;
+    // assign this, for use by getPrefConfig(), in case fUsePrefTable is false
+    fDefaultPref = pref;
 
-    if (!this->onDecode(stream, &tmp, pref, mode)) {
+    if (!this->onDecode(stream, &tmp, mode)) {
         return false;
     }
     bm->swap(tmp);
diff --git a/src/images/SkImageDecoder_libbmp.cpp b/src/images/SkImageDecoder_libbmp.cpp
index a4dcbf6..30bfbdb 100644
--- a/src/images/SkImageDecoder_libbmp.cpp
+++ b/src/images/SkImageDecoder_libbmp.cpp
@@ -31,8 +31,7 @@
     }
 
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm,
-                          SkBitmap::Config pref, Mode mode);
+    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
 };
 
 static SkImageDecoder* Factory(SkStream* stream) {
@@ -81,8 +80,7 @@
     bool fJustBounds;
 };
 
-bool SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
-                                 SkBitmap::Config prefConfig, Mode mode) {
+bool SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
 
     size_t length = stream->getLength();
     SkAutoMalloc storage(length);
@@ -110,12 +108,12 @@
     
     int width = callback.width();
     int height = callback.height();
-    SkBitmap::Config config = SkBitmap::kARGB_8888_Config;
-    
+    SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
+
     // only accept prefConfig if it makes sense for us
-    if (SkBitmap::kARGB_4444_Config == prefConfig ||
-            SkBitmap::kRGB_565_Config == config) {
-        config = prefConfig;
+    if (SkBitmap::kARGB_4444_Config != config &&
+            SkBitmap::kRGB_565_Config != config) {
+        config = SkBitmap::kARGB_8888_Config;
     }
 
     SkScaledBitmapSampler sampler(width, height, getSampleSize());
diff --git a/src/images/SkImageDecoder_libgif.cpp b/src/images/SkImageDecoder_libgif.cpp
index 258a8a0..d2470cc 100644
--- a/src/images/SkImageDecoder_libgif.cpp
+++ b/src/images/SkImageDecoder_libgif.cpp
@@ -31,8 +31,7 @@
     }
     
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm,
-                          SkBitmap::Config pref, Mode mode);
+    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode);
 };
 
 static const uint8_t gStartingIterlaceYValue[] = {
@@ -154,8 +153,7 @@
     return false;
 }
 
-bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm,
-                                 SkBitmap::Config prefConfig, Mode mode) {   
+bool SkGIFImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* bm, Mode mode) {
     GifFileType* gif = DGifOpen(sk_stream, DecodeCallBackProc);
     if (NULL == gif) {
         return error_return(gif, *bm, "DGifOpen");
diff --git a/src/images/SkImageDecoder_libico.cpp b/src/images/SkImageDecoder_libico.cpp
index 9f21e13..ef5b7ac 100644
--- a/src/images/SkImageDecoder_libico.cpp
+++ b/src/images/SkImageDecoder_libico.cpp
@@ -29,8 +29,7 @@
     }
 
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm,
-                          SkBitmap::Config pref, Mode);
+    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
 };
 
 /////////////////////////////////////////////////////////////////////////////////////////
@@ -79,8 +78,7 @@
     return 0;
 }
 
-bool SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
-                                 SkBitmap::Config pref, Mode mode)
+bool SkICOImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode)
 {
     size_t length = stream->read(NULL, 0);
     SkAutoMalloc autoMal(length);
diff --git a/src/images/SkImageDecoder_libjpeg.cpp b/src/images/SkImageDecoder_libjpeg.cpp
index 476cfa1..a64efbc 100644
--- a/src/images/SkImageDecoder_libjpeg.cpp
+++ b/src/images/SkImageDecoder_libjpeg.cpp
@@ -55,8 +55,7 @@
     }
 
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm,
-                          SkBitmap::Config pref, Mode);
+    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
 };
 
 //////////////////////////////////////////////////////////////////////////
@@ -157,8 +156,7 @@
     return false;   // must always return false
 }
 
-bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm,
-                                  SkBitmap::Config prefConfig, Mode mode) {
+bool SkJPEGImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
 #ifdef TIME_DECODE
     AutoTimeMillis atm("JPEG Decode");
 #endif
@@ -215,11 +213,7 @@
     /* default format is RGB */
     cinfo.out_color_space = JCS_RGB;
 
-    SkBitmap::Config config = prefConfig;
-    // if no user preference, see what the device recommends
-    if (config == SkBitmap::kNo_Config)
-        config = SkImageDecoder::GetDeviceConfig();
-
+    SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
     // only these make sense for jpegs
     if (config != SkBitmap::kARGB_8888_Config &&
         config != SkBitmap::kARGB_4444_Config &&
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index 6df56b4..3548fc8 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -37,8 +37,7 @@
     }
     
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm,
-                          SkBitmap::Config pref, Mode);
+    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
 };
 
 #ifndef png_jmpbuf
@@ -110,9 +109,9 @@
     return reallyHasAlpha;
 }
 
-static bool canUpscalePaletteToConfig(SkBitmap::Config prefConfig,
+static bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig,
                                       bool srcHasAlpha) {
-    switch (prefConfig) {
+    switch (dstConfig) {
         case SkBitmap::kARGB_8888_Config:
         case SkBitmap::kARGB_4444_Config:
             return true;
@@ -137,7 +136,7 @@
 }
 
 bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
-                                 SkBitmap::Config prefConfig, Mode mode) {
+                                 Mode mode) {
 //    SkAutoTrace    apr("SkPNGImageDecoder::onDecode");
 
     /* Create and initialize the png_struct with the desired error handler
@@ -233,11 +232,11 @@
     }
     
     if (color_type == PNG_COLOR_TYPE_PALETTE) {
-        config = SkBitmap::kIndex8_Config;
-        // now see if we can upscale to their requested config
         bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
-        if (canUpscalePaletteToConfig(prefConfig, paletteHasAlpha)) {
-            config = prefConfig;
+        config = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha);
+        // now see if we can upscale to their requested config
+        if (!canUpscalePaletteToConfig(config, paletteHasAlpha)) {
+            config = SkBitmap::kIndex8_Config;
         }
     } else {
         png_color_16p   transpColor = NULL;
@@ -278,14 +277,16 @@
                 PNG_COLOR_TYPE_RGB_ALPHA == color_type ||
                 PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
             hasAlpha = true;
-            config = SkBitmap::kARGB_8888_Config;
-        } else {    // we get to choose the config
-            config = prefConfig;
-            if (config == SkBitmap::kNo_Config) {
-                config = SkImageDecoder::GetDeviceConfig();
+        }
+        config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha);
+        // now match the request against our capabilities
+        if (hasAlpha) {
+            if (config != SkBitmap::kARGB_4444_Config) {
+                config = SkBitmap::kARGB_8888_Config;
             }
+        } else {
             if (config != SkBitmap::kRGB_565_Config &&
-                    config != SkBitmap::kARGB_4444_Config) {
+                config != SkBitmap::kARGB_4444_Config) {
                 config = SkBitmap::kARGB_8888_Config;
             }
         }
@@ -311,9 +312,6 @@
     const int sampleSize = this->getSampleSize();
     SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
 
-    // we must always return the same config, independent of mode, so if we were
-    // going to respect prefConfig, it must have happened by now
-
     decodedBitmap->setConfig(config, sampler.scaledWidth(),
                              sampler.scaledHeight(), 0);
     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
diff --git a/src/images/SkImageDecoder_wbmp.cpp b/src/images/SkImageDecoder_wbmp.cpp
index ac242ea..6d63ca9 100644
--- a/src/images/SkImageDecoder_wbmp.cpp
+++ b/src/images/SkImageDecoder_wbmp.cpp
@@ -29,8 +29,7 @@
     }
     
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm,
-                          SkBitmap::Config pref, Mode);
+    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
 };
 
 static bool read_byte(SkStream* stream, uint8_t* data)
@@ -107,7 +106,7 @@
 #define SkAlign8(x)     (((x) + 7) & ~7)
 
 bool SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
-                                  SkBitmap::Config prefConfig, Mode mode)
+                                  Mode mode)
 {
     wbmp_head   head;
     
diff --git a/src/images/SkJpegUtility.cpp b/src/images/SkJpegUtility.cpp
index fc4f358..e207592 100644
--- a/src/images/SkJpegUtility.cpp
+++ b/src/images/SkJpegUtility.cpp
@@ -43,7 +43,7 @@
 static void sk_skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
     skjpeg_source_mgr*  src = (skjpeg_source_mgr*)cinfo->src;
 
-    if (num_bytes > src->bytes_in_buffer) {
+    if (num_bytes > (long)src->bytes_in_buffer) {
         long bytesToSkip = num_bytes - src->bytes_in_buffer;
         while (bytesToSkip > 0) {
             long bytes = (long)src->fStream->skip(bytesToSkip);
diff --git a/src/ports/SkImageDecoder_CG.cpp b/src/ports/SkImageDecoder_CG.cpp
index ea865c8..e7a5528 100644
--- a/src/ports/SkImageDecoder_CG.cpp
+++ b/src/ports/SkImageDecoder_CG.cpp
@@ -42,14 +42,12 @@
 
 class SkImageDecoder_CG : public SkImageDecoder {
 protected:
-    virtual bool onDecode(SkStream* stream, SkBitmap* bm,
-                          SkBitmap::Config pref, Mode);
+    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
 };
 
 #define BITMAP_INFO (kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast)
 
-bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm,
-                                 SkBitmap::Config pref, Mode mode) {
+bool SkImageDecoder_CG::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
     CGImageSourceRef imageSrc = SkStreamToCGImageSource(stream);
 
     if (NULL == imageSrc) {