[androidkit] Bind canvas to native Bitmap
Wrap native Bitmap pixels using JNIGraphis APIs.
Add finalizer to clean up.
Change-Id: I22ba54e65a9cdf498e97afefe8bcc6cd88db0c95
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/394816
Commit-Queue: Florin Malita <fmalita@google.com>
Reviewed-by: Jorge Betancourt <jmbetancourt@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 4f151fa..37f3743 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -2456,7 +2456,7 @@
is_shared_library = true
sources = [ "modules/androidkit/Canvas.cpp" ]
- libs = []
+ libs = [ "jnigraphics" ]
deps = [ ":skia" ]
}
diff --git a/modules/androidkit/Canvas.cpp b/modules/androidkit/Canvas.cpp
index ee4f49a..803dbb1 100644
--- a/modules/androidkit/Canvas.cpp
+++ b/modules/androidkit/Canvas.cpp
@@ -5,38 +5,114 @@
* found in the LICENSE file.
*/
-#include "include/core/SkBitmap.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkImageInfo.h"
#include "include/core/SkPaint.h"
+#include "include/core/SkSurface.h"
+
+#include <android/bitmap.h>
+#include <android/log.h>
#include <jni.h>
+namespace {
+
+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;
+}
+
+SkPaint skpaint(JNIEnv* env, jobject jpaint) {
+ SkPaint paint;
+
+ // TODO: reflect jpaint
+ paint.setColor(0xff00ff00);
+
+ return paint;
+}
+
+class CanvasWrapper {
+ public:
+ CanvasWrapper(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);
+ }
+ }
+
+ void unlockPixels(JNIEnv* env, jobject bitmap) {
+ if (fSurface) {
+ AndroidBitmap_unlockPixels(env, bitmap);
+ }
+ }
+
+ SkCanvas* canvas() const { return fSurface ? fSurface->getCanvas() : nullptr; }
+
+ private:
+ sk_sp<SkSurface> fSurface;
+};
+
+} // namespace
/*
* Takes in a native instance of bitmap and returns a pointer to the raster canvas.
- *
- * The native instance of bitmap provided by Android is not an SkBitmap,
- * so we ignore it for now.
- *
*/
extern "C" JNIEXPORT jlong
JNICALL
-Java_org_skia_androidkit_Canvas_nInitRaster(JNIEnv* env, jobject, SkBitmap* /*bitmap*/) {
- SkCanvas* canvas = new SkCanvas();
- return (jlong) canvas;
+Java_org_skia_androidkit_Canvas_nCreateRaster(JNIEnv* env, jobject, jobject bitmap) {
+ return (jlong) new CanvasWrapper(env, bitmap);
}
extern "C" JNIEXPORT void
JNICALL
-Java_org_skia_androidkit_Canvas_nDrawRect(JNIEnv* env, jobject, jlong canvasProxy,
- jfloat left, jfloat top, jfloat right,
- jfloat bottom, jlong paintProxy) {
- SkCanvas* canvas = reinterpret_cast<SkCanvas*>(canvasProxy);
- SkPaint* paint = reinterpret_cast<SkPaint*>(paintProxy);
- SkScalar left_ = SkFloatToScalar(left);
- SkScalar top_ = SkFloatToScalar(top);
- SkScalar right_ = SkFloatToScalar(right);
- SkScalar bottom_ = SkFloatToScalar(bottom);
-
- canvas->drawRect(SkRect{left_, top_, right_, bottom_}, *paint);
+Java_org_skia_androidkit_Canvas_nFinalize(JNIEnv* env, jobject,
+ jlong canvas_wrapper, jobject bitmap) {
+ auto* wrapper = reinterpret_cast<CanvasWrapper*>(canvas_wrapper);
+ wrapper->unlockPixels(env, bitmap);
+ delete wrapper;
}
+
+extern "C" JNIEXPORT void
+JNICALL
+Java_org_skia_androidkit_Canvas_nDrawRect(JNIEnv* env, jobject, jlong canvas_wrapper,
+ jfloat left, jfloat top, jfloat right, jfloat bottom,
+ jobject paint) {
+ auto* canvas = reinterpret_cast<CanvasWrapper*>(canvas_wrapper)->canvas();
+ if (!canvas) {
+ return;
+ }
+
+ canvas->drawRect(SkRect::MakeLTRB(left, top, right, bottom), skpaint(env, paint));
+}
+
diff --git a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
index 29b87ed..b647679 100644
--- a/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
+++ b/platform_tools/android/apps/AndroidKit/src/main/java/org/skia/androidkit/Canvas.java
@@ -4,8 +4,6 @@
import android.graphics.Paint;
import android.util.Log;
-import java.lang.reflect.Method;
-
public class Canvas {
private long mNativeCanvasWrapper;
private Bitmap mBitmap;
@@ -16,30 +14,30 @@
Log.d(TAG, "loading lib");
System.loadLibrary("androidkit");
}
+
public Canvas(Bitmap bitmap) {
if (!bitmap.isMutable()) {
throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
}
- // --------- ugly class reflection to get the @hide method -----------
- Object bitmapProxy = null;
- try {
- Class c = Class.forName("android.graphics.Bitmap");
- Method m = c.getMethod("getNativeInstance");
- bitmapProxy = m.invoke(bitmap);
- } catch (Exception e) {
- e.printStackTrace();
- throw new RuntimeException(e);
- }
- mNativeCanvasWrapper = nInitRaster(Long.parseLong(bitmapProxy.toString()));
- // --------------------------------------------------------------------
+
mBitmap = bitmap;
+ mNativeCanvasWrapper = nCreateRaster(bitmap);
+ }
+
+ @Override
+ protected void finalize() throws Throwable
+ {
+ nFinalize(mNativeCanvasWrapper, mBitmap);
}
public void drawRect(float left, float right, float top, float bottom, Paint paint) {
- //nDrawRect(mNativeCanvasWrapper, left, right, top, bottom, paint.getNativeInstance());
+ nDrawRect(mNativeCanvasWrapper, left, right, top, bottom, paint);
}
- private static native long nInitRaster(long bitmapHandle);
- private static native long nDrawRect(long canvasProxy, float left, float right, float top, float bottom, long paintProxy);
+ private static native long nCreateRaster(Bitmap bitmap);
+ private static native void nFinalize(long canvasWrapper, Bitmap bitmap);
+
+ private static native void nDrawRect(long canvasWrapper,
+ float left, float right, float top, float bottom, Paint p);
}
diff --git a/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java b/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
index a71e11e..7398306 100644
--- a/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
+++ b/platform_tools/android/apps/androidkitdemo/src/main/java/org/skia/androidkitdemo1/MainActivity.java
@@ -1,16 +1,13 @@
package org.skia.androidkitdemo1;
-// Will eventually be replaced with:
-// import org.skia.androidkit.Canvas;
import android.app.Activity;
-import android.graphics.Canvas;
-
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
+import org.skia.androidkit.Canvas;
public class MainActivity extends Activity {
private static final String TAG = "ANDROIDKIT DEMO";
@@ -29,4 +26,4 @@
ImageView image = findViewById(R.id.image);
image.setImageBitmap(bmp);
}
-}
\ No newline at end of file
+}