Add jpeg encoder alpha handling option

This instructs us on how to encode jpegs when the src
image has alpha.  The original behavior is to ignore
the alpha channel.  This CL adds the option to blend
the pixels onto opaque black.

Note that kBlendOnBlack and kIgnore are identical
unless the input alpha type is kUnpremul.

Bug: 713862
Bug: skia:1501
Change-Id: I4891c70bb0ccd83f7974c359bd40a2143b5c49ac
Reviewed-on: https://skia-review.googlesource.com/15817
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Matt Sarett <msarett@google.com>
diff --git a/src/images/SkJpegEncoder.cpp b/src/images/SkJpegEncoder.cpp
index fd88a5c..d87fed8 100644
--- a/src/images/SkJpegEncoder.cpp
+++ b/src/images/SkJpegEncoder.cpp
@@ -35,7 +35,7 @@
         return std::unique_ptr<SkJpegEncoderMgr>(new SkJpegEncoderMgr(stream));
     }
 
-    bool setParams(const SkImageInfo& srcInfo);
+    bool setParams(const SkImageInfo& srcInfo, const SkJpegEncoder::Options& options);
 
     jpeg_compress_struct* cinfo() { return &fCInfo; }
 
@@ -65,15 +65,36 @@
     transform_scanline_proc fProc;
 };
 
-bool SkJpegEncoderMgr::setParams(const SkImageInfo& srcInfo) {
+bool SkJpegEncoderMgr::setParams(const SkImageInfo& srcInfo, const SkJpegEncoder::Options& options)
+{
+    auto chooseProc8888 = [&]() {
+        if (kUnpremul_SkAlphaType != srcInfo.alphaType() ||
+            SkJpegEncoder::AlphaOption::kIgnore == options.fAlphaOption)
+        {
+            return (transform_scanline_proc) nullptr;
+        }
+
+        // Note that kRespect mode is only supported with sRGB or linear transfer functions.
+        // The legacy code path is incidentally correct when the transfer function is linear.
+        const bool isSRGBTransferFn = srcInfo.gammaCloseToSRGB() &&
+                (SkTransferFunctionBehavior::kRespect == options.fBlendBehavior);
+        if (isSRGBTransferFn) {
+            return transform_scanline_to_premul_linear;
+        } else {
+            return transform_scanline_to_premul_legacy;
+        }
+    };
+
     J_COLOR_SPACE jpegColorType = JCS_EXT_RGBA;
     int numComponents = 0;
     switch (srcInfo.colorType()) {
         case kRGBA_8888_SkColorType:
+            fProc = chooseProc8888();
             jpegColorType = JCS_EXT_RGBA;
             numComponents = 4;
             break;
         case kBGRA_8888_SkColorType:
+            fProc = chooseProc8888();
             jpegColorType = JCS_EXT_BGRA;
             numComponents = 4;
             break;
@@ -83,11 +104,19 @@
             numComponents = 3;
             break;
         case kARGB_4444_SkColorType:
+            if (SkJpegEncoder::AlphaOption::kBlendOnBlack == options.fAlphaOption) {
+                return false;
+            }
+
             fProc = transform_scanline_444;
             jpegColorType = JCS_RGB;
             numComponents = 3;
             break;
         case kIndex_8_SkColorType:
+            if (SkJpegEncoder::AlphaOption::kBlendOnBlack == options.fAlphaOption) {
+                return false;
+            }
+
             fProc = transform_scanline_index8_opaque;
             jpegColorType = JCS_RGB;
             numComponents = 3;
@@ -98,11 +127,18 @@
             numComponents = 1;
             break;
         case kRGBA_F16_SkColorType:
-            if (!srcInfo.colorSpace() || !srcInfo.colorSpace()->gammaIsLinear()) {
+            if (!srcInfo.colorSpace() || !srcInfo.colorSpace()->gammaIsLinear() ||
+                    SkTransferFunctionBehavior::kRespect != options.fBlendBehavior) {
                 return false;
             }
 
-            fProc = transform_scanline_F16_to_8888;
+            if (kUnpremul_SkAlphaType != srcInfo.alphaType() ||
+                SkJpegEncoder::AlphaOption::kIgnore == options.fAlphaOption)
+            {
+                fProc = transform_scanline_F16_to_8888;
+            } else {
+                fProc = transform_scanline_F16_to_premul_8888;
+            }
             jpegColorType = JCS_EXT_RGBA;
             numComponents = 4;
             break;
@@ -125,7 +161,7 @@
 
 std::unique_ptr<SkJpegEncoder> SkJpegEncoder::Make(SkWStream* dst, const SkPixmap& src,
                                                    const Options& options) {
-    if (!SkPixmapIsValid(src, SkTransferFunctionBehavior::kIgnore)) {
+    if (!SkPixmapIsValid(src, options.fBlendBehavior)) {
         return nullptr;
     }
 
@@ -134,7 +170,7 @@
         return nullptr;
     }
 
-    if (!encoderMgr->setParams(src.info())) {
+    if (!encoderMgr->setParams(src.info(), options)) {
         return nullptr;
     }