| #ifndef _ANDROID_GRAPHICS_GRAPHICS_JNI_H_ |
| #define _ANDROID_GRAPHICS_GRAPHICS_JNI_H_ |
| |
| #include <cutils/compiler.h> |
| #include <hwui/Bitmap.h> |
| #include <hwui/Canvas.h> |
| |
| #include "BRDAllocator.h" |
| #include "Bitmap.h" |
| #include "SkBitmap.h" |
| #include "SkCodec.h" |
| #include "SkColorSpace.h" |
| #include "SkMallocPixelRef.h" |
| #include "SkPixelRef.h" |
| #include "SkPoint.h" |
| #include "SkRect.h" |
| #include "graphics_jni_helpers.h" |
| |
| class SkCanvas; |
| struct SkFontMetrics; |
| |
| namespace android { |
| class BitmapRegionDecoderWrapper; |
| class Canvas; |
| class Paint; |
| struct Typeface; |
| } |
| |
| class GraphicsJNI { |
| public: |
| // This enum must keep these int values, to match the int values |
| // in the java Bitmap.Config enum. |
| enum LegacyBitmapConfig { |
| kNo_LegacyBitmapConfig = 0, |
| kA8_LegacyBitmapConfig = 1, |
| kIndex8_LegacyBitmapConfig = 2, |
| kRGB_565_LegacyBitmapConfig = 3, |
| kARGB_4444_LegacyBitmapConfig = 4, |
| kARGB_8888_LegacyBitmapConfig = 5, |
| kRGBA_16F_LegacyBitmapConfig = 6, |
| kHardware_LegacyBitmapConfig = 7, |
| kRGBA_1010102_LegacyBitmapConfig = 8, |
| |
| kLastEnum_LegacyBitmapConfig = kRGBA_1010102_LegacyBitmapConfig |
| }; |
| |
| static void setJavaVM(JavaVM* javaVM); |
| |
| /** |
| * returns a pointer to the JavaVM provided when we initialized the module |
| * DEPRECATED: Objects should know the JavaVM that created them |
| */ |
| static JavaVM* getJavaVM() { return mJavaVM; } |
| |
| /** |
| * return a pointer to the JNIEnv for this thread |
| * DEPRECATED: Objects should know the JavaVM that created them |
| */ |
| static JNIEnv* getJNIEnv(); |
| |
| /** create a JNIEnv* for this thread or assert if one already exists */ |
| static JNIEnv* attachJNIEnv(const char* envName); |
| |
| /** detach the current thread from the JavaVM */ |
| static void detachJNIEnv(); |
| |
| // returns true if an exception is set (and dumps it out to the Log) |
| static bool hasException(JNIEnv*); |
| |
| static void get_jrect(JNIEnv*, jobject jrect, int* L, int* T, int* R, int* B); |
| static void set_jrect(JNIEnv*, jobject jrect, int L, int T, int R, int B); |
| |
| static SkIRect* jrect_to_irect(JNIEnv*, jobject jrect, SkIRect*); |
| static void irect_to_jrect(const SkIRect&, JNIEnv*, jobject jrect); |
| |
| static SkRect* jrectf_to_rect(JNIEnv*, jobject jrectf, SkRect*); |
| static SkRect* jrect_to_rect(JNIEnv*, jobject jrect, SkRect*); |
| static void rect_to_jrectf(const SkRect&, JNIEnv*, jobject jrectf); |
| |
| static void set_cluster_count_to_run_info(JNIEnv* env, jobject runInfo, jint clusterCount); |
| |
| static void set_jpoint(JNIEnv*, jobject jrect, int x, int y); |
| |
| static SkIPoint* jpoint_to_ipoint(JNIEnv*, jobject jpoint, SkIPoint* point); |
| static void ipoint_to_jpoint(const SkIPoint& point, JNIEnv*, jobject jpoint); |
| |
| static SkPoint* jpointf_to_point(JNIEnv*, jobject jpointf, SkPoint* point); |
| static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf); |
| |
| ANDROID_API static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas); |
| static android::Bitmap* getNativeBitmap(JNIEnv*, jobject bitmap); |
| static SkImageInfo getBitmapInfo(JNIEnv*, jobject bitmap, uint32_t* outRowBytes, |
| bool* isHardware); |
| static SkRegion* getNativeRegion(JNIEnv*, jobject region); |
| |
| /** |
| * Set SkFontMetrics to Java Paint.FontMetrics. |
| * Do nothing if metrics is nullptr. |
| */ |
| static void set_metrics(JNIEnv*, jobject metrics, const SkFontMetrics& skmetrics); |
| /** |
| * Set SkFontMetrics to Java Paint.FontMetricsInt and return recommended interline space. |
| * Do nothing if metrics is nullptr. |
| */ |
| static int set_metrics_int(JNIEnv*, jobject metrics, const SkFontMetrics& skmetrics); |
| |
| /* |
| * LegacyBitmapConfig is the old enum in Skia that matched the enum int values |
| * in Bitmap.Config. Skia no longer supports this config, but has replaced it |
| * with SkColorType. These routines convert between the two. |
| */ |
| static SkColorType legacyBitmapConfigToColorType(jint legacyConfig); |
| static jint colorTypeToLegacyBitmapConfig(SkColorType colorType); |
| |
| /** Return the corresponding native colorType from the java Config enum, |
| or kUnknown_SkColorType if the java object is null. |
| */ |
| static SkColorType getNativeBitmapColorType(JNIEnv*, jobject jconfig); |
| static AndroidBitmapFormat getFormatFromConfig(JNIEnv* env, jobject jconfig); |
| static jobject getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format); |
| |
| static bool isHardwareConfig(JNIEnv* env, jobject jconfig); |
| static jint hardwareLegacyBitmapConfig(); |
| |
| static jobject createRegion(JNIEnv* env, SkRegion* region); |
| |
| static jobject createBitmapRegionDecoder(JNIEnv* env, |
| android::BitmapRegionDecoderWrapper* bitmap); |
| |
| /** Copy the colors in colors[] to the bitmap, convert to the correct |
| format along the way. |
| Whether to use premultiplied pixels is determined by dstBitmap's alphaType. |
| */ |
| static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset, |
| int srcStride, int x, int y, int width, int height, |
| SkBitmap* dstBitmap); |
| |
| /** |
| * Convert the native SkColorSpace retrieved from ColorSpace.Rgb.getNativeInstance(). |
| * |
| * This will never throw an Exception. If the ColorSpace is one that Skia cannot |
| * use, ColorSpace.Rgb.getNativeInstance() would have thrown an Exception. It may, |
| * however, be nullptr, which may be acceptable. |
| */ |
| static sk_sp<SkColorSpace> getNativeColorSpace(jlong colorSpaceHandle); |
| |
| /** |
| * Return the android.graphics.ColorSpace Java object that corresponds to decodeColorSpace |
| * and decodeColorType. |
| * |
| * This may create a new object if none of the Named ColorSpaces match. |
| */ |
| static jobject getColorSpace(JNIEnv* env, SkColorSpace* decodeColorSpace, |
| SkColorType decodeColorType); |
| |
| /** |
| * Convert from a Java @ColorLong to an SkColor4f that Skia can use directly. |
| * |
| * This ignores the encoded ColorSpace, besides checking to see if it is sRGB, |
| * which is encoded differently. The color space should be passed down separately |
| * via ColorSpace#getNativeInstance(), and converted with getNativeColorSpace(), |
| * above. |
| */ |
| static SkColor4f convertColorLong(jlong color); |
| |
| private: |
| /* JNI JavaVM pointer */ |
| static JavaVM* mJavaVM; |
| }; |
| |
| class HeapAllocator : public android::skia::BRDAllocator { |
| public: |
| HeapAllocator() { }; |
| ~HeapAllocator() { }; |
| |
| virtual bool allocPixelRef(SkBitmap* bitmap) override; |
| |
| /** |
| * Fetches the backing allocation object. Must be called! |
| */ |
| android::Bitmap* getStorageObjAndReset() { |
| return mStorage.release(); |
| }; |
| |
| SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kYes_ZeroInitialized; } |
| private: |
| sk_sp<android::Bitmap> mStorage; |
| }; |
| |
| /** |
| * Allocator to handle reusing bitmaps for BitmapRegionDecoder. |
| * |
| * The BitmapRegionDecoder documentation states that, if it is |
| * provided, the recycled bitmap will always be reused, clipping |
| * the decoded output to fit in the recycled bitmap if necessary. |
| * This allocator implements that behavior. |
| * |
| * Skia's BitmapRegionDecoder expects the memory that |
| * is allocated to be large enough to decode the entire region |
| * that is requested. It will decode directly into the memory |
| * that is provided. |
| * |
| * FIXME: BUG:25465958 |
| * If the recycled bitmap is not large enough for the decode |
| * requested, meaning that a clip is required, we will allocate |
| * enough memory for Skia to perform the decode, and then copy |
| * from the decoded output into the recycled bitmap. |
| * |
| * If the recycled bitmap is large enough for the decode requested, |
| * we will provide that memory for Skia to decode directly into. |
| * |
| * This allocator should only be used for a single allocation. |
| * After we reuse the recycledBitmap once, it is dangerous to |
| * reuse it again, given that it still may be in use from our |
| * first allocation. |
| */ |
| class RecyclingClippingPixelAllocator : public android::skia::BRDAllocator { |
| public: |
| RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap, |
| bool mustMatchColorType = true); |
| |
| ~RecyclingClippingPixelAllocator(); |
| |
| virtual bool allocPixelRef(SkBitmap* bitmap) override; |
| |
| /** |
| * Must be called! |
| * |
| * In the event that the recycled bitmap is not large enough for |
| * the allocation requested, we will allocate memory on the heap |
| * instead. As a final step, once we are done using this memory, |
| * we will copy the contents of the heap memory into the recycled |
| * bitmap's memory, clipping as necessary. |
| */ |
| void copyIfNecessary(); |
| |
| /** |
| * Indicates that this allocator does not allocate zero initialized |
| * memory. |
| */ |
| SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kNo_ZeroInitialized; } |
| |
| private: |
| android::Bitmap* mRecycledBitmap; |
| const size_t mRecycledBytes; |
| SkBitmap* mSkiaBitmap; |
| bool mNeedsCopy; |
| const bool mMustMatchColorType; |
| }; |
| |
| class AshmemPixelAllocator : public SkBitmap::Allocator { |
| public: |
| explicit AshmemPixelAllocator(JNIEnv* env); |
| ~AshmemPixelAllocator() { }; |
| virtual bool allocPixelRef(SkBitmap* bitmap); |
| android::Bitmap* getStorageObjAndReset() { |
| return mStorage.release(); |
| }; |
| |
| private: |
| JavaVM* mJavaVM; |
| sk_sp<android::Bitmap> mStorage; |
| }; |
| |
| |
| enum JNIAccess { |
| kRO_JNIAccess, |
| kRW_JNIAccess |
| }; |
| |
| class AutoJavaFloatArray { |
| public: |
| AutoJavaFloatArray(JNIEnv* env, jfloatArray array, |
| int minLength = 0, JNIAccess = kRW_JNIAccess); |
| ~AutoJavaFloatArray(); |
| |
| float* ptr() const { return fPtr; } |
| int length() const { return fLen; } |
| |
| private: |
| JNIEnv* fEnv; |
| jfloatArray fArray; |
| float* fPtr; |
| int fLen; |
| int fReleaseMode; |
| }; |
| |
| class AutoJavaIntArray { |
| public: |
| AutoJavaIntArray(JNIEnv* env, jintArray array, int minLength = 0); |
| ~AutoJavaIntArray(); |
| |
| jint* ptr() const { return fPtr; } |
| int length() const { return fLen; } |
| |
| private: |
| JNIEnv* fEnv; |
| jintArray fArray; |
| jint* fPtr; |
| int fLen; |
| }; |
| |
| class AutoJavaShortArray { |
| public: |
| AutoJavaShortArray(JNIEnv* env, jshortArray array, |
| int minLength = 0, JNIAccess = kRW_JNIAccess); |
| ~AutoJavaShortArray(); |
| |
| jshort* ptr() const { return fPtr; } |
| int length() const { return fLen; } |
| |
| private: |
| JNIEnv* fEnv; |
| jshortArray fArray; |
| jshort* fPtr; |
| int fLen; |
| int fReleaseMode; |
| }; |
| |
| class AutoJavaByteArray { |
| public: |
| AutoJavaByteArray(JNIEnv* env, jbyteArray array, int minLength = 0); |
| ~AutoJavaByteArray(); |
| |
| jbyte* ptr() const { return fPtr; } |
| int length() const { return fLen; } |
| |
| private: |
| JNIEnv* fEnv; |
| jbyteArray fArray; |
| jbyte* fPtr; |
| int fLen; |
| }; |
| |
| class JGlobalRefHolder { |
| public: |
| JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {} |
| |
| virtual ~JGlobalRefHolder() { |
| env()->DeleteGlobalRef(mObject); |
| mObject = nullptr; |
| } |
| |
| jobject object() { return mObject; } |
| JavaVM* vm() { return mVm; } |
| |
| JNIEnv* env() { |
| JNIEnv* env; |
| if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { |
| LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", mVm); |
| } |
| return env; |
| } |
| |
| private: |
| JGlobalRefHolder(const JGlobalRefHolder&) = delete; |
| void operator=(const JGlobalRefHolder&) = delete; |
| |
| JavaVM* mVm; |
| jobject mObject; |
| }; |
| |
| void doThrowNPE(JNIEnv* env); |
| void doThrowAIOOBE(JNIEnv* env); // Array Index Out Of Bounds Exception |
| void doThrowIAE(JNIEnv* env, const char* msg = NULL); // Illegal Argument |
| void doThrowRE(JNIEnv* env, const char* msg = NULL); // Runtime |
| void doThrowISE(JNIEnv* env, const char* msg = NULL); // Illegal State |
| void doThrowOOME(JNIEnv* env, const char* msg = NULL); // Out of memory |
| void doThrowIOE(JNIEnv* env, const char* msg = NULL); // IO Exception |
| |
| #define NPE_CHECK_RETURN_ZERO(env, object) \ |
| do { if (NULL == (object)) { doThrowNPE(env); return 0; } } while (0) |
| |
| #define NPE_CHECK_RETURN_VOID(env, object) \ |
| do { if (NULL == (object)) { doThrowNPE(env); return; } } while (0) |
| |
| #endif // _ANDROID_GRAPHICS_GRAPHICS_JNI_H_ |