Merge latest Skia into master (2 commits)

https://skia.googlesource.com/skia.git/+log/20ece3a..a2cedff

Test: Presubmit checks will test this change.
Change-Id: I6a830535fb52cc174ff9c07cd3136388361dc141
diff --git a/gm/gaussianedge.cpp b/gm/gaussianedge.cpp
index 7a45118..eca8495 100644
--- a/gm/gaussianedge.cpp
+++ b/gm/gaussianedge.cpp
@@ -6,8 +6,9 @@
  */
 
 #include "gm.h"
-#include "SkRRect.h"
+#include "SkColorFilter.h"
 #include "SkGaussianEdgeShader.h"
+#include "SkRRect.h"
 
 //#define VIZ 1
 
@@ -118,8 +119,10 @@
 
             SkPaint basePaint;
             basePaint.setAntiAlias(true);
-            basePaint.setShader(SkGaussianEdgeShader::Make());
             basePaint.setColor(SkColorSetARGB(255, (4 * blurRad) >> 8, (4 * blurRad) & 0xff, 0));
+            basePaint.setShader(SkGaussianEdgeShader::Make());
+            basePaint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorRED,
+                                                                   SkBlendMode::kModulate));
 
             //----
             paints[0] = basePaint;
diff --git a/gn/effects.gni b/gn/effects.gni
index 3ae4ebe..cc2b8ed 100644
--- a/gn/effects.gni
+++ b/gn/effects.gni
@@ -40,6 +40,7 @@
   "$_src/effects/SkEmbossMaskFilter.cpp",
   "$_src/effects/SkImageSource.cpp",
   "$_src/effects/SkGaussianEdgeShader.cpp",
+  "$_src/effects/SkGaussianEdgeShader.h",
   "$_src/effects/SkHighContrastFilter.cpp",
   "$_src/effects/SkLayerDrawLooper.cpp",
   "$_src/effects/SkLayerRasterizer.cpp",
@@ -106,7 +107,6 @@
   "$_include/effects/SkDiscretePathEffect.h",
   "$_include/effects/SkDisplacementMapEffect.h",
   "$_include/effects/SkDropShadowImageFilter.h",
-  "$_include/effects/SkGaussianEdgeShader.h",
   "$_include/effects/SkGradientShader.h",
   "$_include/effects/SkImageSource.h",
   "$_include/effects/SkLayerDrawLooper.h",
diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h
index 700dbc2..fd25a23 100644
--- a/include/core/SkBitmap.h
+++ b/include/core/SkBitmap.h
@@ -657,7 +657,9 @@
      *  This is logically the same as creating a bitmap around src, and calling readPixels on it
      *  with this bitmap as the dst.
      */
-    bool writePixels(const SkPixmap& src, int dstX, int dstY);
+    bool writePixels(const SkPixmap& src, int dstX, int dstY) {
+        return this->writePixels(src, dstX, dstY, SkTransferFunctionBehavior::kRespect);
+    }
     bool writePixels(const SkPixmap& src) {
         return this->writePixels(src, 0, 0);
     }
@@ -777,6 +779,8 @@
     uint32_t                  fRowBytes;
     uint8_t                   fFlags;
 
+    bool writePixels(const SkPixmap& src, int x, int y, SkTransferFunctionBehavior behavior);
+
     /*  Unreference any pixelrefs or colortables
     */
     void freePixels();
@@ -785,6 +789,7 @@
     static void WriteRawPixels(SkWriteBuffer*, const SkBitmap&);
     static bool ReadRawPixels(SkReadBuffer*, SkBitmap*);
 
+    friend class SkImage_Raster;
     friend class SkReadBuffer;        // unflatten, rawpixels
     friend class SkBinaryWriteBuffer; // rawpixels
     friend struct SkBitmapProcState;
diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp
index 4a55e1a..0a999ce 100644
--- a/src/core/SkBitmap.cpp
+++ b/src/core/SkBitmap.cpp
@@ -709,7 +709,8 @@
     return this->readPixels(dst.info(), dst.writable_addr(), dst.rowBytes(), srcX, srcY);
 }
 
-bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY) {
+bool SkBitmap::writePixels(const SkPixmap& src, int dstX, int dstY,
+                           SkTransferFunctionBehavior behavior) {
     SkAutoPixmapUnlock dst;
     if (!this->requestLock(&dst)) {
         return false;
@@ -727,7 +728,7 @@
     void* dstPixels = this->getAddr(rec.fX, rec.fY);
     const SkImageInfo dstInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
     SkConvertPixels(dstInfo, dstPixels, this->rowBytes(), rec.fInfo, rec.fPixels, rec.fRowBytes,
-                    src.ctable());
+                    src.ctable(), behavior);
     return true;
 }
 
@@ -848,7 +849,8 @@
     }
     const SkPixmap& pmap = apl.pixmap();
     SkConvertPixels(SkImageInfo::MakeA8(pmap.width(), pmap.height()), alpha, alphaRowBytes,
-                    pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable());
+                    pmap.info(), pmap.addr(), pmap.rowBytes(), pmap.ctable(),
+                    SkTransferFunctionBehavior::kRespect);
     return true;
 }
 
diff --git a/src/core/SkConvertPixels.cpp b/src/core/SkConvertPixels.cpp
index 787acb9..b919f5d 100644
--- a/src/core/SkConvertPixels.cpp
+++ b/src/core/SkConvertPixels.cpp
@@ -5,7 +5,7 @@
  * found in the LICENSE file.
  */
 
-#include "SkColorSpaceXform.h"
+#include "SkColorSpaceXform_Base.h"
 #include "SkColorSpaceXformPriv.h"
 #include "SkColorTable.h"
 #include "SkConvertPixels.h"
@@ -87,9 +87,13 @@
 }
 
 // Fast Path 3: Color space xform.
