Use SkTransferFunctionBehavior in SkImageGenerator

This fixes SkColorSpaceXformCanvas gms that expect
non-linear premuls from the codec.

BUG=skia:

Change-Id: I5dc236d0cd760c23605a26e9c33ddb18955f9231
Reviewed-on: https://skia-review.googlesource.com/10164
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Matt Sarett <msarett@google.com>
diff --git a/include/core/SkImageGenerator.h b/include/core/SkImageGenerator.h
index 6263dee..8624359 100644
--- a/include/core/SkImageGenerator.h
+++ b/include/core/SkImageGenerator.h
@@ -177,6 +177,23 @@
         return false;
     }
 
+    struct Options {
+        Options()
+            : fColorTable(nullptr)
+            , fColorTableCount(nullptr)
+            , fBehavior(SkTransferFunctionBehavior::kRespect)
+        {}
+
+        SkPMColor*                 fColorTable;
+        int*                       fColorTableCount;
+        SkTransferFunctionBehavior fBehavior;
+    };
+    bool getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options* opts);
+    virtual bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
+                             const Options& opts) {
+        return this->onGetPixels(info, pixels, rowBytes, opts.fColorTable, opts.fColorTableCount);
+    }
+
 #if SK_SUPPORT_GPU
     virtual sk_sp<GrTextureProxy> onGenerateTexture(GrContext*, const SkImageInfo&,
                                                     const SkIPoint&);
@@ -186,6 +203,8 @@
     const SkImageInfo fInfo;
     const uint32_t fUniqueID;
 
+    friend class SkImageCacherator;
+
     // This is our default impl, which may be different on different platforms.
     // It is called from NewFromEncoded() after it has checked for any runtime factory.
     // The SkData will never be NULL, as that will have been checked by NewFromEncoded.
diff --git a/src/codec/SkCodecImageGenerator.cpp b/src/codec/SkCodecImageGenerator.cpp
index 56ca21e..6467033 100644
--- a/src/codec/SkCodecImageGenerator.cpp
+++ b/src/codec/SkCodecImageGenerator.cpp
@@ -37,8 +37,19 @@
 
 bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
         SkPMColor ctable[], int* ctableCount) {
-    SkCodec::Result result = fCodec->getPixels(info, pixels, rowBytes, nullptr, ctable,
-            ctableCount);
+    Options opts;
+    opts.fColorTable = ctable;
+    opts.fColorTableCount = ctableCount;
+    opts.fBehavior = SkTransferFunctionBehavior::kRespect;
+    return this->onGetPixels(info, pixels, rowBytes, opts);
+}
+
+bool SkCodecImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
+                                        const Options& opts) {
+    SkCodec::Options codecOpts;
+    codecOpts.fPremulBehavior = opts.fBehavior;
+    SkCodec::Result result = fCodec->getPixels(info, pixels, rowBytes, &codecOpts, opts.fColorTable,
+                                               opts.fColorTableCount);
     switch (result) {
         case SkCodec::kSuccess:
         case SkCodec::kIncompleteInput:
diff --git a/src/codec/SkCodecImageGenerator.h b/src/codec/SkCodecImageGenerator.h
index 727a747..a435205 100644
--- a/src/codec/SkCodecImageGenerator.h
+++ b/src/codec/SkCodecImageGenerator.h
@@ -24,7 +24,9 @@
     SkData* onRefEncodedData(GrContext* ctx) override;
 
     bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[],
-            int* ctableCount) override;
+                     int* ctableCount) override;
+    bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, const Options& opts)
+                     override;
 
     bool onQueryYUV8(SkYUVSizeInfo*, SkYUVColorSpace*) const override;
 
diff --git a/src/core/SkImageCacherator.cpp b/src/core/SkImageCacherator.cpp
index 4929c6b..1a37f3b 100644
--- a/src/core/SkImageCacherator.cpp
+++ b/src/core/SkImageCacherator.cpp
@@ -166,14 +166,18 @@
 }
 
 bool SkImageCacherator::directGeneratePixels(const SkImageInfo& info, void* pixels, size_t rb,
-                                             int srcX, int srcY) {
+                                             int srcX, int srcY,
+                                             SkTransferFunctionBehavior behavior) {
     ScopedGenerator generator(fSharedGenerator);
     const SkImageInfo& genInfo = generator->getInfo();
     // Currently generators do not natively handle subsets, so check that first.
     if (srcX || srcY || genInfo.width() != info.width() || genInfo.height() != info.height()) {
         return false;
     }
-    return generator->getPixels(info, pixels, rb);
+
+    SkImageGenerator::Options opts;
+    opts.fBehavior = behavior;
+    return generator->getPixels(info, pixels, rb, &opts);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkImageCacherator.h b/src/core/SkImageCacherator.h
index e75aab7..233b7db 100644
--- a/src/core/SkImageCacherator.h
+++ b/src/core/SkImageCacherator.h
@@ -88,7 +88,7 @@
     bool lockAsBitmapOnlyIfAlreadyCached(SkBitmap*, CachedFormat);
     // Call the underlying generator directly
     bool directGeneratePixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
-                              int srcX, int srcY);
+                              int srcX, int srcY, SkTransferFunctionBehavior behavior);
 
 private:
     // Ref-counted tuple(SkImageGenerator, SkMutex) which allows sharing of one generator
diff --git a/src/core/SkImageGenerator.cpp b/src/core/SkImageGenerator.cpp
index 18a6ce2..2f209ca 100644
--- a/src/core/SkImageGenerator.cpp
+++ b/src/core/SkImageGenerator.cpp
@@ -45,6 +45,15 @@
     return success;
 }
 
+bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
+                                 const Options* opts) {
+    Options defaultOpts;
+    if (!opts) {
+        opts = &defaultOpts;
+    }
+    return this->onGetPixels(info, pixels, rowBytes, *opts);
+}
+
 bool SkImageGenerator::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) {
     SkASSERT(kIndex_8_SkColorType != info.colorType());
     if (kIndex_8_SkColorType == info.colorType()) {
diff --git a/src/image/SkImage_Generator.cpp b/src/image/SkImage_Generator.cpp
index 15977b9..51fb281 100644
--- a/src/image/SkImage_Generator.cpp
+++ b/src/image/SkImage_Generator.cpp
@@ -60,7 +60,8 @@
             // Try passing the caller's buffer directly down to the generator. If this fails we
             // may still succeed in the general case, as the generator may prefer some other
             // config, which we could then convert via SkBitmap::readPixels.
-            if (fCache.directGeneratePixels(dstInfo, dstPixels, dstRB, srcX, srcY)) {
+            if (fCache.directGeneratePixels(dstInfo, dstPixels, dstRB, srcX, srcY,
+                                            SkTransferFunctionBehavior::kRespect)) {
                 return true;
             }
             // else fall through
@@ -112,7 +113,10 @@
     }
     dst.allocPixels(dstInfo);
 
-    if (!fCache.directGeneratePixels(dstInfo, dst.getPixels(), dst.rowBytes(), 0, 0)) {
+    // Use kIgnore for transfer function behavior.  This is used by the SkColorSpaceXformCanvas,
+    // which wants to pre-xform the inputs but ignore the transfer function on blends.
+    if (!fCache.directGeneratePixels(dstInfo, dst.getPixels(), dst.rowBytes(), 0, 0,
+                                     SkTransferFunctionBehavior::kIgnore)) {
         return nullptr;
     }