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