Add color space to picture image as a creation parameter

This gives a picture image a preferred "native" color space, which
facilitates caching and other things.

BUG=skia:

Change-Id: I95988c14d17f96d7d870b3d1c3b723c36e2c170d
Reviewed-on: https://skia-review.googlesource.com/6158
Reviewed-by: Mike Reed <reed@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/gm/image.cpp b/gm/image.cpp
index c1d3372..0bdd994 100644
--- a/gm/image.cpp
+++ b/gm/image.cpp
@@ -246,7 +246,8 @@
     SkPictureRecorder recorder;
     draw(recorder.beginRecording(SkRect::MakeIWH(info.width(), info.height())));
     return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
-                                    info.dimensions(), nullptr, nullptr);
+                                    info.dimensions(), nullptr, nullptr,
+                                    SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named));
 }
 
 static sk_sp<SkImage> make_codec(const SkImageInfo& info, GrContext*, void (*draw)(SkCanvas*)) {
@@ -343,7 +344,8 @@
     SkPictureRecorder recorder;
     draw_opaque_contents(recorder.beginRecording(SkRect::MakeIWH(info.width(), info.height())));
     sk_sp<SkPicture> pict(recorder.finishRecordingAsPicture());
-    return SkImageGenerator::NewFromPicture(info.dimensions(), pict.get(), nullptr, nullptr);
+    return SkImageGenerator::NewFromPicture(info.dimensions(), pict.get(), nullptr, nullptr,
+                                            SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named));
 }
 
 static SkImageGenerator* gen_png(const SkImageInfo& info) {
diff --git a/gm/image_pict.cpp b/gm/image_pict.cpp
index d2e1eba..229f3c5 100644
--- a/gm/image_pict.cpp
+++ b/gm/image_pict.cpp
@@ -62,14 +62,15 @@
 
         // extract enough just for the oval.
         const SkISize size = SkISize::Make(100, 100);
+        auto srgbColorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
 
         SkMatrix matrix;
         matrix.setTranslate(-100, -100);
-        fImage0 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr);
+        fImage0 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr, srgbColorSpace);
         matrix.postTranslate(-50, -50);
         matrix.postRotate(45);
         matrix.postTranslate(50, 50);
-        fImage1 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr);
+        fImage1 = SkImage::MakeFromPicture(fPicture, size, &matrix, nullptr, srgbColorSpace);
     }
 
     void drawSet(SkCanvas* canvas) const {
@@ -107,7 +108,8 @@
 static SkImageGenerator* make_pic_generator(GrContext*, SkPicture* pic) {
     SkMatrix matrix;
     matrix.setTranslate(-100, -100);
-    return SkImageGenerator::NewFromPicture(SkISize::Make(100, 100), pic, &matrix, nullptr);
+    return SkImageGenerator::NewFromPicture(SkISize::Make(100, 100), pic, &matrix, nullptr,
+                                            SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named));
 }
 
 class RasterGenerator : public SkImageGenerator {
diff --git a/gm/image_shader.cpp b/gm/image_shader.cpp
index 49b1ed5..7803739 100644
--- a/gm/image_shader.cpp
+++ b/gm/image_shader.cpp
@@ -47,7 +47,8 @@
 }
 
 static sk_sp<SkImage> make_pict_gen(GrContext*, SkPicture* pic, const SkImageInfo& info) {
-    return SkImage::MakeFromPicture(sk_ref_sp(pic), info.dimensions(), nullptr, nullptr);
+    return SkImage::MakeFromPicture(sk_ref_sp(pic), info.dimensions(), nullptr, nullptr,
+                                    SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named));
 }
 
 static sk_sp<SkImage> make_encode_gen(GrContext* ctx, SkPicture* pic, const SkImageInfo& info) {
diff --git a/gm/pictureimagegenerator.cpp b/gm/pictureimagegenerator.cpp
index ab4c808..b247af2 100644
--- a/gm/pictureimagegenerator.cpp
+++ b/gm/pictureimagegenerator.cpp
@@ -138,6 +138,7 @@
             { SkISize::Make(200, 100), -1, -1, 0.5f },
         };
 
