Add an option to create unpremultiplied bitmaps.
Currently they cannot be used directly by Skia, but
the pixels can be used elsewhere.

SkImageDecoder:
Add functions to require unpremultiplied output
and query the presence of the requirement

SkImageDecoder_libpng:
SkImageDecoder_libwebp:
SkImageDecoder_WIC:
Respect the requirement for unpremultiplied output.
TODO: Fix SkImageDecoder_CG.

SkScaledBitmapSampler:
Add procs to skip premultiplication and a boolean
parameter to use those procs.

ImageDecodingTest:
Test unpremultiplied bitmap decoding.

SampleUnpremul:
Add a sample which allows visually comparing between the
unpremultiplied version (copied into a premultiplied bitmap,
since drawing unpremultiplied is not currently supported)
and a premultiplied version of image files.

gm.h:
Add a getter for the resource path, so Samples can use it.

As of patch set 13, https://codereview.chromium.org/16816016/
and https://codereview.chromium.org/16983004/, which were
approved separately.

R=reed@google.com

Review URL: https://codereview.chromium.org/16410009

git-svn-id: http://skia.googlecode.com/svn/trunk@9612 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/samplecode/SampleUnpremul.cpp b/samplecode/SampleUnpremul.cpp
new file mode 100644
index 0000000..dfdd2ac
--- /dev/null
+++ b/samplecode/SampleUnpremul.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gm.h"
+#include "SampleCode.h"
+#include "SkBlurDrawLooper.h"
+#include "SkCanvas.h"
+#include "SkColorPriv.h"
+#include "SkForceLinking.h"
+#include "SkImageDecoder.h"
+#include "SkOSFile.h"
+#include "SkStream.h"
+#include "SkString.h"
+#include "SkSystemEventTypes.h"
+#include "SkTypes.h"
+#include "SkUtils.h"
+#include "SkView.h"
+
+__SK_FORCE_IMAGE_DECODER_LINKING;
+
+// Defined in SampleColorFilter.cpp
+extern SkShader* createChecker();
+
+/**
+ *  Interprets c as an unpremultiplied color, and returns the
+ *  premultiplied equivalent.
+ */
+static SkPMColor premultiply_unpmcolor(SkPMColor c) {
+    U8CPU a = SkGetPackedA32(c);
+    U8CPU r = SkGetPackedR32(c);
+    U8CPU g = SkGetPackedG32(c);
+    U8CPU b = SkGetPackedB32(c);
+    return SkPreMultiplyARGB(a, r, g, b);
+}
+
+class UnpremulView : public SampleView {
+public:
+    UnpremulView(SkString res)
+    : fResPath(res)
+    , fPremul(true)
+    , fDecodeSucceeded(false) {
+        this->nextImage();
+    }
+
+protected:
+    // overrides from SkEventSink
+    virtual bool onQuery(SkEvent* evt) SK_OVERRIDE {
+        if (SampleCode::TitleQ(*evt)) {
+            SampleCode::TitleR(evt, "unpremul");
+            return true;
+        }
+        SkUnichar uni;
+        if (SampleCode::CharQ(*evt, &uni)) {
+            char utf8[kMaxBytesInUTF8Sequence];
+            size_t size = SkUTF8_FromUnichar(uni, utf8);
+            // Only consider events for single char keys
+            if (1 == size) {
+                switch (utf8[0]) {
+                    case fNextImageChar:
+                        this->nextImage();
+                        return true;
+                    case fTogglePremulChar:
+                        this->togglePremul();
+                        return true;
+                    default:
+                        break;
+                }
+            }
+        }
+        return this->INHERITED::onQuery(evt);
+    }
+
+    virtual void onDrawBackground(SkCanvas* canvas) SK_OVERRIDE {
+        SkPaint paint;
+        SkAutoTUnref<SkShader> shader(createChecker());
+        paint.setShader(shader.get());
+        canvas->drawPaint(paint);
+    }
+
+    virtual void onDrawContent(SkCanvas* canvas) SK_OVERRIDE {
+        SkPaint paint;
+        paint.setAntiAlias(true);
+        paint.setTextSize(SkIntToScalar(24));
+        SkAutoTUnref<SkBlurDrawLooper> looper(SkNEW_ARGS(SkBlurDrawLooper,
+                                              (SkIntToScalar(2), 0, 0, SK_ColorBLUE)));
+        paint.setLooper(looper);
+        SkScalar height = paint.getFontMetrics(NULL);
+        if (!fDecodeSucceeded) {
+            SkString failure;
+            if (fResPath.size() == 0) {
+                failure.printf("resource path is required!");
+            } else {
+                failure.printf("Failed to decode %s", fCurrFile.c_str());
+            }
+            canvas->drawText(failure.c_str(), failure.size(), 0, height, paint);
+            return;
+        }
+
+        // Name, size of the file, and whether or not it is premultiplied.
+        SkString header(SkOSPath::SkBasename(fCurrFile.c_str()));
+        header.appendf("     [%dx%d]     %s", fBitmap.width(), fBitmap.height(),
+                       (fPremul ? "premultiplied" : "unpremultiplied"));
+        canvas->drawText(header.c_str(), header.size(), 0, height, paint);
+        canvas->translate(0, height);
+
+        // Help messages
+        header.printf("Press '%c' to move to the next image.'", fNextImageChar);
+        canvas->drawText(header.c_str(), header.size(), 0, height, paint);
+        canvas->translate(0, height);
+
+        header.printf("Press '%c' to toggle premultiplied decode.", fTogglePremulChar);
+        canvas->drawText(header.c_str(), header.size(), 0, height, paint);
+
+        // Now draw the image itself.
+        canvas->translate(height * 2, height * 2);
+        if (!fPremul) {
+            // A premultiplied bitmap cannot currently be drawn.
+            SkAutoLockPixels alp(fBitmap);
+            // Copy it to a bitmap which can be drawn, converting
+            // to premultiplied:
+            SkBitmap bm;
+            bm.setConfig(SkBitmap::kARGB_8888_Config, fBitmap.width(),
+                         fBitmap.height());
+            SkASSERT(fBitmap.config() == SkBitmap::kARGB_8888_Config);
+            if (!bm.allocPixels()) {
+                SkString errMsg("allocPixels failed");
+                canvas->drawText(errMsg.c_str(), errMsg.size(), 0, height, paint);
+                return;
+            }
+            for (int i = 0; i < fBitmap.width(); ++i) {
+                for (int j = 0; j < fBitmap.height(); ++j) {
+                    *bm.getAddr32(i, j) = premultiply_unpmcolor(*fBitmap.getAddr32(i, j));
+                }
+            }
+            canvas->drawBitmap(bm, 0, 0);
+        } else {
+            canvas->drawBitmap(fBitmap, 0, 0);
+        }
+    }
+
+private:
+    const SkString  fResPath;
+    SkString        fCurrFile;
+    bool            fPremul;
+    bool            fDecodeSucceeded;
+    SkBitmap        fBitmap;
+    SkOSFile::Iter  fFileIter;
+
+    static const char   fNextImageChar      = 'j';
+    static const char   fTogglePremulChar   = 'h';
+
+    void nextImage() {
+        if (fResPath.size() == 0) {
+            return;
+        }
+        SkString basename;
+        if (!fFileIter.next(&basename)) {
+            fFileIter.reset(fResPath.c_str());
+            if (!fFileIter.next(&basename)) {
+                // Perhaps this should draw some error message?
+                return;
+            }
+        }
+        fCurrFile = SkOSPath::SkPathJoin(fResPath.c_str(), basename.c_str());
+        this->decodeCurrFile();
+    }
+
+    void decodeCurrFile() {
+        if (fCurrFile.size() == 0) {
+            fDecodeSucceeded = false;
+            return;
+        }
+        SkFILEStream stream(fCurrFile.c_str());
+        SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
+        if (NULL == decoder.get()) {
+            fDecodeSucceeded = false;
+            return;
+        }
+        if (!fPremul) {
+            decoder->setRequireUnpremultipliedColors(true);
+        }
+        fDecodeSucceeded = decoder->decode(&stream, &fBitmap,
+                                           SkBitmap::kARGB_8888_Config,
+                                           SkImageDecoder::kDecodePixels_Mode);
+        this->inval(NULL);
+    }
+
+    void togglePremul() {
+        fPremul = !fPremul;
+        this->decodeCurrFile();
+    }
+
+    typedef SampleView INHERITED;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+static SkView* MyFactory() {
+    return new UnpremulView(skiagm::GM::GetResourcePath());
+}
+static SkViewRegister reg(MyFactory);