blob: 98e48830d91954fe0006060aae769a903e181bfd [file] [log] [blame]
/*
* Copyright 2021 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include <android/bitmap.h>
#include <android/log.h>
#include <jni.h>
#include "include/core/SkRefCnt.h"
#include "include/core/SkSurface.h"
#include "include/core/SkTypes.h"
namespace {
class Surface : public SkRefCnt {
public:
virtual void release(JNIEnv*) = 0;
SkCanvas* getCanvas() const { return fSurface->getCanvas(); }
protected:
sk_sp<SkSurface> fSurface;
};
class BitmapSurface final : public Surface {
public:
BitmapSurface(JNIEnv* env, jobject bitmap) {
AndroidBitmapInfo bm_info;
if (AndroidBitmap_getInfo(env, bitmap, &bm_info) != ANDROID_BITMAP_RESULT_SUCCESS) {
return;
}
const auto info = SkImageInfo::Make(bm_info.width, bm_info.height,
color_type(bm_info.format), alpha_type(bm_info.flags));
void* pixels;
if (AndroidBitmap_lockPixels(env, bitmap, &pixels) != ANDROID_BITMAP_RESULT_SUCCESS) {
return;
}
fSurface = SkSurface::MakeRasterDirect(info, pixels, bm_info.stride);
if (!fSurface) {
AndroidBitmap_unlockPixels(env, bitmap);
return;
}
fBitmap = env->NewGlobalRef(bitmap);
}
private:
void release(JNIEnv* env) override {
if (fSurface) {
AndroidBitmap_unlockPixels(env, fBitmap);
fSurface.reset();
env->DeleteGlobalRef(fBitmap);
}
}
static SkColorType color_type(int32_t format) {
switch (format) {
case ANDROID_BITMAP_FORMAT_RGBA_8888: return kRGBA_8888_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_RGBA_F16: return kRGBA_F16_SkColorType;
case ANDROID_BITMAP_FORMAT_A_8: return kAlpha_8_SkColorType;
default: break;
}
return kUnknown_SkColorType;
}
static SkAlphaType alpha_type(int32_t flags) {
switch ((flags >> ANDROID_BITMAP_FLAGS_ALPHA_SHIFT) & ANDROID_BITMAP_FLAGS_ALPHA_MASK) {
case ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE: return kOpaque_SkAlphaType;
case ANDROID_BITMAP_FLAGS_ALPHA_PREMUL: return kPremul_SkAlphaType;
case ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL: return kUnpremul_SkAlphaType;
default: break;
}
return kUnknown_SkAlphaType;
}
jobject fBitmap;
};
static jlong Surface_CreateBitmap(JNIEnv* env, jobject, jobject bitmap) {
return reinterpret_cast<jlong>(new BitmapSurface(env, bitmap));
}
static void Surface_Release(JNIEnv* env, jobject, jlong native_surface) {
if (auto* surface = reinterpret_cast<Surface*>(native_surface)) {
surface->release(env);
delete surface;
}
}
static jlong Surface_GetNativeCanvas(JNIEnv* env, jobject, jlong native_surface) {
const auto* surface = reinterpret_cast<Surface*>(native_surface);
return surface
? reinterpret_cast<jlong>(surface->getCanvas())
: 0;
}
} // namespace
int register_androidkit_Surface(JNIEnv* env) {
static const JNINativeMethod methods[] = {
{"nCreateBitmap" , "(Landroid/graphics/Bitmap;)J",
reinterpret_cast<void*>(Surface_CreateBitmap)},
{"nRelease" , "(J)V", reinterpret_cast<void*>(Surface_Release)},
{"nGetNativeCanvas", "(J)J", reinterpret_cast<void*>(Surface_GetNativeCanvas)},
};
const auto clazz = env->FindClass("org/skia/androidkit/Surface");
return clazz
? env->RegisterNatives(clazz, methods, SK_ARRAY_COUNT(methods))
: JNI_ERR;
}