+        auto srgbColorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
         const unsigned kDrawsPerRow = 4;
         const SkScalar kDrawSize = 250;
 
@@ -154,10 +155,14 @@
             }
             std::unique_ptr<SkImageGenerator> gen(
                 SkImageGenerator::NewFromPicture(configs[i].size, fPicture.get(), &m,
-                                                 p.getAlpha() != 255 ? &p : nullptr));
+                                                 p.getAlpha() != 255 ? &p : nullptr,
+                                                 srgbColorSpace));
+
+            SkImageInfo bmInfo = gen->getInfo().makeColorSpace(
+                sk_ref_sp(canvas->imageInfo().colorSpace()));
+
             SkBitmap bm;
-            SkAssertResult(gen->tryGenerateBitmap(&bm, SkImageInfo::MakeN32Premul(configs[i].size),
-                                                  nullptr));
+            SkAssertResult(gen->tryGenerateBitmap(&bm, bmInfo, nullptr));
 
             const SkScalar x = kDrawSize * (i % kDrawsPerRow);
             const SkScalar y = kDrawSize * (i / kDrawsPerRow);
diff --git a/gm/verylargebitmap.cpp b/gm/verylargebitmap.cpp
index 08ca481..280d117 100644
--- a/gm/verylargebitmap.cpp
+++ b/gm/verylargebitmap.cpp
@@ -32,7 +32,8 @@
     SkPictureRecorder recorder;
     draw(recorder.beginRecording(SkRect::MakeIWH(width, height)), width, height, colors);
     return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
-                                    SkISize::Make(width, height), nullptr, nullptr);
+                                    SkISize::Make(width, height), nullptr, nullptr,
+                                    SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named));
 }
 
 typedef sk_sp<SkImage> (*ImageMakerProc)(int width, int height, SkColor colors[2]);
diff --git a/include/core/SkImage.h b/include/core/SkImage.h
index 2cbcb0a..100298a 100644
--- a/include/core/SkImage.h
+++ b/include/core/SkImage.h
@@ -154,8 +154,15 @@
                                                    const SkISize nv12Sizes[2], GrSurfaceOrigin,
                                                    sk_sp<SkColorSpace> = nullptr);
 
+    /**
+     *  Create a new image from the specified picture. The color space becomes a preferred
+     *  color space for playback of the picture when retrieving the rasterized image contents.
+     */
     static sk_sp<SkImage> MakeFromPicture(sk_sp<SkPicture>, const SkISize& dimensions,
-                                          const SkMatrix*, const SkPaint*);
+                                          const SkMatrix*, const SkPaint*, sk_sp<SkColorSpace>);
+
+    static sk_sp<SkImage> MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions,
+                                          const SkMatrix* matrix, const SkPaint* paint);
 
     static sk_sp<SkImage> MakeTextureFromPixmap(GrContext*, const SkPixmap&, SkBudgeted budgeted);
 
diff --git a/include/core/SkImageGenerator.h b/include/core/SkImageGenerator.h
index eace286..0d24d3a 100644
--- a/include/core/SkImageGenerator.h
+++ b/include/core/SkImageGenerator.h
@@ -241,7 +241,7 @@
      *  time.
      */
     static SkImageGenerator* NewFromPicture(const SkISize&, const SkPicture*, const SkMatrix*,
-                                            const SkPaint*);
+                                            const SkPaint*, sk_sp<SkColorSpace>);
 
     bool tryGenerateBitmap(SkBitmap* bm, const SkImageInfo& info, SkBitmap::Allocator* allocator);
 
diff --git a/src/core/SkPictureImageGenerator.cpp b/src/core/SkPictureImageGenerator.cpp
index d4cf92e..8e42d27 100644
--- a/src/core/SkPictureImageGenerator.cpp
+++ b/src/core/SkPictureImageGenerator.cpp
@@ -17,7 +17,7 @@
 class SkPictureImageGenerator : SkImageGenerator {
 public:
     static SkImageGenerator* Create(const SkISize&, const SkPicture*, const SkMatrix*,
-                                    const SkPaint*);
+                                    const SkPaint*, sk_sp<SkColorSpace>);
 
 protected:
     bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[],
