Home | History | Annotate | Download | only in graphics
      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 <android_runtime/AndroidRuntime.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 == NULL) {
    210         return NULL;
    211     }
    212 
    213     android::Parcel* p = android::parcelForJavaObject(env, parcel);
    214 
    215     SkRegion* region = new SkRegion;
    216     size_t size = p->readInt32();
    217     region->readFromMemory(p->readInplace(size), size);
    218 
    219     return reinterpret_cast<jlong>(region);
    220 }
    221 
    222 static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, jlong regionHandle, jobject parcel)
    223 {
    224     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
    225     if (parcel == NULL) {
    226         return JNI_FALSE;
    227     }
    228 
    229     android::Parcel* p = android::parcelForJavaObject(env, parcel);
    230 
    231     size_t size = region->writeToMemory(NULL);
    232     p->writeInt32(size);
    233     region->writeToMemory(p->writeInplace(size));
    234 
    235     return JNI_TRUE;
    236 }
    237 
    238 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    239 
    240 static jboolean Region_equals(JNIEnv* env, jobject clazz, jlong r1Handle, jlong r2Handle)
    241 {
    242     const SkRegion *r1 = reinterpret_cast<SkRegion*>(r1Handle);
    243     const SkRegion *r2 = reinterpret_cast<SkRegion*>(r2Handle);
    244     return boolTojboolean(*r1 == *r2);
    245 }
    246 
    247 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    248 
    249 struct RgnIterPair {
    250     SkRegion            fRgn;   // a copy of the caller's region
    251     SkRegion::Iterator  fIter;  // an iterator acting upon the copy (fRgn)
    252 
    253     RgnIterPair(const SkRegion& rgn) : fRgn(rgn) {
    254         // have our iterator reference our copy (fRgn), so we know it will be
    255         // unchanged for the lifetime of the iterator
    256         fIter.reset(fRgn);
    257     }
    258 };
    259 
    260 static jlong RegionIter_constructor(JNIEnv* env, jobject, jlong regionHandle)
    261 {
    262     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
    263     SkASSERT(region);
    264     return reinterpret_cast<jlong>(new RgnIterPair(*region));
    265 }
    266 
    267 static void RegionIter_destructor(JNIEnv* env, jobject, jlong pairHandle)
    268 {
    269     RgnIterPair* pair = reinterpret_cast<RgnIterPair*>(pairHandle);
    270     SkASSERT(pair);
    271     delete pair;
    272 }
    273 
    274 static jboolean RegionIter_next(JNIEnv* env, jobject, jlong pairHandle, jobject rectObject)
    275 {
    276     RgnIterPair* pair = reinterpret_cast<RgnIterPair*>(pairHandle);
    277     // the caller has checked that rectObject is not nul
    278     SkASSERT(pair);
    279     SkASSERT(rectObject);
    280 
    281     if (!pair->fIter.done()) {
    282         GraphicsJNI::irect_to_jrect(pair->fIter.rect(), env, rectObject);
    283         pair->fIter.next();
    284         return JNI_TRUE;
    285     }
    286     return JNI_FALSE;
    287 }
    288 
    289 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    290 
    291 static JNINativeMethod gRegionIterMethods[] = {
    292     { "nativeConstructor",  "(J)J",                         (void*)RegionIter_constructor   },
    293     { "nativeDestructor",   "(J)V",                         (void*)RegionIter_destructor    },
    294     { "nativeNext",         "(JLandroid/graphics/Rect;)Z",  (void*)RegionIter_next          }
    295 };
    296 
    297 static JNINativeMethod gRegionMethods[] = {
    298     // these are static methods
    299     { "nativeConstructor",      "()J",                              (void*)Region_constructor       },
    300     { "nativeDestructor",       "(J)V",                             (void*)Region_destructor        },
    301     { "nativeSetRegion",        "(JJ)V",                            (void*)Region_setRegion         },
    302     { "nativeSetRect",          "(JIIII)Z",                         (void*)Region_setRect           },
    303     { "nativeSetPath",          "(JJJ)Z",                           (void*)Region_setPath           },
    304     { "nativeGetBounds",        "(JLandroid/graphics/Rect;)Z",      (void*)Region_getBounds         },
    305     { "nativeGetBoundaryPath",  "(JJ)Z",                            (void*)Region_getBoundaryPath   },
    306     { "nativeOp",               "(JIIIII)Z",                        (void*)Region_op0               },
    307     { "nativeOp",               "(JLandroid/graphics/Rect;JI)Z",    (void*)Region_op1               },
    308     { "nativeOp",               "(JJJI)Z",                          (void*)Region_op2               },
    309     // these are methods that take the java region object
    310     { "isEmpty",                "()Z",                              (void*)Region_isEmpty           },
    311     { "isRect",                 "()Z",                              (void*)Region_isRect            },
    312     { "isComplex",              "()Z",                              (void*)Region_isComplex         },
    313     { "contains",               "(II)Z",                            (void*)Region_contains          },
    314     { "quickContains",          "(IIII)Z",                          (void*)Region_quickContains     },
    315     { "quickReject",            "(IIII)Z",                          (void*)Region_quickRejectIIII   },
    316     { "quickReject",            "(Landroid/graphics/Region;)Z",     (void*)Region_quickRejectRgn    },
    317     { "scale",                  "(FLandroid/graphics/Region;)V",    (void*)Region_scale             },
    318     { "translate",              "(IILandroid/graphics/Region;)V",   (void*)Region_translate         },
    319     { "nativeToString",         "(J)Ljava/lang/String;",            (void*)Region_toString          },
    320     // parceling methods
    321     { "nativeCreateFromParcel", "(Landroid/os/Parcel;)J",           (void*)Region_createFromParcel  },
    322     { "nativeWriteToParcel",    "(JLandroid/os/Parcel;)Z",          (void*)Region_writeToParcel     },
    323     { "nativeEquals",           "(JJ)Z",                            (void*)Region_equals            },
    324 };
    325 
    326 int register_android_graphics_Region(JNIEnv* env)
    327 {
    328     jclass clazz = env->FindClass("android/graphics/Region");
    329     SkASSERT(clazz);
    330 
    331     gRegion_nativeInstanceFieldID = env->GetFieldID(clazz, "mNativeRegion", "J");
    332     SkASSERT(gRegion_nativeInstanceFieldID);
    333 
    334     int result = android::AndroidRuntime::registerNativeMethods(env, "android/graphics/Region",
    335                                                              gRegionMethods, SK_ARRAY_COUNT(gRegionMethods));
    336     if (result < 0)
    337         return result;
    338 
    339     return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/RegionIterator",
    340                                                        gRegionIterMethods, SK_ARRAY_COUNT(gRegionIterMethods));
    341 }
    342 
    343 SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) {
    344     return GetSkRegion(env, regionObj);
    345 }
    346 
    347 } // namespace android
    348