|  | #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_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_ |