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