Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb0c8fc3 authored by Derek Sollenberger's avatar Derek Sollenberger Committed by Stan Iliev
Browse files

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
parent 25b14a1a
Loading
Loading
Loading
Loading
+10 −8
Original line number Original line Diff line number Diff line
#include "GraphicsJNI.h"
#include "GraphicsJNI.h"
#include "SkColorFilter.h"
#include "SkGradientShader.h"
#include "SkGradientShader.h"
#include "SkImagePriv.h"
#include "SkImagePriv.h"
#include "SkShader.h"
#include "SkShader.h"
@@ -64,28 +65,29 @@ static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, j
        jint tileModeX, jint tileModeY) {
        jint tileModeX, jint tileModeY) {
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
    sk_sp<SkImage> image;
    sk_sp<SkImage> image;
    sk_sp<SkColorFilter> colorFilter;
    if (jbitmap) {
    if (jbitmap) {
        // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
        // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
        // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
        // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
        image = android::bitmap::toBitmap(env, jbitmap).makeImage();
        image = android::bitmap::toBitmap(env, jbitmap).makeImage(&colorFilter);
    }
    }


    if (!image.get()) {
    if (!image.get()) {
        SkBitmap bitmap;
        SkBitmap bitmap;
        image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
        image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
    }
    }
    sk_sp<SkShader> baseShader = image->makeShader(
    sk_sp<SkShader> shader = image->makeShader(
            (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
            (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);


    SkShader* shader;
    if (matrix) {
    if (matrix) {
        shader = baseShader->makeWithLocalMatrix(*matrix).release();
        shader = shader->makeWithLocalMatrix(*matrix);
    } else {
    }
        shader = baseShader.release();
    if(colorFilter) {
        shader = shader->makeWithColorFilter(colorFilter);
    }
    }


    ThrowIAE_IfNull(env, shader);
    ThrowIAE_IfNull(env, shader.get());
    return reinterpret_cast<jlong>(shader);
    return reinterpret_cast<jlong>(shader.release());
}
}


///////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////
+1 −0
Original line number Original line Diff line number Diff line
@@ -296,6 +296,7 @@ void GlopBuilder::setFill(int color, float alphaScale,
            colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f);
            colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f);
            colorVector[3] =      srcColorMatrix[19] / 255.0f;  // alpha is linear
            colorVector[3] =      srcColorMatrix[19] / 255.0f;  // alpha is linear
        } else {
        } else {
            ALOGE("unsupported ColorFilter type: %s", colorFilter->getTypeName());
            LOG_ALWAYS_FATAL("unsupported ColorFilter");
            LOG_ALWAYS_FATAL("unsupported ColorFilter");
        }
        }
    } else {
    } else {
+48 −13
Original line number Original line Diff line number Diff line
@@ -24,6 +24,8 @@
#include "pipeline/skia/AnimatedDrawables.h"
#include "pipeline/skia/AnimatedDrawables.h"


#include <SkCanvasStateUtils.h>
#include <SkCanvasStateUtils.h>
#include <SkColorFilter.h>
// TODO remove me!
#include <SkColorSpaceXformCanvas.h>
#include <SkColorSpaceXformCanvas.h>
#include <SkDrawable.h>
#include <SkDrawable.h>
#include <SkDeque.h>
#include <SkDeque.h>
@@ -529,25 +531,49 @@ void SkiaCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, cons
// Canvas draw operations: Bitmaps
// Canvas draw operations: Bitmaps
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------


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& bitmap, float left, float top, const SkPaint* paint) {
void SkiaCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
    mCanvas->drawImage(bitmap.makeImage(), left, top, 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& hwuiBitmap, const SkMatrix& matrix, const SkPaint* paint) {
void SkiaCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
    SkAutoCanvasRestore acr(mCanvas, true);
    SkAutoCanvasRestore acr(mCanvas, true);
    mCanvas->concat(matrix);
    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 srcRight, float srcBottom, float dstLeft, float dstTop,
                            float dstRight, float dstBottom, const SkPaint* paint) {
                            float dstRight, float dstBottom, const SkPaint* paint) {
    SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
    SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
    SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
    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 float* vertices, const int* colors, const SkPaint* paint) {
    const int ptCount = (meshWidth + 1) * (meshHeight + 1);
    const int ptCount = (meshWidth + 1) * (meshHeight + 1);
    const int indexCount = meshWidth * meshHeight * 6;
    const int indexCount = meshWidth * meshHeight * 6;
@@ -565,8 +591,8 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh


    // cons up texture coordinates and indices
    // cons up texture coordinates and indices
    {
    {
        const SkScalar w = SkIntToScalar(hwuiBitmap.width());
        const SkScalar w = SkIntToScalar(bitmap.width());
        const SkScalar h = SkIntToScalar(hwuiBitmap.height());
        const SkScalar h = SkIntToScalar(bitmap.height());
        const SkScalar dx = w / meshWidth;
        const SkScalar dx = w / meshWidth;
        const SkScalar dy = h / meshHeight;
        const SkScalar dy = h / meshHeight;


@@ -627,17 +653,22 @@ void SkiaCanvas::drawBitmapMesh(Bitmap& hwuiBitmap, int meshWidth, int meshHeigh
        tmpPaint = *paint;
        tmpPaint = *paint;
    }
    }


    sk_sp<SkImage> image = hwuiBitmap.makeImage();
    sk_sp<SkColorFilter> colorFilter;
    tmpPaint.setShader(image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode));
    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);
    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) {
        float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {


    SkCanvas::Lattice lattice;
    SkCanvas::Lattice lattice;
    NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
    NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());


    lattice.fFlags = nullptr;
    lattice.fFlags = nullptr;
    int numFlags = 0;
    int numFlags = 0;
@@ -654,7 +685,11 @@ void SkiaCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,


    lattice.fBounds = nullptr;
    lattice.fBounds = nullptr;
    SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
    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) {
void SkiaCanvas::drawVectorDrawable(VectorDrawableRoot* vectorDrawable) {
+8 −11
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@
#include <ui/PixelFormat.h>
#include <ui/PixelFormat.h>


#include <SkCanvas.h>
#include <SkCanvas.h>
#include <SkToSRGBColorFilter.h>
#include <SkImagePriv.h>
#include <SkImagePriv.h>


namespace android {
namespace android {
@@ -208,11 +209,8 @@ Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
    buffer->incStrong(buffer);
    buffer->incStrong(buffer);
    setImmutable(); // HW bitmaps are always immutable
    setImmutable(); // HW bitmaps are always immutable
    if (uirenderer::Properties::isSkiaEnabled()) {
    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),
        mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
                mInfo.alphaType(), nullptr);
                mInfo.alphaType(), mInfo.refColorSpace());
    }
    }
}
}


