Enable colorspace conversion while perserving legacy blending.

When requesting an SkImage from a android::Bitmap we will also
return a colorFilter that will perform the sRGB conversion at draw
time.

Bug: 62347704
Test: CtsUiRenderingTestCases, CtsGraphicsTestCases, CtsViewTestCases
Change-Id: Icc4694e2c42605e29fcc834c252bc21263bac658
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index c19c1a1..8727a1d 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -296,6 +296,7 @@
             colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f);
             colorVector[3] =      srcColorMatrix[19] / 255.0f;  // alpha is linear
         } else {
+            ALOGE("unsupported ColorFilter type: %s", colorFilter->getTypeName());
             LOG_ALWAYS_FATAL("unsupported ColorFilter");
         }
     } else {
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 0a642b6..9683d06 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -24,6 +24,8 @@
 #include "pipeline/skia/AnimatedDrawables.h"
 
 #include <SkCanvasStateUtils.h>
+#include <SkColorFilter.h>
+// TODO remove me!
 #include <SkColorSpaceXformCanvas.h>
 #include <SkDrawable.h>
 #include <SkDeque.h>
@@ -529,25 +531,49 @@
 // Canvas draw operations: Bitmaps
 // ----------------------------------------------------------------------------
 
-void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
-    mCanvas->drawImage(bitmap.makeImage(), left, top, paint);
+inline static const SkPaint* addFilter(const SkPaint* origPaint, SkPaint* tmpPaint,
+        sk_sp<SkColorFilter> colorFilter) {
+    if (colorFilter) {
+        if (origPaint) {
+            *tmpPaint = *origPaint;
+        }
+        tmpPaint->setColorFilter(colorFilter);
+        return tmpPaint;
+    } else {
+        return origPaint;
+    }
 }
 
-void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) {
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
+    SkPaint tmpPaint;
+    sk_sp<SkColorFilter> colorFilter;
+    sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+    mCanvas->drawImage(image, left, top, addFilter(paint, &tmpPaint, colorFilter));
+}
+
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
     SkAutoCanvasRestore acr(mCanvas, true);
     mCanvas->concat(matrix);
-    mCanvas->drawImage(hwuiBitmap.makeImage(), 0, 0, paint);
+
+    SkPaint tmpPaint;
+    sk_sp<SkColorFilter> colorFilter;
+    sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+    mCanvas->drawImage(image, 0, 0, addFilter(paint, &tmpPaint, colorFilter));
 }
 
-void SkiaCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
                             float srcRight, float srcBottom, float dstLeft, float dstTop,
                             float dstRight, float dstBottom, const SkPaint* paint) {
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-    mCanvas->drawImageRect(hwuiBitmap.makeImage(), srcRect, dstRect, paint);
+
+    SkPaint tmpPaint;
+    sk_sp<SkColorFilter> colorFilter;
+    sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+    mCanvas->drawImageRect(image, srcRect, dstRect, addFilter(paint, &tmpPaint, colorFilter));
 }
 
-void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeight,
+void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
         const float* vertices, const int* colors, const SkPaint* paint) {
     const int ptCount = (meshWidth + 1) * (meshHeight + 1);
     const int indexCount = meshWidth * meshHeight * 6;
@@ -565,8 +591,8 @@
 
     // cons up texture coordinates and indices
     {
-        const SkScalar w = SkIntToScalar(hwuiBitmap.width());
-        const SkScalar h = SkIntToScalar(hwuiBitmap.height());
+        const SkScalar w = SkIntToScalar(bitmap.width());
+        const SkScalar h = SkIntToScalar(bitmap.height());
         const SkScalar dx = w / meshWidth;
         const SkScalar dy = h / meshHeight;
 
@@ -627,17 +653,22 @@
         tmpPaint = *paint;
     }
 
-    sk_sp<SkImage> image = hwuiBitmap.makeImage();
-    tmpPaint.setShader(image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode));
+    sk_sp<SkColorFilter> colorFilter;
+    sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+    sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+    if(colorFilter) {
+        shader = shader->makeWithColorFilter(colorFilter);
+    }
+    tmpPaint.setShader(shader);
 
     mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint);
 }
 
-void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
+void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk,
         float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
 
     SkCanvas::Lattice lattice;
-    NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
+    NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
 
     lattice.fFlags = nullptr;
     int numFlags = 0;
@@ -654,7 +685,11 @@
 
     lattice.fBounds = nullptr;
     SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-    mCanvas->drawImageLattice(hwuiBitmap.makeImage().get(), lattice, dst, paint);
