1 #ifndef _ANDROID_GRAPHICS_GRAPHICS_JNI_H_ 2 #define _ANDROID_GRAPHICS_GRAPHICS_JNI_H_ 3 4 #include <cutils/compiler.h> 5 #include <hwui/Bitmap.h> 6 #include <hwui/Canvas.h> 7 8 #include "BRDAllocator.h" 9 #include "Bitmap.h" 10 #include "SkBitmap.h" 11 #include "SkCodec.h" 12 #include "SkColorSpace.h" 13 #include "SkMallocPixelRef.h" 14 #include "SkPixelRef.h" 15 #include "SkPoint.h" 16 #include "SkRect.h" 17 #include "graphics_jni_helpers.h" 18 19 class SkCanvas; 20 struct SkFontMetrics; 21 22 namespace android { 23 class BitmapRegionDecoderWrapper; 24 class Canvas; 25 class Paint; 26 struct Typeface; 27 } 28 29 class GraphicsJNI { 30 public: 31 // This enum must keep these int values, to match the int values 32 // in the java Bitmap.Config enum. 33 enum LegacyBitmapConfig { 34 kNo_LegacyBitmapConfig = 0, 35 kA8_LegacyBitmapConfig = 1, 36 kIndex8_LegacyBitmapConfig = 2, 37 kRGB_565_LegacyBitmapConfig = 3, 38 kARGB_4444_LegacyBitmapConfig = 4, 39 kARGB_8888_LegacyBitmapConfig = 5, 40 kRGBA_16F_LegacyBitmapConfig = 6, 41 kHardware_LegacyBitmapConfig = 7, 42 kRGBA_1010102_LegacyBitmapConfig = 8, 43 44 kLastEnum_LegacyBitmapConfig = kRGBA_1010102_LegacyBitmapConfig 45 }; 46 47 static void setJavaVM(JavaVM* javaVM); 48 49 /** 50 * returns a pointer to the JavaVM provided when we initialized the module 51 * DEPRECATED: Objects should know the JavaVM that created them 52 */ getJavaVM()53 static JavaVM* getJavaVM() { return mJavaVM; } 54 55 /** 56 * return a pointer to the JNIEnv for this thread 57 * DEPRECATED: Objects should know the JavaVM that created them 58 */ 59 static JNIEnv* getJNIEnv(); 60 61 /** create a JNIEnv* for this thread or assert if one already exists */ 62 static JNIEnv* attachJNIEnv(const char* envName); 63 64 /** detach the current thread from the JavaVM */ 65 static void detachJNIEnv(); 66 67 // returns true if an exception is set (and dumps it out to the Log) 68 static bool hasException(JNIEnv*); 69 70 static void get_jrect(JNIEnv*, jobject jrect, int* L, int* T, int* R, int* B); 71 static void set_jrect(JNIEnv*, jobject jrect, int L, int T, int R, int B); 72 73 static SkIRect* jrect_to_irect(JNIEnv*, jobject jrect, SkIRect*); 74 static void irect_to_jrect(const SkIRect&, JNIEnv*, jobject jrect); 75 76 static SkRect* jrectf_to_rect(JNIEnv*, jobject jrectf, SkRect*); 77 static SkRect* jrect_to_rect(JNIEnv*, jobject jrect, SkRect*); 78 static void rect_to_jrectf(const SkRect&, JNIEnv*, jobject jrectf); 79 80 static void set_jpoint(JNIEnv*, jobject jrect, int x, int y); 81 82 static SkIPoint* jpoint_to_ipoint(JNIEnv*, jobject jpoint, SkIPoint* point); 83 static void ipoint_to_jpoint(const SkIPoint& point, JNIEnv*, jobject jpoint); 84 85 static SkPoint* jpointf_to_point(JNIEnv*, jobject jpointf, SkPoint* point); 86 static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf); 87 88 ANDROID_API static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas); 89 static android::Bitmap* getNativeBitmap(JNIEnv*, jobject bitmap); 90 static SkImageInfo getBitmapInfo(JNIEnv*, jobject bitmap, uint32_t* outRowBytes, 91 bool* isHardware); 92 static SkRegion* getNativeRegion(JNIEnv*, jobject region); 93 94 /** 95 * Set SkFontMetrics to Java Paint.FontMetrics. 96 * Do nothing if metrics is nullptr. 97 */ 98 static void set_metrics(JNIEnv*, jobject metrics, const SkFontMetrics& skmetrics); 99 /** 100 * Set SkFontMetrics to Java Paint.FontMetricsInt and return recommended interline space. 101 * Do nothing if metrics is nullptr. 102 */ 103 static int set_metrics_int(JNIEnv*, jobject metrics, const SkFontMetrics& skmetrics); 104 105 /* 106 * LegacyBitmapConfig is the old enum in Skia that matched the enum int values 107 * in Bitmap.Config. Skia no longer supports this config, but has replaced it 108 * with SkColorType. These routines convert between the two. 109 */ 110 static SkColorType legacyBitmapConfigToColorType(jint legacyConfig); 111 static jint colorTypeToLegacyBitmapConfig(SkColorType colorType); 112 113 /** Return the corresponding native colorType from the java Config enum, 114 or kUnknown_SkColorType if the java object is null. 115 */ 116 static SkColorType getNativeBitmapColorType(JNIEnv*, jobject jconfig); 117 static AndroidBitmapFormat getFormatFromConfig(JNIEnv* env, jobject jconfig); 118 static jobject getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format); 119 120 static bool isHardwareConfig(JNIEnv* env, jobject jconfig); 121 static jint hardwareLegacyBitmapConfig(); 122 123 static jobject createRegion(JNIEnv* env, SkRegion* region); 124 125 static jobject createBitmapRegionDecoder(JNIEnv* env, 126 android::BitmapRegionDecoderWrapper* bitmap); 127 128 /** 129 * Given a bitmap we natively allocate a memory block to store the contents 130 * of that bitmap. The memory is then attached to the bitmap via an 131 * SkPixelRef, which ensures that upon deletion the appropriate caches 132 * are notified. 133 */ 134 static bool allocatePixels(JNIEnv* env, SkBitmap* bitmap); 135 136 /** Copy the colors in colors[] to the bitmap, convert to the correct 137 format along the way. 138 Whether to use premultiplied pixels is determined by dstBitmap's alphaType. 139 */ 140 static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset, 141 int srcStride, int x, int y, int width, int height, 142 SkBitmap* dstBitmap); 143 144 /** 145 * Convert the native SkColorSpace retrieved from ColorSpace.Rgb.getNativeInstance(). 146 * 147 * This will never throw an Exception. If the ColorSpace is one that Skia cannot 148 * use, ColorSpace.Rgb.getNativeInstance() would have thrown an Exception. It may, 149 * however, be nullptr, which may be acceptable. 150 */ 151 static sk_sp<SkColorSpace> getNativeColorSpace(jlong colorSpaceHandle); 152 153 /** 154 * Return the android.graphics.ColorSpace Java object that corresponds to decodeColorSpace 155 * and decodeColorType. 156 * 157 * This may create a new object if none of the Named ColorSpaces match. 158 */ 159 static jobject getColorSpace(JNIEnv* env, SkColorSpace* decodeColorSpace, 160 SkColorType decodeColorType); 161 162 /** 163 * Convert from a Java @ColorLong to an SkColor4f that Skia can use directly. 164 * 165 * This ignores the encoded ColorSpace, besides checking to see if it is sRGB, 166 * which is encoded differently. The color space should be passed down separately 167 * via ColorSpace#getNativeInstance(), and converted with getNativeColorSpace(), 168 * above. 169 */ 170 static SkColor4f convertColorLong(jlong color); 171 172 private: 173 /* JNI JavaVM pointer */ 174 static JavaVM* mJavaVM; 175 }; 176 177 class HeapAllocator : public android::skia::BRDAllocator { 178 public: HeapAllocator()179 HeapAllocator() { }; ~HeapAllocator()180 ~HeapAllocator() { }; 181 182 virtual bool allocPixelRef(SkBitmap* bitmap) override; 183 184 /** 185 * Fetches the backing allocation object. Must be called! 186 */ getStorageObjAndReset()187 android::Bitmap* getStorageObjAndReset() { 188 return mStorage.release(); 189 }; 190 zeroInit()191 SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kYes_ZeroInitialized; } 192 private: 193 sk_sp<android::Bitmap> mStorage; 194 }; 195 196 /** 197 * Allocator to handle reusing bitmaps for BitmapRegionDecoder. 198 * 199 * The BitmapRegionDecoder documentation states that, if it is 200 * provided, the recycled bitmap will always be reused, clipping 201 * the decoded output to fit in the recycled bitmap if necessary. 202 * This allocator implements that behavior. 203 * 204 * Skia's BitmapRegionDecoder expects the memory that 205 * is allocated to be large enough to decode the entire region 206 * that is requested. It will decode directly into the memory 207 * that is provided. 208 * 209 * FIXME: BUG:25465958 210 * If the recycled bitmap is not large enough for the decode 211 * requested, meaning that a clip is required, we will allocate 212 * enough memory for Skia to perform the decode, and then copy 213 * from the decoded output into the recycled bitmap. 214 * 215 * If the recycled bitmap is large enough for the decode requested, 216 * we will provide that memory for Skia to decode directly into. 217 * 218 * This allocator should only be used for a single allocation. 219 * After we reuse the recycledBitmap once, it is dangerous to 220 * reuse it again, given that it still may be in use from our 221 * first allocation. 222 */ 223 class RecyclingClippingPixelAllocator : public android::skia::BRDAllocator { 224 public: 225 RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap, 226 bool mustMatchColorType = true); 227 228 ~RecyclingClippingPixelAllocator(); 229 230 virtual bool allocPixelRef(SkBitmap* bitmap) override; 231 232 /** 233 * Must be called! 234 * 235 * In the event that the recycled bitmap is not large enough for 236 * the allocation requested, we will allocate memory on the heap 237 * instead. As a final step, once we are done using this memory, 238 * we will copy the contents of the heap memory into the recycled 239 * bitmap's memory, clipping as necessary. 240 */ 241 void copyIfNecessary(); 242 243 /** 244 * Indicates that this allocator does not allocate zero initialized 245 * memory. 246 */ zeroInit()247 SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kNo_ZeroInitialized; } 248 249 private: 250 android::Bitmap* mRecycledBitmap; 251 const size_t mRecycledBytes; 252 SkBitmap* mSkiaBitmap; 253 bool mNeedsCopy; 254 const bool mMustMatchColorType; 255 }; 256 257 class AshmemPixelAllocator : public SkBitmap::Allocator { 258 public: 259 explicit AshmemPixelAllocator(JNIEnv* env); ~AshmemPixelAllocator()260 ~AshmemPixelAllocator() { }; 261 virtual bool allocPixelRef(SkBitmap* bitmap); getStorageObjAndReset()262 android::Bitmap* getStorageObjAndReset() { 263 return mStorage.release(); 264 }; 265 266 private: 267 JavaVM* mJavaVM; 268 sk_sp<android::Bitmap> mStorage; 269 }; 270 271 272 enum JNIAccess { 273 kRO_JNIAccess, 274 kRW_JNIAccess 275 }; 276 277 class AutoJavaFloatArray { 278 public: 279 AutoJavaFloatArray(JNIEnv* env, jfloatArray array, 280 int minLength = 0, JNIAccess = kRW_JNIAccess); 281 ~AutoJavaFloatArray(); 282 ptr()283 float* ptr() const { return fPtr; } length()284 int length() const { return fLen; } 285 286 private: 287 JNIEnv* fEnv; 288 jfloatArray fArray; 289 float* fPtr; 290 int fLen; 291 int fReleaseMode; 292 }; 293 294 class AutoJavaIntArray { 295 public: 296 AutoJavaIntArray(JNIEnv* env, jintArray array, int minLength = 0); 297 ~AutoJavaIntArray(); 298 ptr()299 jint* ptr() const { return fPtr; } length()300 int length() const { return fLen; } 301 302 private: 303 JNIEnv* fEnv; 304 jintArray fArray; 305 jint* fPtr; 306 int fLen; 307 }; 308 309 class AutoJavaShortArray { 310 public: 311 AutoJavaShortArray(JNIEnv* env, jshortArray array, 312 int minLength = 0, JNIAccess = kRW_JNIAccess); 313 ~AutoJavaShortArray(); 314 ptr()315 jshort* ptr() const { return fPtr; } length()316 int length() const { return fLen; } 317 318 private: 319 JNIEnv* fEnv; 320 jshortArray fArray; 321 jshort* fPtr; 322 int fLen; 323 int fReleaseMode; 324 }; 325 326 class AutoJavaByteArray { 327 public: 328 AutoJavaByteArray(JNIEnv* env, jbyteArray array, int minLength = 0); 329 ~AutoJavaByteArray(); 330 ptr()331 jbyte* ptr() const { return fPtr; } length()332 int length() const { return fLen; } 333 334 private: 335 JNIEnv* fEnv; 336 jbyteArray fArray; 337 jbyte* fPtr; 338 int fLen; 339 }; 340 341 class JGlobalRefHolder { 342 public: JGlobalRefHolder(JavaVM * vm,jobject object)343 JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {} 344 ~JGlobalRefHolder()345 virtual ~JGlobalRefHolder() { 346 env()->DeleteGlobalRef(mObject); 347 mObject = nullptr; 348 } 349 object()350 jobject object() { return mObject; } vm()351 JavaVM* vm() { return mVm; } 352 env()353 JNIEnv* env() { 354 JNIEnv* env; 355 if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { 356 LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", mVm); 357 } 358 return env; 359 } 360 361 private: 362 JGlobalRefHolder(const JGlobalRefHolder&) = delete; 363 void operator=(const JGlobalRefHolder&) = delete; 364 365 JavaVM* mVm; 366 jobject mObject; 367 }; 368 369 void doThrowNPE(JNIEnv* env); 370 void doThrowAIOOBE(JNIEnv* env); // Array Index Out Of Bounds Exception 371 void doThrowIAE(JNIEnv* env, const char* msg = NULL); // Illegal Argument 372 void doThrowRE(JNIEnv* env, const char* msg = NULL); // Runtime 373 void doThrowISE(JNIEnv* env, const char* msg = NULL); // Illegal State 374 void doThrowOOME(JNIEnv* env, const char* msg = NULL); // Out of memory 375 void doThrowIOE(JNIEnv* env, const char* msg = NULL); // IO Exception 376 377 #define NPE_CHECK_RETURN_ZERO(env, object) \ 378 do { if (NULL == (object)) { doThrowNPE(env); return 0; } } while (0) 379 380 #define NPE_CHECK_RETURN_VOID(env, object) \ 381 do { if (NULL == (object)) { doThrowNPE(env); return; } } while (0) 382 383 #endif // _ANDROID_GRAPHICS_GRAPHICS_JNI_H_ 384