@@ -319,7 +317,7 @@ GraphicBuffer* Bitmap::graphicBuffer() {
    return nullptr;
    return nullptr;
}
}


sk_sp<SkImage> Bitmap::makeImage() {
sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) {
    sk_sp<SkImage> image = mImage;
    sk_sp<SkImage> image = mImage;
    if (!image) {
    if (!image) {
        SkASSERT(!(isHardware() && uirenderer::Properties::isSkiaEnabled()));
        SkASSERT(!(isHardware() && uirenderer::Properties::isSkiaEnabled()));
@@ -330,12 +328,11 @@ sk_sp<SkImage> Bitmap::makeImage() {
        // Note we don't cache in this case, because the raster image holds a pointer to this Bitmap
        // 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.
        // internally and ~Bitmap won't be invoked.
        // TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
        // 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;
    return image;
}
}
+13 −3
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
#pragma once
#pragma once


#include <SkBitmap.h>
#include <SkBitmap.h>
#include <SkColorFilter.h>
#include <SkColorSpace.h>
#include <SkColorSpace.h>
#include <SkImage.h>
#include <SkImage.h>
#include <SkImageInfo.h>
#include <SkImageInfo.h>
@@ -96,9 +97,18 @@ public:


    GraphicBuffer* graphicBuffer();
    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.
     * Creates or returns a cached SkImage and is safe to be invoked from either
    sk_sp<SkImage> makeImage();
     * 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:
private:
    virtual ~Bitmap();
    virtual ~Bitmap();
    void* getStorage() const;
    void* getStorage() const;
Loading