• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #define LOG_TAG "9patch"
19 #define LOG_NDEBUG 1
20 
21 #include <utils/ResourceTypes.h>
22 #include <utils/Log.h>
23 
24 #include "SkCanvas.h"
25 #include "SkRegion.h"
26 #include "GraphicsJNI.h"
27 
28 #include "JNIHelp.h"
29 
30 extern void NinePatch_Draw(SkCanvas* canvas, const SkRect& bounds,
31                 const SkBitmap& bitmap, const android::Res_png_9patch& chunk,
32                            const SkPaint* paint, SkRegion** outRegion);
33 
34 using namespace android;
35 
36 class SkNinePatchGlue {
37 public:
isNinePatchChunk(JNIEnv * env,jobject,jbyteArray obj)38     static jboolean isNinePatchChunk(JNIEnv* env, jobject, jbyteArray obj)
39     {
40         if (NULL == obj) {
41             return false;
42         }
43         if (env->GetArrayLength(obj) < (int)sizeof(Res_png_9patch)) {
44             return false;
45         }
46         const jbyte* array = env->GetByteArrayElements(obj, 0);
47         if (array != NULL) {
48             const Res_png_9patch* chunk =
49                                 reinterpret_cast<const Res_png_9patch*>(array);
50             int8_t wasDeserialized = chunk->wasDeserialized;
51             env->ReleaseByteArrayElements(obj, const_cast<jbyte*>(array),
52                                           JNI_ABORT);
53             return wasDeserialized != -1;
54         }
55         return false;
56     }
57 
validateNinePatchChunk(JNIEnv * env,jobject,jint,jbyteArray obj)58     static void validateNinePatchChunk(JNIEnv* env, jobject, jint, jbyteArray obj)
59     {
60         if (env->GetArrayLength(obj) < (int) (sizeof(Res_png_9patch))) {
61             jniThrowException(env, "java/lang/RuntimeException",
62                               "Array too small for chunk.");
63             return;
64         }
65 
66         // XXX Also check that dimensions are correct.
67     }
68 
draw(JNIEnv * env,SkCanvas * canvas,SkRect & bounds,const SkBitmap * bitmap,jbyteArray chunkObj,const SkPaint * paint,jint destDensity,jint srcDensity)69     static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds,
70                       const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
71                       jint destDensity, jint srcDensity)
72     {
73         size_t chunkSize = env->GetArrayLength(chunkObj);
74         void* storage = alloca(chunkSize);
75         env->GetByteArrayRegion(chunkObj, 0, chunkSize,
76                                 reinterpret_cast<jbyte*>(storage));
77         if (!env->ExceptionCheck()) {
78             // need to deserialize the chunk
79             Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
80             assert(chunkSize == chunk->serializedSize());
81             // this relies on deserialization being done in place
82             Res_png_9patch::deserialize(chunk);
83 
84             if (destDensity == srcDensity || destDensity == 0
85                     || srcDensity == 0) {
86                 LOGV("Drawing unscaled 9-patch: (%g,%g)-(%g,%g)",
87                         SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
88                         SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom));
89                 NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
90             } else {
91                 canvas->save();
92 
93                 SkScalar scale = SkFloatToScalar(destDensity / (float)srcDensity);
94                 canvas->translate(bounds.fLeft, bounds.fTop);
95                 canvas->scale(scale, scale);
96 
97                 bounds.fRight = SkScalarDiv(bounds.fRight-bounds.fLeft, scale);
98                 bounds.fBottom = SkScalarDiv(bounds.fBottom-bounds.fTop, scale);
99                 bounds.fLeft = bounds.fTop = 0;
100 
101                 LOGV("Drawing scaled 9-patch: (%g,%g)-(%g,%g) srcDensity=%d destDensity=%d",
102                         SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
103                         SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom),
104                         srcDensity, destDensity);
105 
106                 NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
107 
108                 canvas->restore();
109             }
110         }
111     }
112 
drawF(JNIEnv * env,jobject,SkCanvas * canvas,jobject boundsRectF,const SkBitmap * bitmap,jbyteArray chunkObj,const SkPaint * paint,jint destDensity,jint srcDensity)113     static void drawF(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRectF,
114                       const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
115                       jint destDensity, jint srcDensity)
116     {
117         SkASSERT(canvas);
118         SkASSERT(boundsRectF);
119         SkASSERT(bitmap);
120         SkASSERT(chunkObj);
121         // paint is optional
122 
123         SkRect      bounds;
124         GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds);
125 
126         draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity);
127     }
128 
drawI(JNIEnv * env,jobject,SkCanvas * canvas,jobject boundsRect,const SkBitmap * bitmap,jbyteArray chunkObj,const SkPaint * paint,jint destDensity,jint srcDensity)129     static void drawI(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRect,
130                       const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint,
131                       jint destDensity, jint srcDensity)
132     {
133         SkASSERT(canvas);
134         SkASSERT(boundsRect);
135         SkASSERT(bitmap);
136         SkASSERT(chunkObj);
137         // paint is optional
138 
139         SkRect      bounds;
140         GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
141         draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity);
142     }
143 
getTransparentRegion(JNIEnv * env,jobject,const SkBitmap * bitmap,jbyteArray chunkObj,jobject boundsRect)144     static jint getTransparentRegion(JNIEnv* env, jobject,
145                     const SkBitmap* bitmap, jbyteArray chunkObj,
146                     jobject boundsRect)
147     {
148         SkASSERT(bitmap);
149         SkASSERT(chunkObj);
150         SkASSERT(boundsRect);
151 
152         SkRect      bounds;
153         GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds);
154         size_t chunkSize = env->GetArrayLength(chunkObj);
155         void* storage = alloca(chunkSize);
156         env->GetByteArrayRegion(chunkObj, 0, chunkSize,
157                                 reinterpret_cast<jbyte*>(storage));
158         if (!env->ExceptionCheck()) {
159             // need to deserialize the chunk
160             Res_png_9patch* chunk = static_cast<Res_png_9patch*>(storage);
161             assert(chunkSize == chunk->serializedSize());
162             // this relies on deserialization being done in place
163             Res_png_9patch::deserialize(chunk);
164             SkRegion* region = NULL;
165             NinePatch_Draw(NULL, bounds, *bitmap, *chunk, NULL, &region);
166             return (jint)region;
167         }
168         return 0;
169     }
170 
171 };
172 
173 /////////////////////////////////////////////////////////////////////////////////////////
174 
175 #include <android_runtime/AndroidRuntime.h>
176 
177 static JNINativeMethod gNinePatchMethods[] = {
178     { "isNinePatchChunk", "([B)Z",                      (void*)SkNinePatchGlue::isNinePatchChunk   },
179     { "validateNinePatchChunk", "(I[B)V",               (void*)SkNinePatchGlue::validateNinePatchChunk   },
180     { "nativeDraw", "(ILandroid/graphics/RectF;I[BIII)V", (void*)SkNinePatchGlue::drawF   },
181     { "nativeDraw", "(ILandroid/graphics/Rect;I[BIII)V",  (void*)SkNinePatchGlue::drawI   },
182     { "nativeGetTransparentRegion", "(I[BLandroid/graphics/Rect;)I",
183                                                         (void*)SkNinePatchGlue::getTransparentRegion   }
184 };
185 
186 int register_android_graphics_NinePatch(JNIEnv* env);
register_android_graphics_NinePatch(JNIEnv * env)187 int register_android_graphics_NinePatch(JNIEnv* env)
188 {
189     return android::AndroidRuntime::registerNativeMethods(env,
190                                                        "android/graphics/NinePatch",
191                                                        gNinePatchMethods,
192                                                        SK_ARRAY_COUNT(gNinePatchMethods));
193 }
194