@@ -30,7 +30,8 @@
 #endif
 
 private:
-    SkPictureImageGenerator(const SkISize&, const SkPicture*, const SkMatrix*, const SkPaint*);
+    SkPictureImageGenerator(const SkImageInfo& info, const SkPicture*, const SkMatrix*,
+                            const SkPaint*);
 
     sk_sp<const SkPicture> fPicture;
     SkMatrix               fMatrix;
@@ -40,17 +41,29 @@
 };
 
 SkImageGenerator* SkPictureImageGenerator::Create(const SkISize& size, const SkPicture* picture,
-                                const SkMatrix* matrix, const SkPaint* paint) {
+                                                  const SkMatrix* matrix, const SkPaint* paint,
+                                                  sk_sp<SkColorSpace> colorSpace) {
     if (!picture || size.isEmpty()) {
         return nullptr;
     }
 
-    return new SkPictureImageGenerator(size, picture, matrix, paint);
+    SkColorType colorType;
+    if (!colorSpace || colorSpace->gammaCloseToSRGB()) {
+        colorType = kN32_SkColorType;
+    } else if (colorSpace->gammaIsLinear()) {
+        colorType = kRGBA_F16_SkColorType;
+    } else {
+        return nullptr;
+    }
+
+    SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), colorType,
+                                         kPremul_SkAlphaType, std::move(colorSpace));
+    return new SkPictureImageGenerator(info, picture, matrix, paint);
 }
 
-SkPictureImageGenerator::SkPictureImageGenerator(const SkISize& size, const SkPicture* picture,
+SkPictureImageGenerator::SkPictureImageGenerator(const SkImageInfo& info, const SkPicture* picture,
                                                  const SkMatrix* matrix, const SkPaint* paint)
-    : INHERITED(SkImageInfo::MakeS32(size.width(), size.height(), kPremul_SkAlphaType))
+    : INHERITED(info)
     , fPicture(SkRef(picture)) {
 
     if (matrix) {
@@ -123,8 +136,9 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 SkImageGenerator* SkImageGenerator::NewFromPicture(const SkISize& size, const SkPicture* picture,
-                                                   const SkMatrix* matrix, const SkPaint* paint) {
-    return SkPictureImageGenerator::Create(size, picture, matrix, paint);
+                                                   const SkMatrix* matrix, const SkPaint* paint,
+                                                   sk_sp<SkColorSpace> colorSpace) {
+    return SkPictureImageGenerator::Create(size, picture, matrix, paint, std::move(colorSpace));
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
index 23f2e31..e34ca99 100644
--- a/src/core/SkPictureShader.cpp
+++ b/src/core/SkPictureShader.cpp
@@ -157,6 +157,7 @@
 }
 
 sk_sp<SkShader> SkPictureShader::refBitmapShader(const SkMatrix& viewMatrix, const SkMatrix* localM,
+                                                 SkColorSpace* dstColorSpace,
                                                  const int maxTextureSize) const {
     SkASSERT(fPicture && !fPicture->cullRect().isEmpty());
 
@@ -225,7 +226,8 @@
                                  SkMatrix::kFill_ScaleToFit);
 
         sk_sp<SkImage> tileImage(
-            SkImage::MakeFromPicture(fPicture, tileSize, &tileMatrix, nullptr));
+            SkImage::MakeFromPicture(fPicture, tileSize, &tileMatrix, nullptr,
+                                     sk_ref_sp(dstColorSpace)));
         if (!tileImage) {
             return nullptr;
         }
@@ -245,7 +247,8 @@
 }
 
 SkShader::Context* SkPictureShader::onCreateContext(const ContextRec& rec, void* storage) const {
-    sk_sp<SkShader> bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.fLocalMatrix));
+    sk_sp<SkShader> bitmapShader(this->refBitmapShader(*rec.fMatrix, rec.fLocalMatrix,
+                                                       rec.fDstColorSpace));
     if (!bitmapShader) {
         return nullptr;
     }
