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