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

Commit 33e3741c authored by Matt Sarett's avatar Matt Sarett
Browse files

Decode images to sRGB, premultiply based on framework define

This reenables color conversion to sRGB at decode time.

Use the value ANDROID_LINEAR_BLENDING_ENABLED to decide
whether to use the codec's linear premultiply or manually
perform a legacy premultiply.

Test: Demonstrated that legacy premultiply is still
faster than the linear premultiply.  So the performance
of the two pass approach (decode, then premultiply)
is acceptable.  Skia tests both of these decoding modes.

BUG:33741991
BUG:8860389
BUG:24279600

Change-Id: Idea0f359565bd8c7c3ba06e77a897173677db1c6
parent e19fa20c
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -215,6 +215,7 @@ LOCAL_C_INCLUDES += \
    external/skia/src/effects \
    external/skia/src/image \
    external/skia/src/images \
    external/skia/src/utils \
    external/sqlite/dist \
    external/sqlite/android \
    external/tremor/Tremor \
+49 −3
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include "SkBRDAllocator.h"
#include "SkFrontBufferedStream.h"
#include "SkMath.h"
#include "SkOpts.h"
#include "SkPixelRef.h"
#include "SkStream.h"
#include "SkUtils.h"
@@ -224,6 +225,45 @@ static bool needsFineScale(const SkISize fullSize, const SkISize decodedSize,
           needsFineScale(fullSize.height(), decodedSize.height(), sampleSize);
}

static inline SkAlphaType computeDecodeAlphaType(SkColorType colorType, SkAlphaType alphaType) {
#ifndef ANDROID_ENABLE_LINEAR_BLENDING
    // Skia premultiplies linearly.  Until the framework enables linear blending,
    // it expects a legacy premultiply.
    if (kPremul_SkAlphaType == alphaType && kRGBA_F16_SkColorType != colorType) {
        return kUnpremul_SkAlphaType;
    }
#endif

    return alphaType;
}

static inline void premultiplyIfNecessary(SkBitmap* bitmap, SkPMColor* colorPtr, int* colorCount,
        SkAlphaType alphaType, bool requireUnpremultiplied) {
#ifndef ANDROID_ENABLE_LINEAR_BLENDING
    if (kUnpremul_SkAlphaType != alphaType || requireUnpremultiplied) {
        return;
    }

    switch (bitmap->colorType()) {
        case kN32_SkColorType:
            for (int y = 0; y < bitmap->height(); y++) {
                SkOpts::RGBA_to_rgbA(bitmap->getAddr32(0, y), bitmap->getAddr32(0, y),
                    bitmap->width());
            }

            return;
        case kIndex_8_SkColorType:
            SkOpts::RGBA_to_rgbA(colorPtr, colorPtr, *colorCount);
            return;
        default:
            // kRGBA_F16 will be premultiplied by the codec if necessary.
            // kGray_8 (alias kAlpha_8) and k565 are opaque.
            LOG_ALWAYS_FATAL("Should be unreachable - no need for legacy premultiply.");
            return;
    }
#endif
}

static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding, jobject options) {
    // This function takes ownership of the input stream.  Since the SkAndroidCodec
    // will take ownership of the stream, we don't necessarily need to take ownership
@@ -391,13 +431,17 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
        colorCount = &maxColors;
    }

    // Set the alpha type for the decode.
    SkAlphaType alphaType = codec->computeOutputAlphaType(requireUnpremultiplied);
    SkAlphaType decodeAlphaType = computeDecodeAlphaType(decodeColorType, alphaType);

    const SkImageInfo decodeInfo = SkImageInfo::Make(size.width(), size.height(),
            decodeColorType, alphaType, GraphicsJNI::colorSpaceForType(decodeColorType));
            decodeColorType, decodeAlphaType, codec->computeOutputColorSpace(decodeColorType));

    // When supported by the colorType, we will decode to sRGB (or linear sRGB).  However,
    // we only want to mark the bitmap as sRGB when linear blending is enabled.
    SkImageInfo bitmapInfo = decodeInfo.makeAlphaType(alphaType)
            .makeColorSpace(GraphicsJNI::colorSpaceForType(decodeColorType));

    SkImageInfo bitmapInfo = decodeInfo;
    if (decodeColorType == kGray_8_SkColorType) {
        // The legacy implementation of BitmapFactory used kAlpha8 for
        // grayscale images (before kGray8 existed).  While the codec
@@ -433,6 +477,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding
        default:
            return nullObjectReturn("codec->getAndroidPixels() failed.");
    }
    premultiplyIfNecessary(&decodingBitmap, colorPtr, colorCount, decodeAlphaType,
            requireUnpremultiplied);

    jbyteArray ninePatchChunk = NULL;
    if (peeker.mPatch != NULL) {