@@ -323,7 +326,7 @@
         maxTextureSize = args.fContext->caps()->maxTextureSize();
     }
     sk_sp<SkShader> bitmapShader(this->refBitmapShader(*args.fViewMatrix, args.fLocalMatrix,
-                                                       maxTextureSize));
+                                                       args.fDstColorSpace, maxTextureSize));
     if (!bitmapShader) {
         return nullptr;
     }
diff --git a/src/core/SkPictureShader.h b/src/core/SkPictureShader.h
index f2927a0..6de7e4a 100644
--- a/src/core/SkPictureShader.h
+++ b/src/core/SkPictureShader.h
@@ -41,6 +41,7 @@
     SkPictureShader(sk_sp<SkPicture>, TileMode, TileMode, const SkMatrix*, const SkRect*);
 
     sk_sp<SkShader> refBitmapShader(const SkMatrix&, const SkMatrix* localMatrix,
+                                    SkColorSpace* dstColorSpace,
                                     const int maxTextureSize = 0) const;
 
     sk_sp<SkPicture>    fPicture;
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 9aff820..7a71546 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -314,12 +314,18 @@
 }
 
 sk_sp<SkImage> SkImage::MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions,
-                                        const SkMatrix* matrix, const SkPaint* paint) {
+                                        const SkMatrix* matrix, const SkPaint* paint,
+                                        sk_sp<SkColorSpace> colorSpace) {
     if (!picture) {
         return nullptr;
     }
-    return MakeFromGenerator(SkImageGenerator::NewFromPicture(dimensions, picture.get(),
-                                                              matrix, paint));
+    return MakeFromGenerator(SkImageGenerator::NewFromPicture(dimensions, picture.get(), matrix,
+                                                              paint, std::move(colorSpace)));
+}
+
+sk_sp<SkImage> SkImage::MakeFromPicture(sk_sp<SkPicture> picture, const SkISize& dimensions,
+                                        const SkMatrix* matrix, const SkPaint* paint) {
+    return MakeFromPicture(std::move(picture), dimensions, matrix, paint, nullptr);
 }
 
 sk_sp<SkImage> SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRect& subset,
diff --git a/tests/ImageIsOpaqueTest.cpp b/tests/ImageIsOpaqueTest.cpp
index cc7255d..21ddb5d 100644
--- a/tests/ImageIsOpaqueTest.cpp
+++ b/tests/ImageIsOpaqueTest.cpp
@@ -124,7 +124,8 @@
         SkImage::MakeRasterCopy(pmap),
         GetResourceAsImage("mandrill_128.png"),
         GetResourceAsImage("color_wheel.jpg"),
-        SkImage::MakeFromPicture(make_picture(), { 10, 10 }, nullptr, nullptr),
+        SkImage::MakeFromPicture(make_picture(), { 10, 10 }, nullptr, nullptr,
+                                 SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named)),
     })
     {
         REPORTER_ASSERT(reporter, image->isAlphaOnly() == false);
diff --git a/tests/ImageTest.cpp b/tests/ImageTest.cpp
index 3b99394..c801d67 100644
--- a/tests/ImageTest.cpp
+++ b/tests/ImageTest.cpp
@@ -129,7 +129,8 @@
     SkCanvas* canvas = recorder.beginRecording(10, 10);
     canvas->clear(SK_ColorCYAN);
     return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(), SkISize::Make(10, 10),
-                                    nullptr, nullptr);
+                                    nullptr, nullptr,
+                                    SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named));
 };
 #endif
 // Want to ensure that our Release is called when the owning image is destroyed
diff --git a/tests/SkResourceCacheTest.cpp b/tests/SkResourceCacheTest.cpp
index c8da135..ed2ff74 100644
--- a/tests/SkResourceCacheTest.cpp
+++ b/tests/SkResourceCacheTest.cpp
@@ -329,7 +329,8 @@
             SkCanvas* canvas = recorder.beginRecording(10, 10);
             canvas->clear(SK_ColorCYAN);
             return SkImage::MakeFromPicture(recorder.finishRecordingAsPicture(),
-                                            SkISize::Make(10, 10), nullptr, nullptr);
+                                            SkISize::Make(10, 10), nullptr, nullptr,
+                                            SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named));
         });
     }
 }