Home | History | Annotate | Download | only in graphics
      1 #define LOG_TAG "GraphicsJNI"
      2 
      3 #include <unistd.h>
      4 #include <sys/mman.h>
      5 
      6 #include "jni.h"
      7 #include <nativehelper/JNIHelp.h>
      8 #include "GraphicsJNI.h"
      9 #include "core_jni_helpers.h"
     10 
     11 #include "SkCanvas.h"
     12 #include "SkMath.h"
     13 #include "SkRegion.h"
     14 #include <android_runtime/AndroidRuntime.h>
     15 #include <cutils/ashmem.h>
     16 #include <hwui/Canvas.h>
     17 
     18 using namespace android;
     19 
     20 void doThrowNPE(JNIEnv* env) {
     21     jniThrowNullPointerException(env, NULL);
     22 }
     23 
     24 void doThrowAIOOBE(JNIEnv* env) {
     25     jniThrowException(env, "java/lang/ArrayIndexOutOfBoundsException", NULL);
     26 }
     27 
     28 void doThrowRE(JNIEnv* env, const char* msg) {
     29     jniThrowRuntimeException(env, msg);
     30 }
     31 
     32 void doThrowIAE(JNIEnv* env, const char* msg) {
     33     jniThrowException(env, "java/lang/IllegalArgumentException", msg);
     34 }
     35 
     36 void doThrowISE(JNIEnv* env, const char* msg) {
     37     jniThrowException(env, "java/lang/IllegalStateException", msg);
     38 }
     39 
     40 void doThrowOOME(JNIEnv* env, const char* msg) {
     41     jniThrowException(env, "java/lang/OutOfMemoryError", msg);
     42 }
     43 
     44 void doThrowIOE(JNIEnv* env, const char* msg) {
     45     jniThrowException(env, "java/io/IOException", msg);
     46 }
     47 
     48 bool GraphicsJNI::hasException(JNIEnv *env) {
     49     if (env->ExceptionCheck() != 0) {
     50         ALOGE("*** Uncaught exception returned from Java call!\n");
     51         env->ExceptionDescribe();
     52         return true;
     53     }
     54     return false;
     55 }
     56 
     57 ///////////////////////////////////////////////////////////////////////////////
     58 
     59 AutoJavaFloatArray::AutoJavaFloatArray(JNIEnv* env, jfloatArray array,
     60                                        int minLength, JNIAccess access)
     61 : fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
     62     ALOG_ASSERT(env);
     63     if (array) {
     64         fLen = env->GetArrayLength(array);
     65         if (fLen < minLength) {
     66             LOG_ALWAYS_FATAL("bad length");
     67         }
     68         fPtr = env->GetFloatArrayElements(array, NULL);
     69     }
     70     fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0;
     71 }
     72 
     73 AutoJavaFloatArray::~AutoJavaFloatArray() {
     74     if (fPtr) {
     75         fEnv->ReleaseFloatArrayElements(fArray, fPtr, fReleaseMode);
     76     }
     77 }
     78 
     79 AutoJavaIntArray::AutoJavaIntArray(JNIEnv* env, jintArray array,
     80                                        int minLength)
     81 : fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
     82     ALOG_ASSERT(env);
     83     if (array) {
     84         fLen = env->GetArrayLength(array);
     85         if (fLen < minLength) {
     86             LOG_ALWAYS_FATAL("bad length");
     87         }
     88         fPtr = env->GetIntArrayElements(array, NULL);
     89     }
     90 }
     91 
     92 AutoJavaIntArray::~AutoJavaIntArray() {
     93     if (fPtr) {
     94         fEnv->ReleaseIntArrayElements(fArray, fPtr, 0);
     95     }
     96 }
     97 
     98 AutoJavaShortArray::AutoJavaShortArray(JNIEnv* env, jshortArray array,
     99                                        int minLength, JNIAccess access)
    100 : fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
    101     ALOG_ASSERT(env);
    102     if (array) {
    103         fLen = env->GetArrayLength(array);
    104         if (fLen < minLength) {
    105             LOG_ALWAYS_FATAL("bad length");
    106         }
    107         fPtr = env->GetShortArrayElements(array, NULL);
    108     }
    109     fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0;
    110 }
    111 
    112 AutoJavaShortArray::~AutoJavaShortArray() {
    113     if (fPtr) {
    114         fEnv->ReleaseShortArrayElements(fArray, fPtr, fReleaseMode);
    115     }
    116 }
    117 
    118 AutoJavaByteArray::AutoJavaByteArray(JNIEnv* env, jbyteArray array,
    119                                        int minLength)
    120 : fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
    121     ALOG_ASSERT(env);
    122     if (array) {
    123         fLen = env->GetArrayLength(array);
    124         if (fLen < minLength) {
    125             LOG_ALWAYS_FATAL("bad length");
    126         }
    127         fPtr = env->GetByteArrayElements(array, NULL);
    128     }
    129 }
    130 
    131 AutoJavaByteArray::~AutoJavaByteArray() {
    132     if (fPtr) {
    133         fEnv->ReleaseByteArrayElements(fArray, fPtr, 0);
    134     }
    135 }
    136 
    137 ///////////////////////////////////////////////////////////////////////////////
    138 
    139 static jclass   gRect_class;
    140 static jfieldID gRect_leftFieldID;
    141 static jfieldID gRect_topFieldID;
    142 static jfieldID gRect_rightFieldID;
    143 static jfieldID gRect_bottomFieldID;
    144 
    145 static jclass   gRectF_class;
    146 static jfieldID gRectF_leftFieldID;
    147 static jfieldID gRectF_topFieldID;
    148 static jfieldID gRectF_rightFieldID;
    149 static jfieldID gRectF_bottomFieldID;
    150 
    151 static jclass   gPoint_class;
    152 static jfieldID gPoint_xFieldID;
    153 static jfieldID gPoint_yFieldID;
    154 
    155 static jclass   gPointF_class;
    156 static jfieldID gPointF_xFieldID;
    157 static jfieldID gPointF_yFieldID;
    158 
    159 static jclass   gBitmapConfig_class;
    160 static jfieldID gBitmapConfig_nativeInstanceID;
    161 
    162 static jclass   gBitmapRegionDecoder_class;
    163 static jmethodID gBitmapRegionDecoder_constructorMethodID;
    164 
    165 static jclass   gCanvas_class;
    166 static jfieldID gCanvas_nativeInstanceID;
    167 
    168 static jclass   gPicture_class;
    169 static jfieldID gPicture_nativeInstanceID;
    170 
    171 static jclass   gRegion_class;
    172 static jfieldID gRegion_nativeInstanceID;
    173 static jmethodID gRegion_constructorMethodID;
    174 
    175 static jclass    gByte_class;
    176 static jobject   gVMRuntime;
    177 static jclass    gVMRuntime_class;
    178 static jmethodID gVMRuntime_newNonMovableArray;
    179 static jmethodID gVMRuntime_addressOf;
    180 
    181 static jclass gColorSpace_class;
    182 static jmethodID gColorSpace_getMethodID;
    183 static jmethodID gColorSpace_matchMethodID;
    184 
    185 static jclass gColorSpaceRGB_class;
    186 static jmethodID gColorSpaceRGB_constructorMethodID;
    187 
    188 static jclass gColorSpace_Named_class;
    189 static jfieldID gColorSpace_Named_sRGBFieldID;
    190 static jfieldID gColorSpace_Named_ExtendedSRGBFieldID;
    191 static jfieldID gColorSpace_Named_LinearSRGBFieldID;
    192 static jfieldID gColorSpace_Named_LinearExtendedSRGBFieldID;
    193 
    194 static jclass gTransferParameters_class;
    195 static jmethodID gTransferParameters_constructorMethodID;
    196 
    197 ///////////////////////////////////////////////////////////////////////////////
    198 
    199 void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B)
    200 {
    201     ALOG_ASSERT(env->IsInstanceOf(obj, gRect_class));
    202 
    203     *L = env->GetIntField(obj, gRect_leftFieldID);
    204     *T = env->GetIntField(obj, gRect_topFieldID);
    205     *R = env->GetIntField(obj, gRect_rightFieldID);
    206     *B = env->GetIntField(obj, gRect_bottomFieldID);
    207 }
    208 
    209 void GraphicsJNI::set_jrect(JNIEnv* env, jobject obj, int L, int T, int R, int B)
    210 {
    211     ALOG_ASSERT(env->IsInstanceOf(obj, gRect_class));
    212 
    213     env->SetIntField(obj, gRect_leftFieldID, L);
    214     env->SetIntField(obj, gRect_topFieldID, T);
    215     env->SetIntField(obj, gRect_rightFieldID, R);
    216     env->SetIntField(obj, gRect_bottomFieldID, B);
    217 }
    218 
    219 SkIRect* GraphicsJNI::jrect_to_irect(JNIEnv* env, jobject obj, SkIRect* ir)
    220 {
    221     ALOG_ASSERT(env->IsInstanceOf(obj, gRect_class));
    222 
    223     ir->set(env->GetIntField(obj, gRect_leftFieldID),
    224             env->GetIntField(obj, gRect_topFieldID),
    225             env->GetIntField(obj, gRect_rightFieldID),
    226             env->GetIntField(obj, gRect_bottomFieldID));
    227     return ir;
    228 }
    229 
    230 void GraphicsJNI::irect_to_jrect(const SkIRect& ir, JNIEnv* env, jobject obj)
    231 {
    232     ALOG_ASSERT(env->IsInstanceOf(obj, gRect_class));
    233 
    234     env->SetIntField(obj, gRect_leftFieldID, ir.fLeft);
    235     env->SetIntField(obj, gRect_topFieldID, ir.fTop);
    236     env->SetIntField(obj, gRect_rightFieldID, ir.fRight);
    237     env->SetIntField(obj, gRect_bottomFieldID, ir.fBottom);
    238 }
    239 
    240 SkRect* GraphicsJNI::jrectf_to_rect(JNIEnv* env, jobject obj, SkRect* r)
    241 {
    242     ALOG_ASSERT(env->IsInstanceOf(obj, gRectF_class));
    243 
    244     r->set(env->GetFloatField(obj, gRectF_leftFieldID),
    245            env->GetFloatField(obj, gRectF_topFieldID),
    246            env->GetFloatField(obj, gRectF_rightFieldID),
    247            env->GetFloatField(obj, gRectF_bottomFieldID));
    248     return r;
    249 }
    250 
    251 SkRect* GraphicsJNI::jrect_to_rect(JNIEnv* env, jobject obj, SkRect* r)
    252 {
    253     ALOG_ASSERT(env->IsInstanceOf(obj, gRect_class));
    254 
    255     r->set(SkIntToScalar(env->GetIntField(obj, gRect_leftFieldID)),
    256            SkIntToScalar(env->GetIntField(obj, gRect_topFieldID)),
    257            SkIntToScalar(env->GetIntField(obj, gRect_rightFieldID)),
    258            SkIntToScalar(env->GetIntField(obj, gRect_bottomFieldID)));
    259     return r;
    260 }
    261 
    262 void GraphicsJNI::rect_to_jrectf(const SkRect& r, JNIEnv* env, jobject obj)
    263 {
    264     ALOG_ASSERT(env->IsInstanceOf(obj, gRectF_class));
    265 
    266     env->SetFloatField(obj, gRectF_leftFieldID, SkScalarToFloat(r.fLeft));
    267     env->SetFloatField(obj, gRectF_topFieldID, SkScalarToFloat(r.fTop));
    268     env->SetFloatField(obj, gRectF_rightFieldID, SkScalarToFloat(r.fRight));
    269     env->SetFloatField(obj, gRectF_bottomFieldID, SkScalarToFloat(r.fBottom));
    270 }
    271 
    272 SkIPoint* GraphicsJNI::jpoint_to_ipoint(JNIEnv* env, jobject obj, SkIPoint* point)
    273 {
    274     ALOG_ASSERT(env->IsInstanceOf(obj, gPoint_class));
    275 
    276     point->set(env->GetIntField(obj, gPoint_xFieldID),
    277                env->GetIntField(obj, gPoint_yFieldID));
    278     return point;
    279 }
    280 
    281 void GraphicsJNI::ipoint_to_jpoint(const SkIPoint& ir, JNIEnv* env, jobject obj)
    282 {
    283     ALOG_ASSERT(env->IsInstanceOf(obj, gPoint_class));
    284 
    285     env->SetIntField(obj, gPoint_xFieldID, ir.fX);
    286     env->SetIntField(obj, gPoint_yFieldID, ir.fY);
    287 }
    288 
    289 SkPoint* GraphicsJNI::jpointf_to_point(JNIEnv* env, jobject obj, SkPoint* point)
    290 {
    291     ALOG_ASSERT(env->IsInstanceOf(obj, gPointF_class));
    292 
    293     point->set(env->GetIntField(obj, gPointF_xFieldID),
    294                env->GetIntField(obj, gPointF_yFieldID));
    295     return point;
    296 }
    297 
    298 void GraphicsJNI::point_to_jpointf(const SkPoint& r, JNIEnv* env, jobject obj)
    299 {
    300     ALOG_ASSERT(env->IsInstanceOf(obj, gPointF_class));
    301 
    302     env->SetFloatField(obj, gPointF_xFieldID, SkScalarToFloat(r.fX));
    303     env->SetFloatField(obj, gPointF_yFieldID, SkScalarToFloat(r.fY));
    304 }
    305 
    306 // See enum values in GraphicsJNI.h
    307 jint GraphicsJNI::colorTypeToLegacyBitmapConfig(SkColorType colorType) {
    308     switch (colorType) {
    309         case kRGBA_F16_SkColorType:
    310             return kRGBA_16F_LegacyBitmapConfig;
    311         case kN32_SkColorType:
    312             return kARGB_8888_LegacyBitmapConfig;
    313         case kARGB_4444_SkColorType:
    314             return kARGB_4444_LegacyBitmapConfig;
    315         case kRGB_565_SkColorType:
    316             return kRGB_565_LegacyBitmapConfig;
    317         case kAlpha_8_SkColorType:
    318             return kA8_LegacyBitmapConfig;
    319         case kUnknown_SkColorType:
    320         default:
    321             break;
    322     }
    323     return kNo_LegacyBitmapConfig;
    324 }
    325 
    326 SkColorType GraphicsJNI::legacyBitmapConfigToColorType(jint legacyConfig) {
    327     const uint8_t gConfig2ColorType[] = {
    328         kUnknown_SkColorType,
    329         kAlpha_8_SkColorType,
    330         kUnknown_SkColorType, // Previously kIndex_8_SkColorType,
    331         kRGB_565_SkColorType,
    332         kARGB_4444_SkColorType,
    333         kN32_SkColorType,
    334         kRGBA_F16_SkColorType,
    335         kN32_SkColorType
    336     };
    337 
    338     if (legacyConfig < 0 || legacyConfig > kLastEnum_LegacyBitmapConfig) {
    339         legacyConfig = kNo_LegacyBitmapConfig;
    340     }
    341     return static_cast<SkColorType>(gConfig2ColorType[legacyConfig]);
    342 }
    343 
    344 void GraphicsJNI::getSkBitmap(JNIEnv* env, jobject bitmap, SkBitmap* outBitmap) {
    345     bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap);
    346 }
    347 
    348 SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) {
    349     ALOG_ASSERT(env);
    350     if (NULL == jconfig) {
    351         return kUnknown_SkColorType;
    352     }
    353     ALOG_ASSERT(env->IsInstanceOf(jconfig, gBitmapConfig_class));
    354     int c = env->GetIntField(jconfig, gBitmapConfig_nativeInstanceID);
    355     return legacyBitmapConfigToColorType(c);
    356 }
    357 
    358 bool GraphicsJNI::isHardwareConfig(JNIEnv* env, jobject jconfig) {
    359     ALOG_ASSERT(env);
    360     if (NULL == jconfig) {
    361         return false;
    362     }
    363     int c = env->GetIntField(jconfig, gBitmapConfig_nativeInstanceID);
    364     return c == kHardware_LegacyBitmapConfig;
    365 }
    366 
    367 jint GraphicsJNI::hardwareLegacyBitmapConfig() {
    368     return kHardware_LegacyBitmapConfig;
    369 }
    370 
    371 android::Canvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {
    372     ALOG_ASSERT(env);
    373     ALOG_ASSERT(canvas);
    374     ALOG_ASSERT(env->IsInstanceOf(canvas, gCanvas_class));
    375     jlong canvasHandle = env->GetLongField(canvas, gCanvas_nativeInstanceID);
    376     if (!canvasHandle) {
    377         return NULL;
    378     }
    379     return reinterpret_cast<android::Canvas*>(canvasHandle);
    380 }
    381 
    382 SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region)
    383 {
    384     ALOG_ASSERT(env);
    385     ALOG_ASSERT(region);
    386     ALOG_ASSERT(env->IsInstanceOf(region, gRegion_class));
    387     jlong regionHandle = env->GetLongField(region, gRegion_nativeInstanceID);
    388     SkRegion* r = reinterpret_cast<SkRegion*>(regionHandle);
    389     ALOG_ASSERT(r);
    390     return r;
    391 }
    392 
    393 ///////////////////////////////////////////////////////////////////////////////////////////
    394 
    395 jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
    396 {
    397     ALOG_ASSERT(bitmap != NULL);
    398 
    399     jobject obj = env->NewObject(gBitmapRegionDecoder_class,
    400             gBitmapRegionDecoder_constructorMethodID,
    401             reinterpret_cast<jlong>(bitmap));
    402     hasException(env); // For the side effect of logging.
    403     return obj;
    404 }
    405 
    406 jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
    407 {
    408     ALOG_ASSERT(region != NULL);
    409     jobject obj = env->NewObject(gRegion_class, gRegion_constructorMethodID,
    410                                  reinterpret_cast<jlong>(region), 0);
    411     hasException(env); // For the side effect of logging.
    412     return obj;
    413 }
    414 
    415 ///////////////////////////////////////////////////////////////////////////////
    416 
    417 jobject GraphicsJNI::getColorSpace(JNIEnv* env, SkColorSpace* decodeColorSpace,
    418         SkColorType decodeColorType) {
    419     if (!decodeColorSpace || decodeColorType == kAlpha_8_SkColorType) {
    420         return nullptr;
    421     }
    422 
    423     // Special checks for the common sRGB cases and their extended variants.
    424     jobject namedCS = nullptr;
    425     sk_sp<SkColorSpace> srgbLinear = SkColorSpace::MakeSRGBLinear();
    426     if (decodeColorType == kRGBA_F16_SkColorType) {
    427         // An F16 Bitmap will always report that it is EXTENDED if
    428         // it matches a ColorSpace that has an EXTENDED variant.
    429         if (decodeColorSpace->isSRGB()) {
    430             namedCS = env->GetStaticObjectField(gColorSpace_Named_class,
    431                                                 gColorSpace_Named_ExtendedSRGBFieldID);
    432         } else if (decodeColorSpace == srgbLinear.get()) {
    433             namedCS = env->GetStaticObjectField(gColorSpace_Named_class,
    434                                                 gColorSpace_Named_LinearExtendedSRGBFieldID);
    435         }
    436     } else if (decodeColorSpace->isSRGB()) {
    437         namedCS = env->GetStaticObjectField(gColorSpace_Named_class,
    438                                             gColorSpace_Named_sRGBFieldID);
    439     } else if (decodeColorSpace == srgbLinear.get()) {
    440         namedCS = env->GetStaticObjectField(gColorSpace_Named_class,
    441                                             gColorSpace_Named_LinearSRGBFieldID);
    442     }
    443 
    444     if (namedCS) {
    445         return env->CallStaticObjectMethod(gColorSpace_class, gColorSpace_getMethodID, namedCS);
    446     }
    447 
    448     // Try to match against known RGB color spaces using the CIE XYZ D50
    449     // conversion matrix and numerical transfer function parameters
    450     skcms_Matrix3x3 xyzMatrix;
    451     LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix));
    452 
    453     skcms_TransferFunction transferParams;
    454     // We can only handle numerical transfer functions at the moment
    455     LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams));
    456 
    457     jobject params = env->NewObject(gTransferParameters_class,
    458             gTransferParameters_constructorMethodID,
    459             transferParams.a, transferParams.b, transferParams.c,
    460             transferParams.d, transferParams.e, transferParams.f,
    461             transferParams.g);
    462 
    463     jfloatArray xyzArray = env->NewFloatArray(9);
    464     jfloat xyz[9] = {
    465             xyzMatrix.vals[0][0],
    466             xyzMatrix.vals[1][0],
    467             xyzMatrix.vals[2][0],
    468             xyzMatrix.vals[0][1],
    469             xyzMatrix.vals[1][1],
    470             xyzMatrix.vals[2][1],
    471             xyzMatrix.vals[0][2],
    472             xyzMatrix.vals[1][2],
    473             xyzMatrix.vals[2][2]
    474     };
    475     env->SetFloatArrayRegion(xyzArray, 0, 9, xyz);
    476 
    477     jobject colorSpace = env->CallStaticObjectMethod(gColorSpace_class,
    478             gColorSpace_matchMethodID, xyzArray, params);
    479 
    480     if (colorSpace == nullptr) {
    481         // We couldn't find an exact match, let's create a new color space
    482         // instance with the 3x3 conversion matrix and transfer function
    483         colorSpace = env->NewObject(gColorSpaceRGB_class,
    484                 gColorSpaceRGB_constructorMethodID,
    485                 env->NewStringUTF("Unknown"), xyzArray, params);
    486     }
    487 
    488     env->DeleteLocalRef(xyzArray);
    489     return colorSpace;
    490 }
    491 
    492 ///////////////////////////////////////////////////////////////////////////////
    493 bool HeapAllocator::allocPixelRef(SkBitmap* bitmap) {
    494     mStorage = android::Bitmap::allocateHeapBitmap(bitmap);
    495     return !!mStorage;
    496 }
    497 
    498 ////////////////////////////////////////////////////////////////////////////////
    499 
    500 RecyclingClippingPixelAllocator::RecyclingClippingPixelAllocator(
    501         android::Bitmap* recycledBitmap, size_t recycledBytes)
    502     : mRecycledBitmap(recycledBitmap)
    503     , mRecycledBytes(recycledBytes)
    504     , mSkiaBitmap(nullptr)
    505     , mNeedsCopy(false)
    506 {}
    507 
    508 RecyclingClippingPixelAllocator::~RecyclingClippingPixelAllocator() {}
    509 
    510 bool RecyclingClippingPixelAllocator::allocPixelRef(SkBitmap* bitmap) {
    511     // Ensure that the caller did not pass in a NULL bitmap to the constructor or this
    512     // function.
    513     LOG_ALWAYS_FATAL_IF(!mRecycledBitmap);
    514     LOG_ALWAYS_FATAL_IF(!bitmap);
    515     mSkiaBitmap = bitmap;
    516 
    517     // This behaves differently than the RecyclingPixelAllocator.  For backwards
    518     // compatibility, the original color type of the recycled bitmap must be maintained.
    519     if (mRecycledBitmap->info().colorType() != bitmap->colorType()) {
    520         return false;
    521     }
    522 
    523     // The Skia bitmap specifies the width and height needed by the decoder.
    524     // mRecycledBitmap specifies the width and height of the bitmap that we
    525     // want to reuse.  Neither can be changed.  We will try to find a way
    526     // to reuse the memory.
    527     const int maxWidth = SkTMax(bitmap->width(), mRecycledBitmap->info().width());
    528     const int maxHeight = SkTMax(bitmap->height(), mRecycledBitmap->info().height());
    529     const SkImageInfo maxInfo = bitmap->info().makeWH(maxWidth, maxHeight);
    530     const size_t rowBytes = maxInfo.minRowBytes();
    531     const size_t bytesNeeded = maxInfo.computeByteSize(rowBytes);
    532     if (bytesNeeded <= mRecycledBytes) {
    533         // Here we take advantage of reconfigure() to reset the rowBytes
    534         // of mRecycledBitmap.  It is very important that we pass in
    535         // mRecycledBitmap->info() for the SkImageInfo.  According to the
    536         // specification for BitmapRegionDecoder, we are not allowed to change
    537         // the SkImageInfo.
    538         // We can (must) preserve the color space since it doesn't affect the
    539         // storage needs
    540         mRecycledBitmap->reconfigure(
    541                 mRecycledBitmap->info().makeColorSpace(bitmap->refColorSpace()),
    542                 rowBytes);
    543 
    544         // Give the bitmap the same pixelRef as mRecycledBitmap.
    545         // skbug.com/4538: We also need to make sure that the rowBytes on the pixel ref
    546         //                 match the rowBytes on the bitmap.
    547         bitmap->setInfo(bitmap->info(), rowBytes);
    548         bitmap->setPixelRef(sk_ref_sp(mRecycledBitmap), 0, 0);
    549 
    550         // Make sure that the recycled bitmap has the correct alpha type.
    551         mRecycledBitmap->setAlphaType(bitmap->alphaType());
    552 
    553         bitmap->notifyPixelsChanged();
    554         mNeedsCopy = false;
    555 
    556         // TODO: If the dimensions of the SkBitmap are smaller than those of
    557         // mRecycledBitmap, should we zero the memory in mRecycledBitmap?
    558         return true;
    559     }
    560 
    561     // In the event that mRecycledBitmap is not large enough, allocate new memory
    562     // on the heap.
    563     SkBitmap::HeapAllocator heapAllocator;
    564 
    565     // We will need to copy from heap memory to mRecycledBitmap's memory after the
    566     // decode is complete.
    567     mNeedsCopy = true;
    568 
    569     return heapAllocator.allocPixelRef(bitmap);
    570 }
    571 
    572 void RecyclingClippingPixelAllocator::copyIfNecessary() {
    573     if (mNeedsCopy) {
    574         mRecycledBitmap->ref();
    575         SkPixelRef* recycledPixels = mRecycledBitmap;
    576         void* dst = recycledPixels->pixels();
    577         const size_t dstRowBytes = mRecycledBitmap->rowBytes();
    578         const size_t bytesToCopy = std::min(mRecycledBitmap->info().minRowBytes(),
    579                 mSkiaBitmap->info().minRowBytes());
    580         const int rowsToCopy = std::min(mRecycledBitmap->info().height(),
    581                 mSkiaBitmap->info().height());
    582         for (int y = 0; y < rowsToCopy; y++) {
    583             memcpy(dst, mSkiaBitmap->getAddr(0, y), bytesToCopy);
    584             dst = SkTAddOffset<void>(dst, dstRowBytes);
    585         }
    586         recycledPixels->notifyPixelsChanged();
    587         recycledPixels->unref();
    588     }
    589     mRecycledBitmap = nullptr;
    590     mSkiaBitmap = nullptr;
    591 }
    592 
    593 ////////////////////////////////////////////////////////////////////////////////
    594 
    595 AshmemPixelAllocator::AshmemPixelAllocator(JNIEnv *env) {
    596     LOG_ALWAYS_FATAL_IF(env->GetJavaVM(&mJavaVM) != JNI_OK,
    597             "env->GetJavaVM failed");
    598 }
    599 
    600 bool AshmemPixelAllocator::allocPixelRef(SkBitmap* bitmap) {
    601     mStorage = android::Bitmap::allocateAshmemBitmap(bitmap);
    602     return !!mStorage;
    603 }
    604 
    605 ////////////////////////////////////////////////////////////////////////////////
    606 
    607 int register_android_graphics_Graphics(JNIEnv* env)
    608 {
    609     jmethodID m;
    610     jclass c;
    611 
    612     gRect_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Rect"));
    613     gRect_leftFieldID = GetFieldIDOrDie(env, gRect_class, "left", "I");
    614     gRect_topFieldID = GetFieldIDOrDie(env, gRect_class, "top", "I");
    615     gRect_rightFieldID = GetFieldIDOrDie(env, gRect_class, "right", "I");
    616     gRect_bottomFieldID = GetFieldIDOrDie(env, gRect_class, "bottom", "I");
    617 
    618     gRectF_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/RectF"));
    619     gRectF_leftFieldID = GetFieldIDOrDie(env, gRectF_class, "left", "F");
    620     gRectF_topFieldID = GetFieldIDOrDie(env, gRectF_class, "top", "F");
    621     gRectF_rightFieldID = GetFieldIDOrDie(env, gRectF_class, "right", "F");
    622     gRectF_bottomFieldID = GetFieldIDOrDie(env, gRectF_class, "bottom", "F");
    623 
    624     gPoint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Point"));
    625     gPoint_xFieldID = GetFieldIDOrDie(env, gPoint_class, "x", "I");
    626     gPoint_yFieldID = GetFieldIDOrDie(env, gPoint_class, "y", "I");
    627 
    628     gPointF_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/PointF"));
    629     gPointF_xFieldID = GetFieldIDOrDie(env, gPointF_class, "x", "F");
    630     gPointF_yFieldID = GetFieldIDOrDie(env, gPointF_class, "y", "F");
    631 
    632     gBitmapRegionDecoder_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/BitmapRegionDecoder"));
    633     gBitmapRegionDecoder_constructorMethodID = GetMethodIDOrDie(env, gBitmapRegionDecoder_class, "<init>", "(J)V");
    634 
    635     gBitmapConfig_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Bitmap$Config"));
    636     gBitmapConfig_nativeInstanceID = GetFieldIDOrDie(env, gBitmapConfig_class, "nativeInt", "I");
    637 
    638     gCanvas_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Canvas"));
    639     gCanvas_nativeInstanceID = GetFieldIDOrDie(env, gCanvas_class, "mNativeCanvasWrapper", "J");
    640 
    641     gPicture_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Picture"));
    642     gPicture_nativeInstanceID = GetFieldIDOrDie(env, gPicture_class, "mNativePicture", "J");
    643 
    644     gRegion_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Region"));
    645     gRegion_nativeInstanceID = GetFieldIDOrDie(env, gRegion_class, "mNativeRegion", "J");
    646     gRegion_constructorMethodID = GetMethodIDOrDie(env, gRegion_class, "<init>", "(JI)V");
    647 
    648     c = env->FindClass("java/lang/Byte");
    649     gByte_class = (jclass) env->NewGlobalRef(
    650         env->GetStaticObjectField(c, env->GetStaticFieldID(c, "TYPE", "Ljava/lang/Class;")));
    651 
    652     gVMRuntime_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "dalvik/system/VMRuntime"));
    653     m = env->GetStaticMethodID(gVMRuntime_class, "getRuntime", "()Ldalvik/system/VMRuntime;");
    654     gVMRuntime = env->NewGlobalRef(env->CallStaticObjectMethod(gVMRuntime_class, m));
    655     gVMRuntime_newNonMovableArray = GetMethodIDOrDie(env, gVMRuntime_class, "newNonMovableArray",
    656                                                      "(Ljava/lang/Class;I)Ljava/lang/Object;");
    657     gVMRuntime_addressOf = GetMethodIDOrDie(env, gVMRuntime_class, "addressOf", "(Ljava/lang/Object;)J");
    658 
    659     gColorSpace_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/ColorSpace"));
    660     gColorSpace_getMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class,
    661             "get", "(Landroid/graphics/ColorSpace$Named;)Landroid/graphics/ColorSpace;");
    662     gColorSpace_matchMethodID = GetStaticMethodIDOrDie(env, gColorSpace_class, "match",
    663             "([FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)Landroid/graphics/ColorSpace;");
    664 
    665     gColorSpaceRGB_class = MakeGlobalRefOrDie(env,
    666             FindClassOrDie(env, "android/graphics/ColorSpace$Rgb"));
    667     gColorSpaceRGB_constructorMethodID = GetMethodIDOrDie(env, gColorSpaceRGB_class,
    668             "<init>", "(Ljava/lang/String;[FLandroid/graphics/ColorSpace$Rgb$TransferParameters;)V");
    669 
    670     gColorSpace_Named_class = MakeGlobalRefOrDie(env,
    671             FindClassOrDie(env, "android/graphics/ColorSpace$Named"));
    672     gColorSpace_Named_sRGBFieldID = GetStaticFieldIDOrDie(env,
    673             gColorSpace_Named_class, "SRGB", "Landroid/graphics/ColorSpace$Named;");
    674     gColorSpace_Named_ExtendedSRGBFieldID = GetStaticFieldIDOrDie(env,
    675             gColorSpace_Named_class, "EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;");
    676     gColorSpace_Named_LinearSRGBFieldID = GetStaticFieldIDOrDie(env,
    677             gColorSpace_Named_class, "LINEAR_SRGB", "Landroid/graphics/ColorSpace$Named;");
    678     gColorSpace_Named_LinearExtendedSRGBFieldID = GetStaticFieldIDOrDie(env,
    679             gColorSpace_Named_class, "LINEAR_EXTENDED_SRGB", "Landroid/graphics/ColorSpace$Named;");
    680 
    681     gTransferParameters_class = MakeGlobalRefOrDie(env, FindClassOrDie(env,
    682             "android/graphics/ColorSpace$Rgb$TransferParameters"));
    683     gTransferParameters_constructorMethodID = GetMethodIDOrDie(env, gTransferParameters_class,
    684             "<init>", "(DDDDDDD)V");
    685 
    686     return 0;
    687 }
    688