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 <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     explicit 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