1 /* 2 * Copyright (C) 2011 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 "SkRegion.h" 18 #include "SkPath.h" 19 #include "GraphicsJNI.h" 20 21 #include <binder/Parcel.h> 22 #include "android_os_Parcel.h" 23 #include "android_util_Binder.h" 24 25 #include <jni.h> 26 #include <core_jni_helpers.h> 27 28 namespace android { 29 30 static jfieldID gRegion_nativeInstanceFieldID; 31 32 static inline jboolean boolTojboolean(bool value) { 33 return value ? JNI_TRUE : JNI_FALSE; 34 } 35 36 static inline SkRegion* GetSkRegion(JNIEnv* env, jobject regionObject) { 37 jlong regionHandle = env->GetLongField(regionObject, gRegion_nativeInstanceFieldID); 38 SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); 39 SkASSERT(region != NULL); 40 return region; 41 } 42 43 static jlong Region_constructor(JNIEnv* env, jobject) { 44 return reinterpret_cast<jlong>(new SkRegion); 45 } 46 47 static void Region_destructor(JNIEnv* env, jobject, jlong regionHandle) { 48 SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); 49 SkASSERT(region); 50 delete region; 51 } 52 53 static void Region_setRegion(JNIEnv* env, jobject, jlong dstHandle, jlong srcHandle) { 54 SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); 55 const SkRegion* src = reinterpret_cast<SkRegion*>(srcHandle); 56 SkASSERT(dst && src); 57 *dst = *src; 58 } 59 60 static jboolean Region_setRect(JNIEnv* env, jobject, jlong dstHandle, jint left, jint top, jint right, jint bottom) { 61 SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); 62 bool result = dst->setRect(left, top, right, bottom); 63 return boolTojboolean(result); 64 } 65 66 static jboolean Region_setPath(JNIEnv* env, jobject, jlong dstHandle, 67 jlong pathHandle, jlong clipHandle) { 68 SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); 69 const SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 70 const SkRegion* clip = reinterpret_cast<SkRegion*>(clipHandle); 71 SkASSERT(dst && path && clip); 72 bool result = dst->setPath(*path, *clip); 73 return boolTojboolean(result); 74 75 } 76 77 static jboolean Region_getBounds(JNIEnv* env, jobject, jlong regionHandle, jobject rectBounds) { 78 SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); 79 GraphicsJNI::irect_to_jrect(region->getBounds(), env, rectBounds); 80 bool result = !region->isEmpty(); 81 return boolTojboolean(result); 82 } 83 84 static jboolean Region_getBoundaryPath(JNIEnv* env, jobject, jlong regionHandle, jlong pathHandle) { 85 const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); 86 SkPath* path = reinterpret_cast<SkPath*>(pathHandle); 87 bool result = region->getBoundaryPath(path); 88 return boolTojboolean(result); 89 } 90 91 static jboolean Region_op0(JNIEnv* env, jobject, jlong dstHandle, jint left, jint top, jint right, jint bottom, jint op) { 92 SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); 93 SkIRect ir; 94 95 ir.set(left, top, right, bottom); 96 bool result = dst->op(ir, (SkRegion::Op)op); 97 return boolTojboolean(result); 98 } 99 100 static jboolean Region_op1(JNIEnv* env, jobject, jlong dstHandle, jobject rectObject, jlong regionHandle, jint op) { 101 SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); 102 const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); 103 SkIRect ir; 104 GraphicsJNI::jrect_to_irect(env, rectObject, &ir); 105 bool result = dst->op(ir, *region, (SkRegion::Op)op); 106 return boolTojboolean(result); 107 } 108 109 static jboolean Region_op2(JNIEnv* env, jobject, jlong dstHandle, jlong region1Handle, jlong region2Handle, jint op) { 110 SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); 111 const SkRegion* region1 = reinterpret_cast<SkRegion*>(region1Handle); 112 const SkRegion* region2 = reinterpret_cast<SkRegion*>(region2Handle); 113 bool result = dst->op(*region1, *region2, (SkRegion::Op)op); 114 return boolTojboolean(result); 115 } 116 117 //////////////////////////////////// These are methods, not static 118 119 static jboolean Region_isEmpty(JNIEnv* env, jobject region) { 120 bool result = GetSkRegion(env, region)->isEmpty(); 121 return boolTojboolean(result); 122 } 123 124 static jboolean Region_isRect(JNIEnv* env, jobject region) { 125 bool result = GetSkRegion(env, region)->isRect(); 126 return boolTojboolean(result); 127 } 128 129 static jboolean Region_isComplex(JNIEnv* env, jobject region) { 130 bool result = GetSkRegion(env, region)->isComplex(); 131 return boolTojboolean(result); 132 } 133 134 static jboolean Region_contains(JNIEnv* env, jobject region, jint x, jint y) { 135 bool result = GetSkRegion(env, region)->contains(x, y); 136 return boolTojboolean(result); 137 } 138 139 static jboolean Region_quickContains(JNIEnv* env, jobject region, jint left, jint top, jint right, jint bottom) { 140 bool result = GetSkRegion(env, region)->quickContains(left, top, right, bottom); 141 return boolTojboolean(result); 142 } 143 144 static jboolean Region_quickRejectIIII(JNIEnv* env, jobject region, jint left, jint top, jint right, jint bottom) { 145 SkIRect ir; 146 ir.set(left, top, right, bottom); 147 bool result = GetSkRegion(env, region)->quickReject(ir); 148 return boolTojboolean(result); 149 } 150 151 static jboolean Region_quickRejectRgn(JNIEnv* env, jobject region, jobject other) { 152 bool result = GetSkRegion(env, region)->quickReject(*GetSkRegion(env, other)); 153 return boolTojboolean(result); 154 } 155 156 static void Region_translate(JNIEnv* env, jobject region, jint x, jint y, jobject dst) { 157 SkRegion* rgn = GetSkRegion(env, region); 158 if (dst) 159 rgn->translate(x, y, GetSkRegion(env, dst)); 160 else 161 rgn->translate(x, y); 162 } 163 164 // Scale the rectangle by given scale and set the reuslt to the dst. 165 static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) { 166 dst->fLeft = (int)::roundf(src.fLeft * scale); 167 dst->fTop = (int)::roundf(src.fTop * scale); 168 dst->fRight = (int)::roundf(src.fRight * scale); 169 dst->fBottom = (int)::roundf(src.fBottom * scale); 170 } 171 172 // Scale the region by given scale and set the reuslt to the dst. 173 // dest and src can be the same region instance. 174 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) { 175 SkRegion tmp; 176 SkRegion::Iterator iter(src); 177 178 for (; !iter.done(); iter.next()) { 179 SkIRect r; 180 scale_rect(&r, iter.rect(), scale); 181 tmp.op(r, SkRegion::kUnion_Op); 182 } 183 dst->swap(tmp); 184 } 185 186 static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst) { 187 SkRegion* rgn = GetSkRegion(env, region); 188 if (dst) 189 scale_rgn(GetSkRegion(env, dst), *rgn, scale); 190 else 191 scale_rgn(rgn, *rgn, scale); 192 } 193 194 static jstring Region_toString(JNIEnv* env, jobject clazz, jlong regionHandle) { 195 SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); 196 char* str = region->toString(); 197 if (str == NULL) { 198 return NULL; 199 } 200 jstring result = env->NewStringUTF(str); 201 free(str); 202 return result; 203 } 204 205 //////////////////////////////////////////////////////////////////////////////////////////////////////////// 206 207 static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel) 208 { 209 if (parcel == nullptr) { 210 return 0; 211 } 212 213 android::Parcel* p = android::parcelForJavaObject(env, parcel); 214 215 std::vector<int32_t> rects; 216 p->readInt32Vector(&rects); 217 218 if ((rects.size() % 4) != 0) { 219 return 0; 220 } 221 222 SkRegion* region = new SkRegion; 223 for (size_t x = 0; x + 4 <= rects.size(); x += 4) { 224 region->op(rects[x], rects[x+1], rects[x+2], rects[x+3], SkRegion::kUnion_Op); 225 } 226 227 return reinterpret_cast<jlong>(region); 228 } 229 230 static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, jlong regionHandle, jobject parcel) 231 { 232 const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); 233 if (parcel == nullptr) { 234 return JNI_FALSE; 235 } 236 237 android::Parcel* p = android::parcelForJavaObject(env, parcel); 238 239 std::vector<int32_t> rects; 240 SkRegion::Iterator it(*region); 241 while (!it.done()) { 242 const SkIRect& r = it.rect(); 243 rects.push_back(r.fLeft); 244 rects.push_back(r.fTop); 245 rects.push_back(r.fRight); 246 rects.push_back(r.fBottom); 247 it.next(); 248 } 249 250 p->writeInt32Vector(rects); 251 return JNI_TRUE; 252 } 253 254 //////////////////////////////////////////////////////////////////////////////////////////////////////////// 255 256 static jboolean Region_equals(JNIEnv* env, jobject clazz, jlong r1Handle, jlong r2Handle) 257 { 258 const SkRegion *r1 = reinterpret_cast<SkRegion*>(r1Handle); 259 const SkRegion *r2 = reinterpret_cast<SkRegion*>(r2Handle); 260 return boolTojboolean(*r1 == *r2); 261 } 262 263 //////////////////////////////////////////////////////////////////////////////////////////////////////////// 264 265 struct RgnIterPair { 266 SkRegion fRgn; // a copy of the caller's region 267 SkRegion::Iterator fIter; // an iterator acting upon the copy (fRgn) 268 269 RgnIterPair(const SkRegion& rgn) : fRgn(rgn) { 270 // have our iterator reference our copy (fRgn), so we know it will be 271 // unchanged for the lifetime of the iterator 272 fIter.reset(fRgn); 273 } 274 }; 275 276 static jlong RegionIter_constructor(JNIEnv* env, jobject, jlong regionHandle) 277 { 278 const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); 279 SkASSERT(region); 280 return reinterpret_cast<jlong>(new RgnIterPair(*region)); 281 } 282 283 static void RegionIter_destructor(JNIEnv* env, jobject, jlong pairHandle) 284 { 285 RgnIterPair* pair = reinterpret_cast<RgnIterPair*>(pairHandle); 286 SkASSERT(pair); 287 delete pair; 288 } 289 290 static jboolean RegionIter_next(JNIEnv* env, jobject, jlong pairHandle, jobject rectObject) 291 { 292 RgnIterPair* pair = reinterpret_cast<RgnIterPair*>(pairHandle); 293 // the caller has checked that rectObject is not nul 294 SkASSERT(pair); 295 SkASSERT(rectObject); 296 297 if (!pair->fIter.done()) { 298 GraphicsJNI::irect_to_jrect(pair->fIter.rect(), env, rectObject); 299 pair->fIter.next(); 300 return JNI_TRUE; 301 } 302 return JNI_FALSE; 303 } 304 305 //////////////////////////////////////////////////////////////////////////////////////////////////////////// 306 307 static const JNINativeMethod gRegionIterMethods[] = { 308 { "nativeConstructor", "(J)J", (void*)RegionIter_constructor }, 309 { "nativeDestructor", "(J)V", (void*)RegionIter_destructor }, 310 { "nativeNext", "(JLandroid/graphics/Rect;)Z", (void*)RegionIter_next } 311 }; 312 313 static const JNINativeMethod gRegionMethods[] = { 314 // these are static methods 315 { "nativeConstructor", "()J", (void*)Region_constructor }, 316 { "nativeDestructor", "(J)V", (void*)Region_destructor }, 317 { "nativeSetRegion", "(JJ)V", (void*)Region_setRegion }, 318 { "nativeSetRect", "(JIIII)Z", (void*)Region_setRect }, 319 { "nativeSetPath", "(JJJ)Z", (void*)Region_setPath }, 320 { "nativeGetBounds", "(JLandroid/graphics/Rect;)Z", (void*)Region_getBounds }, 321 { "nativeGetBoundaryPath", "(JJ)Z", (void*)Region_getBoundaryPath }, 322 { "nativeOp", "(JIIIII)Z", (void*)Region_op0 }, 323 { "nativeOp", "(JLandroid/graphics/Rect;JI)Z", (void*)Region_op1 }, 324 { "nativeOp", "(JJJI)Z", (void*)Region_op2 }, 325 // these are methods that take the java region object 326 { "isEmpty", "()Z", (void*)Region_isEmpty }, 327 { "isRect", "()Z", (void*)Region_isRect }, 328 { "isComplex", "()Z", (void*)Region_isComplex }, 329 { "contains", "(II)Z", (void*)Region_contains }, 330 { "quickContains", "(IIII)Z", (void*)Region_quickContains }, 331 { "quickReject", "(IIII)Z", (void*)Region_quickRejectIIII }, 332 { "quickReject", "(Landroid/graphics/Region;)Z", (void*)Region_quickRejectRgn }, 333 { "scale", "(FLandroid/graphics/Region;)V", (void*)Region_scale }, 334 { "translate", "(IILandroid/graphics/Region;)V", (void*)Region_translate }, 335 { "nativeToString", "(J)Ljava/lang/String;", (void*)Region_toString }, 336 // parceling methods 337 { "nativeCreateFromParcel", "(Landroid/os/Parcel;)J", (void*)Region_createFromParcel }, 338 { "nativeWriteToParcel", "(JLandroid/os/Parcel;)Z", (void*)Region_writeToParcel }, 339 { "nativeEquals", "(JJ)Z", (void*)Region_equals }, 340 }; 341 342 int register_android_graphics_Region(JNIEnv* env) 343 { 344 jclass clazz = FindClassOrDie(env, "android/graphics/Region"); 345 346 gRegion_nativeInstanceFieldID = GetFieldIDOrDie(env, clazz, "mNativeRegion", "J"); 347 348 RegisterMethodsOrDie(env, "android/graphics/Region", gRegionMethods, NELEM(gRegionMethods)); 349 return RegisterMethodsOrDie(env, "android/graphics/RegionIterator", gRegionIterMethods, 350 NELEM(gRegionIterMethods)); 351 } 352 353 SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) { 354 return GetSkRegion(env, regionObj); 355 } 356 357 } // namespace android 358