-static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo) {
-    if (kUnpremul_SkAlphaType == dstInfo.alphaType() && kPremul_SkAlphaType == srcInfo.alphaType())
-    {
+static inline bool optimized_color_xform(const SkImageInfo& dstInfo, const SkImageInfo& srcInfo,
+                                         SkTransferFunctionBehavior behavior) {
+    // Unpremultiplication is unsupported by SkColorSpaceXform.  Note that if |src| is non-linearly
+    // premultiplied, we're always going to have to unpremultiply before doing anything.
+    if (kPremul_SkAlphaType == srcInfo.alphaType() &&
+            (kUnpremul_SkAlphaType == dstInfo.alphaType() ||
+             SkTransferFunctionBehavior::kIgnore == behavior)) {
         return false;
     }
 
@@ -115,7 +119,7 @@
 
 static inline void apply_color_xform(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
                                      const SkImageInfo& srcInfo, const void* srcPixels,
-                                     size_t srcRB) {
+                                     size_t srcRB, SkTransferFunctionBehavior behavior) {
     SkColorSpaceXform::ColorFormat dstFormat = select_xform_format(dstInfo.colorType());
     SkColorSpaceXform::ColorFormat srcFormat = select_xform_format(srcInfo.colorType());
     SkAlphaType xformAlpha;
@@ -142,8 +146,8 @@
             break;
     }
 
-    std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(srcInfo.colorSpace(),
-                                                                      dstInfo.colorSpace());
+    std::unique_ptr<SkColorSpaceXform> xform =
+            SkColorSpaceXform_Base::New(srcInfo.colorSpace(), dstInfo.colorSpace(), behavior);
     SkASSERT(xform);
 
     for (int y = 0; y < dstInfo.height(); y++) {
@@ -158,14 +162,14 @@
 template <typename T>
 void do_index8(const SkImageInfo& dstInfo, T* dstPixels, size_t dstRB,
                const SkImageInfo& srcInfo, const uint8_t* srcPixels, size_t srcRB,
-               SkColorTable* ctable) {
+               SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
     T dstCTable[256];
     int count = ctable->count();
     SkImageInfo srcInfo8888 = srcInfo.makeColorType(kN32_SkColorType).makeWH(count, 1);
     SkImageInfo dstInfoCT = dstInfo.makeWH(count, 1);
     size_t rowBytes = count * sizeof(T);
     SkConvertPixels(dstInfoCT, dstCTable, rowBytes, srcInfo8888, ctable->readColors(), rowBytes,
-                    nullptr);
+                    nullptr, behavior);
 
     for (int y = 0; y < dstInfo.height(); y++) {
         for (int x = 0; x < dstInfo.width(); x++) {
@@ -178,21 +182,25 @@
 
 void convert_from_index8(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
                          const SkImageInfo& srcInfo, const uint8_t* srcPixels, size_t srcRB,
-                         SkColorTable* ctable) {
+                         SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
     switch (dstInfo.colorType()) {
         case kAlpha_8_SkColorType:
-            do_index8(dstInfo, (uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
+            do_index8(dstInfo, (uint8_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
+                      behavior);
             break;
         case kRGB_565_SkColorType:
         case kARGB_4444_SkColorType:
-            do_index8(dstInfo, (uint16_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
+            do_index8(dstInfo, (uint16_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
+                      behavior);
             break;
         case kRGBA_8888_SkColorType:
         case kBGRA_8888_SkColorType:
-            do_index8(dstInfo, (uint32_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
+            do_index8(dstInfo, (uint32_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
+                      behavior);
             break;
         case kRGBA_F16_SkColorType:
-            do_index8(dstInfo, (uint64_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable);
+            do_index8(dstInfo, (uint64_t*) dstPixels, dstRB, srcInfo, srcPixels, srcRB, ctable,
+                      behavior);
             break;
         default:
             SkASSERT(false);
@@ -267,7 +275,7 @@
 // Default: Use the pipeline.
 static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size_t dstRB,
                                   const SkImageInfo& srcInfo, const void* srcRow, size_t srcRB,
-                                  bool isColorAware) {
+                                  bool isColorAware, SkTransferFunctionBehavior behavior) {
     SkRasterPipeline pipeline;
     switch (srcInfo.colorType()) {
         case kRGBA_8888_SkColorType:
@@ -294,6 +302,12 @@
             break;
     }
 
+    SkAlphaType premulState = srcInfo.alphaType();
+    if (kPremul_SkAlphaType == premulState && SkTransferFunctionBehavior::kIgnore == behavior) {
+        pipeline.append(SkRasterPipeline::unpremul);
+        premulState = kUnpremul_SkAlphaType;
+    }
+
     if (isColorAware && srcInfo.gammaCloseToSRGB()) {
         pipeline.append_from_srgb(srcInfo.alphaType());
     }
@@ -304,18 +318,32 @@
                                               dstInfo.colorSpace()));
     }
 
-    SkAlphaType sat = srcInfo.alphaType();
     SkAlphaType dat = dstInfo.alphaType();
-    if (sat == kPremul_SkAlphaType && dat == kUnpremul_SkAlphaType) {
-        pipeline.append(SkRasterPipeline::unpremul);
-    } else if (sat == kUnpremul_SkAlphaType && dat == kPremul_SkAlphaType) {
-        pipeline.append(SkRasterPipeline::premul);
+    if (SkTransferFunctionBehavior::kRespect == behavior) {
+        if (kPremul_SkAlphaType == premulState && kUnpremul_SkAlphaType == dat) {
+            pipeline.append(SkRasterPipeline::unpremul);
+            premulState = kUnpremul_SkAlphaType;
+        } else if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat) {
+            pipeline.append(SkRasterPipeline::premul);
+            premulState = kPremul_SkAlphaType;
+        }
     }
 
     if (isColorAware && dstInfo.gammaCloseToSRGB()) {
         pipeline.append(SkRasterPipeline::to_srgb);
     }
 
+    if (kUnpremul_SkAlphaType == premulState && kPremul_SkAlphaType == dat &&
+        SkTransferFunctionBehavior::kIgnore == behavior)
+    {
+        pipeline.append(SkRasterPipeline::premul);
+        premulState = kPremul_SkAlphaType;
+    }
+
+    // The final premul state must equal the dst alpha type.  Note that if we are "converting"
+    // opaque to another alpha type, there's no need to worry about multiplication.
+    SkASSERT(premulState == dat || kOpaque_SkAlphaType == srcInfo.alphaType());
+
     switch (dstInfo.colorType()) {
         case kRGBA_8888_SkColorType:
             pipeline.append(SkRasterPipeline::store_8888, &dstRow);
@@ -349,7 +377,7 @@
 
 void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRB,
                      const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRB,
-                     SkColorTable* ctable) {
+                     SkColorTable* ctable, SkTransferFunctionBehavior behavior) {
     SkASSERT(dstInfo.dimensions() == srcInfo.dimensions());
     SkASSERT(SkImageInfoValidConversion(dstInfo, srcInfo));
 
@@ -369,8 +397,8 @@
     }
 
     // Fast Path 3: Color space xform.
-    if (isColorAware && optimized_color_xform(dstInfo, srcInfo)) {
-        apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB);
+    if (isColorAware && optimized_color_xform(dstInfo, srcInfo, behavior)) {
+        apply_color_xform(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, behavior);
         return;
     }
 
@@ -378,7 +406,7 @@
     if (kIndex_8_SkColorType == srcInfo.colorType()) {
         SkASSERT(ctable);
         convert_from_index8(dstInfo, dstPixels, dstRB, srcInfo, (const uint8_t*) srcPixels, srcRB,
-                            ctable);
+                            ctable, behavior);
         return;
     }
 
@@ -389,5 +417,6 @@
     }
 
     // Default: Use the pipeline.
-    convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware);
+    convert_with_pipeline(dstInfo, dstPixels, dstRB, srcInfo, srcPixels, srcRB, isColorAware,
+                          behavior);
 }
diff --git a/src/core/SkConvertPixels.h b/src/core/SkConvertPixels.h
index aa641e5..c825d84 100644
--- a/src/core/SkConvertPixels.h
+++ b/src/core/SkConvertPixels.h
@@ -15,7 +15,7 @@
 
 void SkConvertPixels(const SkImageInfo& dstInfo, void* dstPixels, size_t dstRowBytes,
                      const SkImageInfo& srcInfo, const void* srcPixels, size_t srcRowBytes,
-                     SkColorTable* srcCTable = nullptr);
+                     SkColorTable* srcCTable, SkTransferFunctionBehavior behavior);
 
 static inline void SkRectMemcpy(void* dst, size_t dstRB, const void* src, size_t srcRB,
                                 size_t bytesPerRow, int rowCount) {
diff --git a/src/core/SkPixmap.cpp b/src/core/SkPixmap.cpp
index 62dda16..7eac6c4 100644
--- a/src/core/SkPixmap.cpp
+++ b/src/core/SkPixmap.cpp
@@ -98,7 +98,7 @@
     const void* srcPixels = this->addr(rec.fX, rec.fY);
     const SkImageInfo srcInfo = fInfo.makeWH(rec.fInfo.width(), rec.fInfo.height());
     SkConvertPixels(rec.fInfo, rec.fPixels, rec.fRowBytes, srcInfo, srcPixels, this->rowBytes(),
-                    this->ctable());
+                    this->ctable(), SkTransferFunctionBehavior::kRespect);
     return true;
 }
 
diff --git a/include/effects/SkGaussianEdgeShader.h b/src/effects/SkGaussianEdgeShader.h
similarity index 100%
rename from include/effects/SkGaussianEdgeShader.h
rename to src/effects/SkGaussianEdgeShader.h
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 30262dd..547bdbf 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -374,7 +374,9 @@
         src.setColorSpace(SkColorSpace::MakeSRGB());
     }
 
-    SkAssertResult(dst.writePixels(src));
+    // 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.
+    SkAssertResult(dst.writePixels(src, 0, 0, SkTransferFunctionBehavior::kIgnore));
     dst.setImmutable();
     return SkImage::MakeFromBitmap(dst);
 }
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
index 97d3b67..df4dde3 100644
--- a/src/ports/SkGlobalInitialization_default.cpp
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -23,8 +23,7 @@
 #include "SkDisplacementMapEffect.h"
 #include "SkDropShadowImageFilter.h"
 #include "../../src/effects/SkEmbossMaskFilter.h"
-#include "SkGaussianEdgeShader.h"
-#include "SkRRectsGaussianEdgeMaskFilter.h"
+#include "../../src/effects/SkGaussianEdgeShader.h"
 #include "SkGradientShader.h"
 #include "SkHighContrastFilter.h"
 #include "SkImageSource.h"
@@ -44,6 +43,7 @@
 #include "SkPaintImageFilter.h"
 #include "SkPerlinNoiseShader.h"
 #include "SkPictureImageFilter.h"
+#include "SkRRectsGaussianEdgeMaskFilter.h"
 #include "SkTableColorFilter.h"
 #include "SkTileImageFilter.h"
 #include "SkXfermodeImageFilter.h"