+
+    SkPaint tmpPaint;
+    sk_sp<SkColorFilter> colorFilter;
+    sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+    mCanvas->drawImageLattice(image.get(), lattice, dst, addFilter(paint, &tmpPaint, colorFilter));
 }
 
 void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 75b6d23..0aeb762 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -31,6 +31,7 @@
 #include <ui/PixelFormat.h>
 
 #include <SkCanvas.h>
+#include <SkToSRGBColorFilter.h>
 #include <SkImagePriv.h>
 
 namespace android {
@@ -208,11 +209,8 @@
     buffer->incStrong(buffer);
     setImmutable(); // HW bitmaps are always immutable
     if (uirenderer::Properties::isSkiaEnabled()) {
-        // GraphicBuffer should be in the display color space (Bitmap::createFrom is always
-        // passing SRGB). The code that uploads into a GraphicBuffer should do color conversion if
-        // needed.
         mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
-                mInfo.alphaType(), nullptr);
+                mInfo.alphaType(), mInfo.refColorSpace());
     }
 }
 
@@ -319,7 +317,7 @@
     return nullptr;
 }
 
-sk_sp<SkImage> Bitmap::makeImage() {
+sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) {
     sk_sp<SkImage> image = mImage;
     if (!image) {
         SkASSERT(!(isHardware() && uirenderer::Properties::isSkiaEnabled()));
@@ -330,12 +328,11 @@
         // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
         // internally and ~Bitmap won't be invoked.
         // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
-        if (uirenderer::Properties::isSkiaEnabled()) {
-            image = SkMakeImageInColorSpace(skiaBitmap, SkColorSpace::MakeSRGB(),
-                    skiaBitmap.getGenerationID(), kNever_SkCopyPixelsMode);
-        } else {
-            image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
-        }
+        image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
+    }
+    if(uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr
+            && !image->colorSpace()->isSRGB()) {
+        *outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace());
     }
     return image;
 }
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 634e764..fc27af9f 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -16,6 +16,7 @@
 #pragma once
 
 #include <SkBitmap.h>
+#include <SkColorFilter.h>
 #include <SkColorSpace.h>
 #include <SkImage.h>
 #include <SkImageInfo.h>
@@ -96,9 +97,18 @@
 
     GraphicBuffer* graphicBuffer();
 
-    // makeImage creates or returns a cached SkImage. Can be invoked from UI or render thread.
-    // Caching is supported only for HW Bitmaps with skia pipeline.
-    sk_sp<SkImage> makeImage();
+    /**
+     * Creates or returns a cached SkImage and is safe to be invoked from either
+     * the UI or RenderThread.
+     *
+     * @param outputColorFilter is a required param that will be populated by
+     *     this function if the bitmap's colorspace is not sRGB. If populated the
+     *     filter will convert colors from the bitmaps colorspace into sRGB. It
+     *     is the callers responsibility to use this colorFilter when drawing
+     *     this image into any destination that is presumed to be sRGB (i.e. a
+     *     buffer that has no colorspace defined).
+     */
+    sk_sp<SkImage> makeImage(sk_sp<SkColorFilter>* outputColorFilter);
 private:
     virtual ~Bitmap();
     void* getStorage() const;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index bf77446..5f8ee18 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -305,12 +305,6 @@
         return nullptr;
     }
 
-    auto colorSpace = info.colorSpace();
-    bool convertToSRGB = false;
-    if (colorSpace && (!colorSpace->isSRGB())) {
-        isSupported = false;
-        convertToSRGB = true;
-    }
 
     SkBitmap bitmap;
     if (isSupported) {
@@ -319,7 +313,7 @@
         bitmap.allocPixels(SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(),
                 nullptr));
         bitmap.eraseColor(0);
