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_cluster_count_to_run_info(JNIEnv* env, jobject runInfo, jint clusterCount); 81 82 static void set_jpoint(JNIEnv*, jobject jrect, int x, int y); 83 84 static SkIPoint* jpoint_to_ipoint(JNIEnv*, jobject jpoint, SkIPoint* point); 85 static void ipoint_to_jpoint(const SkIPoint& point, JNIEnv*, jobject jpoint); 86 87 static SkPoint* jpointf_to_point(JNIEnv*, jobject jpointf, SkPoint* point); 88 static void point_to_jpointf(const SkPoint& point, JNIEnv*, jobject jpointf); 89 90 ANDROID_API static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas); 91 static android::Bitmap* getNativeBitmap(JNIEnv*, jobject bitmap); 92 static SkImageInfo getBitmapInfo(JNIEnv*, jobject bitmap, uint32_t* outRowBytes, 93 bool* isHardware); 94 static SkRegion* getNativeRegion(JNIEnv*, jobject region); 95 96 /** 97 * Set SkFontMetrics to Java Paint.FontMetrics. 98 * Do nothing if metrics is nullptr. 99 */ 100 static void set_metrics(JNIEnv*, jobject metrics, const SkFontMetrics& skmetrics); 101 /** 102 * Set SkFontMetrics to Java Paint.FontMetricsInt and return recommended interline space. 103 * Do nothing if metrics is nullptr. 104 */ 105 static int set_metrics_int(JNIEnv*, jobject metrics, const SkFontMetrics& skmetrics); 106 107 /* 108 * LegacyBitmapConfig is the old enum in Skia that matched the enum int values 109 * in Bitmap.Config. Skia no longer supports this config, but has replaced it 110 * with SkColorType. These routines convert between the two. 111 */ 112 static SkColorType legacyBitmapConfigToColorType(jint legacyConfig); 113 static jint colorTypeToLegacyBitmapConfig(SkColorType colorType); 114 115 /** Return the corresponding native colorType from the java Config enum, 116 or kUnknown_SkColorType if the java object is null. 117 */ 118 static SkColorType getNativeBitmapColorType(JNIEnv*, jobject jconfig); 119 static AndroidBitmapFormat getFormatFromConfig(JNIEnv* env, jobject jconfig); 120 static jobject getConfigFromFormat(JNIEnv* env, AndroidBitmapFormat format); 121 122 static bool isHardwareConfig(JNIEnv* env, jobject jconfig); 123 static jint hardwareLegacyBitmapConfig(); 124 125 static jobject createRegion(JNIEnv* env, SkRegion* region); 126 127 static jobject createBitmapRegionDecoder(JNIEnv* env, 128 android::BitmapRegionDecoderWrapper* bitmap); 129 130 /** Copy the colors in colors[] to the bitmap, convert to the correct 131 format along the way. 132 Whether to use premultiplied pixels is determined by dstBitmap's alphaType. 133 */ 134 static bool SetPixels(JNIEnv* env, jintArray colors, int srcOffset, 135 int srcStride, int x, int y, int width, int height, 136 SkBitmap* dstBitmap); 137 138 /** 139 * Convert the native SkColorSpace retrieved from ColorSpace.Rgb.getNativeInstance(). 140 * 141 * This will never throw an Exception. If the ColorSpace is one that Skia cannot 142 * use, ColorSpace.Rgb.getNativeInstance() would have thrown an Exception. It may, 143 * however, be nullptr, which may be acceptable. 144 */ 145 static sk_sp<SkColorSpace> getNativeColorSpace(jlong colorSpaceHandle); 146 147 /** 148 * Return the android.graphics.ColorSpace Java object that corresponds to decodeColorSpace 149 * and decodeColorType. 150 * 151 * This may create a new object if none of the Named ColorSpaces match. 152 */ 153 static jobject getColorSpace(JNIEnv* env, SkColorSpace* decodeColorSpace, 154 SkColorType decodeColorType); 155 156 /** 157 * Convert from a Java @ColorLong to an SkColor4f that Skia can use directly. 158 * 159 * This ignores the encoded ColorSpace, besides checking to see if it is sRGB, 160 * which is encoded differently. The color space should be passed down separately 161 * via ColorSpace#getNativeInstance(), and converted with getNativeColorSpace(), 162 * above. 163 */ 164 static SkColor4f convertColorLong(jlong color); 165 166 private: 167 /* JNI JavaVM pointer */ 168 static JavaVM* mJavaVM; 169 }; 170 171 class HeapAllocator : public android::skia::BRDAllocator { 172 public: HeapAllocator()173 HeapAllocator() { }; ~HeapAllocator()174 ~HeapAllocator() { }; 175 176 virtual bool allocPixelRef(SkBitmap* bitmap) override; 177 178 /** 179 * Fetches the backing allocation object. Must be called! 180 */ getStorageObjAndReset()181 android::Bitmap* getStorageObjAndReset() { 182 return mStorage.release(); 183 }; 184 zeroInit()185 SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kYes_ZeroInitialized; } 186 private: 187 sk_sp<android::Bitmap> mStorage; 188 }; 189 190 /** 191 * Allocator to handle reusing bitmaps for BitmapRegionDecoder. 192 * 193 * The BitmapRegionDecoder documentation states that, if it is 194 * provided, the recycled bitmap will always be reused, clipping 195 * the decoded output to fit in the recycled bitmap if necessary. 196 * This allocator implements that behavior. 197 * 198 * Skia's BitmapRegionDecoder expects the memory that 199 * is allocated to be large enough to decode the entire region 200 * that is requested. It will decode directly into the memory 201 * that is provided. 202 * 203 * FIXME: BUG:25465958 204 * If the recycled bitmap is not large enough for the decode 205 * requested, meaning that a clip is required, we will allocate 206 * enough memory for Skia to perform the decode, and then copy 207 * from the decoded output into the recycled bitmap. 208 * 209 * If the recycled bitmap is large enough for the decode requested, 210 * we will provide that memory for Skia to decode directly into. 211 * 212 * This allocator should only be used for a single allocation. 213 * After we reuse the recycledBitmap once, it is dangerous to 214 * reuse it again, given that it still may be in use from our 215 * first allocation. 216 */ 217 class RecyclingClippingPixelAllocator : public android::skia::BRDAllocator { 218 public: 219 RecyclingClippingPixelAllocator(android::Bitmap* recycledBitmap, bool mustMatchColorType = true, 220 std::optional<SkRect> desiredSubset = std::nullopt); 221 222 ~RecyclingClippingPixelAllocator(); 223 224 virtual bool allocPixelRef(SkBitmap* bitmap) override; 225 226 /** 227 * Must be called! 228 * 229 * In the event that the recycled bitmap is not large enough for 230 * the allocation requested, we will allocate memory on the heap 231 * instead. As a final step, once we are done using this memory, 232 * we will copy the contents of the heap memory into the recycled 233 * bitmap's memory, clipping as necessary. 234 */ 235 void copyIfNecessary(); 236 237 /** 238 * Indicates that this allocator does not allocate zero initialized 239 * memory. 240 */ zeroInit()241 SkCodec::ZeroInitialized zeroInit() const override { return SkCodec::kNo_ZeroInitialized; } 242 243 private: 244 /** 245 * Optionally returns a subset rectangle that we need to upsample from. 246 * E.g., a gainmap subset may be decoded in a slightly larger rectangle 247 * than is needed (in order to correctly preserve gainmap alignment when 248 * rendering at display time), so we need to re-sample the "intended" 249 * gainmap back up to the bitmap dimensions. 250 * 251 * If we don't need to upsample from a subregion, then returns an empty 252 * optional 253 */ 254 static std::optional<SkRect> getSourceBoundsForUpsample(std::optional<SkRect> subset); 255 256 android::Bitmap* mRecycledBitmap; 257 const size_t mRecycledBytes; 258 SkBitmap* mSkiaBitmap; 259 bool mNeedsCopy; 260 const bool mMustMatchColorType; 261 const std::optional<SkRect> mDesiredSubset; 262 }; 263 264 class AshmemPixelAllocator : public SkBitmap::Allocator { 265 public: 266 explicit AshmemPixelAllocator(JNIEnv* env); ~AshmemPixelAllocator()267 ~AshmemPixelAllocator() { }; 268 virtual bool allocPixelRef(SkBitmap* bitmap); getStorageObjAndReset()269 android::Bitmap* getStorageObjAndReset() { 270 return mStorage.release(); 271 }; 272 273 private: 274 JavaVM* mJavaVM; 275 sk_sp<android::Bitmap> mStorage; 276 }; 277 278 279 enum JNIAccess { 280 kRO_JNIAccess, 281 kRW_JNIAccess 282 }; 283 284 class AutoJavaFloatArray { 285 public: 286 AutoJavaFloatArray(JNIEnv* env, jfloatArray array, 287 int minLength = 0, JNIAccess = kRW_JNIAccess); 288 ~AutoJavaFloatArray(); 289 ptr()290 float* ptr() const { return fPtr; } length()291 int length() const { return fLen; } 292 293 private: 294 JNIEnv* fEnv; 295 jfloatArray fArray; 296 float* fPtr; 297 int fLen; 298 int fReleaseMode; 299 }; 300 301 class AutoJavaIntArray { 302 public: 303 AutoJavaIntArray(JNIEnv* env, jintArray array, int minLength = 0); 304 ~AutoJavaIntArray(); 305 ptr()306 jint* ptr() const { return fPtr; } length()307 int length() const { return fLen; } 308 309 private: 310 JNIEnv* fEnv; 311 jintArray fArray; 312 jint* fPtr; 313 int fLen; 314 }; 315 316 class AutoJavaShortArray { 317 public: 318 AutoJavaShortArray(JNIEnv* env, jshortArray array, 319 int minLength = 0, JNIAccess = kRW_JNIAccess); 320 ~AutoJavaShortArray(); 321 ptr()322 jshort* ptr() const { return fPtr; } length()323 int length() const { return fLen; } 324 325 private: 326 JNIEnv* fEnv; 327 jshortArray fArray; 328 jshort* fPtr; 329 int fLen; 330 int fReleaseMode; 331 }; 332 333 class AutoJavaByteArray { 334 public: 335 AutoJavaByteArray(JNIEnv* env, jbyteArray array, int minLength = 0); 336 ~AutoJavaByteArray(); 337 ptr()338 jbyte* ptr() const { return fPtr; } length()339 int length() const { return fLen; } 340 341 private: 342 JNIEnv* fEnv; 343 jbyteArray fArray; 344 jbyte* fPtr; 345 int fLen; 346 }; 347 348 class JGlobalRefHolder { 349 public: JGlobalRefHolder(JavaVM * vm,jobject object)350 JGlobalRefHolder(JavaVM* vm, jobject object) : mVm(vm), mObject(object) {} 351 ~JGlobalRefHolder()352 virtual ~JGlobalRefHolder() { 353 env()->DeleteGlobalRef(mObject); 354 mObject = nullptr; 355 } 356 object()357 jobject object() { return mObject; } vm()358 JavaVM* vm() { return mVm; } 359 env()360 JNIEnv* env() { 361 JNIEnv* env; 362 if (mVm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { 363 LOG_ALWAYS_FATAL("Failed to get JNIEnv for JavaVM: %p", mVm); 364 } 365 return env; 366 } 367 368 private: 369 JGlobalRefHolder(const JGlobalRefHolder&) = delete; 370 void operator=(const JGlobalRefHolder&) = delete; 371 372 JavaVM* mVm; 373 jobject mObject; 374 }; 375 376 void doThrowNPE(JNIEnv* env); 377 void doThrowAIOOBE(JNIEnv* env); // Array Index Out Of Bounds Exception 378 void doThrowIAE(JNIEnv* env, const char* msg = NULL); // Illegal Argument 379 void doThrowRE(JNIEnv* env, const char* msg = NULL); // Runtime 380 void doThrowISE(JNIEnv* env, const char* msg = NULL); // Illegal State 381 void doThrowOOME(JNIEnv* env, const char* msg = NULL); // Out of memory 382 void doThrowIOE(JNIEnv* env, const char* msg = NULL); // IO Exception 383 384 #define NPE_CHECK_RETURN_ZERO(env, object) \ 385 do { if (NULL == (object)) { doThrowNPE(env); return 0; } } while (0) 386 387 #define NPE_CHECK_RETURN_VOID(env, object) \ 388 do { if (NULL == (object)) { doThrowNPE(env); return; } } while (0) 389 390 #endif // _ANDROID_GRAPHICS_GRAPHICS_JNI_H_ 391