blob: 6a3c01efe98c456104e1532c163c11cf5e044e7f [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "Bitmap"
#include <log/log.h>
#include "android/graphics/bitmap.h"
#include "TypeCast.h"
#include "GraphicsJNI.h"
#include <GraphicsJNI.h>
#include <hwui/Bitmap.h>
using namespace android;
ABitmap* ABitmap_acquireBitmapFromJava(JNIEnv* env, jobject bitmapObj) {
Bitmap* bitmap = GraphicsJNI::getNativeBitmap(env, bitmapObj);
if (bitmap) {
bitmap->ref();
return TypeCast::toABitmap(bitmap);
}
return nullptr;
}
void ABitmap_acquireRef(ABitmap* bitmap) {
SkSafeRef(TypeCast::toBitmap(bitmap));
}
void ABitmap_releaseRef(ABitmap* bitmap) {
SkSafeUnref(TypeCast::toBitmap(bitmap));
}
static AndroidBitmapFormat getFormat(const SkImageInfo& info) {
switch (info.colorType()) {
case kN32_SkColorType:
return ANDROID_BITMAP_FORMAT_RGBA_8888;
case kRGB_565_SkColorType:
return ANDROID_BITMAP_FORMAT_RGB_565;
case kARGB_4444_SkColorType:
return ANDROID_BITMAP_FORMAT_RGBA_4444;
case kAlpha_8_SkColorType:
return ANDROID_BITMAP_FORMAT_A_8;
case kRGBA_F16_SkColorType:
return ANDROID_BITMAP_FORMAT_RGBA_F16;
default:
return ANDROID_BITMAP_FORMAT_NONE;
}
}
static SkColorType getColorType(AndroidBitmapFormat format) {
switch (format) {
case ANDROID_BITMAP_FORMAT_RGBA_8888:
return kN32_SkColorType;
case ANDROID_BITMAP_FORMAT_RGB_565:
return kRGB_565_SkColorType;
case ANDROID_BITMAP_FORMAT_RGBA_4444:
return kARGB_4444_SkColorType;
case ANDROID_BITMAP_FORMAT_A_8:
return kAlpha_8_SkColorType;
case ANDROID_BITMAP_FORMAT_RGBA_F16:
return kRGBA_F16_SkColorType;
default:
return kUnknown_SkColorType;
}
}
static uint32_t getInfoFlags(const SkImageInfo& info) {
switch (info.alphaType()) {
case kUnknown_SkAlphaType:
LOG_ALWAYS_FATAL("Bitmap has no alpha type");
break;
case kOpaque_SkAlphaType:
return ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE;
case kPremul_SkAlphaType:
return ANDROID_BITMAP_FLAGS_ALPHA_PREMUL;
case kUnpremul_SkAlphaType:
return ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL;
}
}
ABitmap* ABitmap_copy(ABitmap* srcBitmapHandle, AndroidBitmapFormat dstFormat) {
SkColorType dstColorType = getColorType(dstFormat);
if (srcBitmapHandle && dstColorType != kUnknown_SkColorType) {
SkBitmap srcBitmap;
TypeCast::toBitmap(srcBitmapHandle)->getSkBitmap(&srcBitmap);
sk_sp<Bitmap> dstBitmap =
Bitmap::allocateHeapBitmap(srcBitmap.info().makeColorType(dstColorType));
if (dstBitmap && srcBitmap.readPixels(dstBitmap->info(), dstBitmap->pixels(),
dstBitmap->rowBytes(), 0, 0)) {
return TypeCast::toABitmap(dstBitmap.release());
}
}
return nullptr;
}
static AndroidBitmapInfo getInfo(const SkImageInfo& imageInfo, uint32_t rowBytes) {
AndroidBitmapInfo info;
info.width = imageInfo.width();
info.height = imageInfo.height();
info.stride = rowBytes;
info.format = getFormat(imageInfo);
info.flags = getInfoFlags(imageInfo);
return info;
}
AndroidBitmapInfo ABitmap_getInfo(ABitmap* bitmapHandle) {
Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle);
return getInfo(bitmap->info(), bitmap->rowBytes());
}
static bool nearlyEqual(float a, float b) {
// By trial and error, this is close enough to match for the ADataSpaces we
// compare for.
return ::fabs(a - b) < .002f;
}
static bool nearlyEqual(const skcms_TransferFunction& x, const skcms_TransferFunction& y) {
return nearlyEqual(x.g, y.g)
&& nearlyEqual(x.a, y.a)
&& nearlyEqual(x.b, y.b)
&& nearlyEqual(x.c, y.c)
&& nearlyEqual(x.d, y.d)
&& nearlyEqual(x.e, y.e)
&& nearlyEqual(x.f, y.f);
}
static bool nearlyEqual(const skcms_Matrix3x3& x, const skcms_Matrix3x3& y) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (!nearlyEqual(x.vals[i][j], y.vals[i][j])) return false;
}
}
return true;
}
static constexpr skcms_TransferFunction k2Dot6 = {2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
// Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut
// matches the white point used by ColorSpace.Named.DCIP3.
static constexpr skcms_Matrix3x3 kDCIP3 = {{
{0.486143, 0.323835, 0.154234},
{0.226676, 0.710327, 0.0629966},
{0.000800549, 0.0432385, 0.78275},
}};
ADataSpace ABitmap_getDataSpace(ABitmap* bitmapHandle) {
Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle);
const SkImageInfo& info = bitmap->info();
SkColorSpace* colorSpace = info.colorSpace();
if (!colorSpace) {
return ADATASPACE_UNKNOWN;
}
if (colorSpace->isSRGB()) {
if (info.colorType() == kRGBA_F16_SkColorType) {
return ADATASPACE_SCRGB;
}
return ADATASPACE_SRGB;
}
skcms_TransferFunction fn;
LOG_ALWAYS_FATAL_IF(!colorSpace->isNumericalTransferFn(&fn));
skcms_Matrix3x3 gamut;
LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&gamut));
if (nearlyEqual(gamut, SkNamedGamut::kSRGB)) {
if (nearlyEqual(fn, SkNamedTransferFn::kLinear)) {
// Skia doesn't differentiate amongst the RANGES. In Java, we associate
// LINEAR_EXTENDED_SRGB with F16, and LINEAR_SRGB with other Configs.
// Make the same association here.
if (info.colorType() == kRGBA_F16_SkColorType) {
return ADATASPACE_SCRGB_LINEAR;
}
return ADATASPACE_SRGB_LINEAR;
}
if (nearlyEqual(fn, SkNamedTransferFn::kRec2020)) {
return ADATASPACE_BT709;
}
}
if (nearlyEqual(fn, SkNamedTransferFn::kSRGB) && nearlyEqual(gamut, SkNamedGamut::kDCIP3)) {
return ADATASPACE_DISPLAY_P3;
}
if (nearlyEqual(fn, SkNamedTransferFn::k2Dot2) && nearlyEqual(gamut, SkNamedGamut::kAdobeRGB)) {
return ADATASPACE_ADOBE_RGB;
}
if (nearlyEqual(fn, SkNamedTransferFn::kRec2020) &&
nearlyEqual(gamut, SkNamedGamut::kRec2020)) {
return ADATASPACE_BT2020;
}
if (nearlyEqual(fn, k2Dot6) && nearlyEqual(gamut, kDCIP3)) {
return ADATASPACE_DCI_P3;
}
return ADATASPACE_UNKNOWN;
}
AndroidBitmapInfo ABitmap_getInfoFromJava(JNIEnv* env, jobject bitmapObj) {
uint32_t rowBytes = 0;
SkImageInfo imageInfo = GraphicsJNI::getBitmapInfo(env, bitmapObj, &rowBytes);
return getInfo(imageInfo, rowBytes);
}
void* ABitmap_getPixels(ABitmap* bitmapHandle) {
Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle);
if (bitmap->isHardware()) {
return nullptr;
}
return bitmap->pixels();
}
AndroidBitmapFormat ABitmapConfig_getFormatFromConfig(JNIEnv* env, jobject bitmapConfigObj) {
return GraphicsJNI::getFormatFromConfig(env, bitmapConfigObj);
}
jobject ABitmapConfig_getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format) {
return GraphicsJNI::getConfigFromFormat(env, format);
}
void ABitmap_notifyPixelsChanged(ABitmap* bitmapHandle) {
Bitmap* bitmap = TypeCast::toBitmap(bitmapHandle);
if (bitmap->isImmutable()) {
ALOGE("Attempting to modify an immutable Bitmap!");
}
return bitmap->notifyPixelsChanged();
}