-        if (info.colorType() == kRGBA_F16_SkColorType || convertToSRGB) {
+        if (info.colorType() == kRGBA_F16_SkColorType) {
             // Drawing RGBA_F16 onto ARGB_8888 is not supported
             skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
                     bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index d08a62c..a8463ec 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -167,7 +167,8 @@
     GrContext* context = thread.getGrContext();
     if (context) {
         ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
-        auto image = bitmap->makeImage();
+        sk_sp<SkColorFilter> colorFilter;
+        auto image = bitmap->makeImage(&colorFilter);
         if (image.get() && !bitmap->isHardware()) {
             SkImage_pinAsTexture(image.get(), context);
             SkImage_unpinAsTexture(image.get(), context);
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index a0cce98..6c88e93 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -145,10 +145,14 @@
 // Recording Canvas draw operations: Bitmaps
 // ----------------------------------------------------------------------------
 
-inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPaint) {
-    if (origPaint && origPaint->isAntiAlias()) {
-        *tmpPaint = *origPaint;
+inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint,
+        sk_sp<SkColorFilter> colorFilter) {
+    if ((origPaint && origPaint->isAntiAlias()) || colorFilter) {
+        if (origPaint) {
+            *tmpPaint = *origPaint;
+        }
         tmpPaint->setAntiAlias(false);
+        tmpPaint->setColorFilter(colorFilter);
         return tmpPaint;
     } else {
         return origPaint;
@@ -156,9 +160,10 @@
 }
 
 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
-    sk_sp<SkImage> image = bitmap.makeImage();
     SkPaint tmpPaint;
-    mRecorder.drawImage(image, left, top, nonAAPaint(paint, &tmpPaint));
+    sk_sp<SkColorFilter> colorFilter;
+    sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+    mRecorder.drawImage(image, left, top, bitmapPaint(paint, &tmpPaint, colorFilter));
     // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
     // it is not safe to store a raw SkImage pointer, because the image object will be destroyed
     // when this function ends.
@@ -167,36 +172,40 @@
     }
 }
 
-void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
         const SkPaint* paint) {
     SkAutoCanvasRestore acr(&mRecorder, true);
     concat(matrix);
-    sk_sp<SkImage> image = hwuiBitmap.makeImage();
+
     SkPaint tmpPaint;
-    mRecorder.drawImage(image, 0, 0, nonAAPaint(paint, &tmpPaint));
-    if (!hwuiBitmap.isImmutable() && image.get() && !image->unique()) {
+    sk_sp<SkColorFilter> colorFilter;
+    sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+    mRecorder.drawImage(image, 0, 0, bitmapPaint(paint, &tmpPaint, colorFilter));
+    if (!bitmap.isImmutable() && image.get() && !image->unique()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
 }
 
-void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
         float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
         float dstBottom, const SkPaint* paint) {
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-    sk_sp<SkImage> image = hwuiBitmap.makeImage();
+
     SkPaint tmpPaint;
-    mRecorder.drawImageRect(image, srcRect, dstRect, nonAAPaint(paint, &tmpPaint));
-    if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty()
+    sk_sp<SkColorFilter> colorFilter;
+    sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+    mRecorder.drawImageRect(image, srcRect, dstRect, bitmapPaint(paint, &tmpPaint, colorFilter));
+    if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty()
             && !dstRect.isEmpty()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
 }
 
-void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
+void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk,
         float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
     SkCanvas::Lattice lattice;
-    NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
+    NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
 
     lattice.fFlags = nullptr;
     int numFlags = 0;
@@ -213,11 +222,13 @@
 
     lattice.fBounds = nullptr;
     SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-    sk_sp<SkImage> image = hwuiBitmap.makeImage();
 
     SkPaint tmpPaint;
-    mRecorder.drawImageLattice(image.get(), lattice, dst, nonAAPaint(paint, &tmpPaint));
-    if (!hwuiBitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
+    sk_sp<SkColorFilter> colorFilter;
+    sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
+    mRecorder.drawImageLattice(image.get(), lattice, dst,
+            bitmapPaint(paint, &tmpPaint, colorFilter));
+    if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
 }
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index 4797dec..0f2dc03 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -46,7 +46,8 @@
         });
 
         SkPaint paint;
-        sk_sp<SkImage> image = hwuiBitmap->makeImage();
+        sk_sp<SkColorFilter> colorFilter;
+        sk_sp<SkImage> image = hwuiBitmap->makeImage(&colorFilter);
         sk_sp<SkShader> repeatShader = image->makeShader(
                 SkShader::TileMode::kRepeat_TileMode,
                 SkShader::TileMode::kRepeat_TileMode,
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index c246eba..960b053 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -75,7 +75,8 @@
     void doFrame(int frameNr) override { }
 
     sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) {
-        sk_sp<SkImage> image = bitmap.makeImage();
+        sk_sp<SkColorFilter> colorFilter;
+        sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
         return image->makeShader(SkShader::TileMode::kClamp_TileMode,
                 SkShader::TileMode::kClamp_TileMode);
     }