1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android/bitmap.h>
18 
19 #pragma GCC diagnostic push
20 #pragma GCC diagnostic ignored "-Wunused-parameter"
21 #include <GraphicsJNI.h>
22 #pragma GCC diagnostic pop
23 
AndroidBitmap_getInfo(JNIEnv * env,jobject jbitmap,AndroidBitmapInfo * info)24 int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
25                           AndroidBitmapInfo* info) {
26     if (NULL == env || NULL == jbitmap) {
27         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
28     }
29 
30     SkBitmap bm;
31     GraphicsJNI::getSkBitmap(env, jbitmap, &bm);
32 
33     if (info) {
34         info->width     = bm.width();
35         info->height    = bm.height();
36         info->stride    = bm.rowBytes();
37         info->flags     = 0;
38 
39         switch (bm.colorType()) {
40             case kN32_SkColorType:
41                 info->format = ANDROID_BITMAP_FORMAT_RGBA_8888;
42                 break;
43             case kRGB_565_SkColorType:
44                 info->format = ANDROID_BITMAP_FORMAT_RGB_565;
45                 break;
46             case kARGB_4444_SkColorType:
47                 info->format = ANDROID_BITMAP_FORMAT_RGBA_4444;
48                 break;
49             case kAlpha_8_SkColorType:
50                 info->format = ANDROID_BITMAP_FORMAT_A_8;
51                 break;
52             default:
53                 info->format = ANDROID_BITMAP_FORMAT_NONE;
54                 break;
55         }
56     }
57     return ANDROID_BITMAP_RESULT_SUCCESS;
58 }
59 
AndroidBitmap_lockPixels(JNIEnv * env,jobject jbitmap,void ** addrPtr)60 int AndroidBitmap_lockPixels(JNIEnv* env, jobject jbitmap, void** addrPtr) {
61     if (NULL == env || NULL == jbitmap) {
62         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
63     }
64 
65     SkPixelRef* pixelRef = GraphicsJNI::refSkPixelRef(env, jbitmap);
66     if (!pixelRef) {
67         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
68     }
69 
70     pixelRef->lockPixels();
71     void* addr = pixelRef->pixels();
72     if (NULL == addr) {
73         pixelRef->unlockPixels();
74         pixelRef->unref();
75         return ANDROID_BITMAP_RESULT_ALLOCATION_FAILED;
76     }
77 
78     if (addrPtr) {
79         *addrPtr = addr;
80     }
81     return ANDROID_BITMAP_RESULT_SUCCESS;
82 }
83 
AndroidBitmap_unlockPixels(JNIEnv * env,jobject jbitmap)84 int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap) {
85     if (NULL == env || NULL == jbitmap) {
86         return ANDROID_BITMAP_RESULT_BAD_PARAMETER;
87     }
88 
89     SkPixelRef* pixelRef = GraphicsJNI::refSkPixelRef(env, jbitmap);
90     if (!pixelRef) {
91         return ANDROID_BITMAP_RESULT_JNI_EXCEPTION;
92     }
93 
94     // notifyPixelsChanged() needs be called to apply writes to GL-backed
95     // bitmaps.  Note that this will slow down read-only accesses to the
96     // bitmaps, but the NDK methods are primarily intended to be used for
97     // writes.
98     pixelRef->notifyPixelsChanged();
99 
100     pixelRef->unlockPixels();
101     // Awkward in that we need to double-unref as the call to get the SkPixelRef
102     // did a ref(), so we need to unref() for the local ref and for the previous
103     // AndroidBitmap_lockPixels(). However this keeps GraphicsJNI a bit safer
104     // if others start using it without knowing about android::Bitmap's "fun"
105     // ref counting mechanism(s).
106     pixelRef->unref();
107     pixelRef->unref();
108 
109     return ANDROID_BITMAP_RESULT_SUCCESS;
110 }
111 
112