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_util_Binder.h"
     23 
     24 #include <jni.h>
     25 #include <android_runtime/AndroidRuntime.h>
     26 
     27 namespace android {
     28 
     29 static jfieldID gRegion_nativeInstanceFieldID;
     30 
     31 static inline SkRegion* GetSkRegion(JNIEnv* env, jobject regionObject) {
     32     SkRegion* rgn = (SkRegion*)env->GetIntField(regionObject, gRegion_nativeInstanceFieldID);
     33     SkASSERT(rgn != NULL);
     34     return rgn;
     35 }
     36 
     37 static SkRegion* Region_constructor(JNIEnv* env, jobject) {
     38     return new SkRegion;
     39 }
     40 
     41 static void Region_destructor(JNIEnv* env, jobject, SkRegion* region) {
     42     SkASSERT(region);
     43     delete region;
     44 }
     45 
     46 static void Region_setRegion(JNIEnv* env, jobject, SkRegion* dst, const SkRegion* src) {
     47     SkASSERT(dst && src);
     48     *dst = *src;
     49 }
     50 
     51 static jboolean Region_setRect(JNIEnv* env, jobject, SkRegion* dst, int left, int top, int right, int bottom) {
     52     return dst->setRect(left, top, right, bottom);
     53 }
     54 
     55 static jboolean Region_setPath(JNIEnv* env, jobject, SkRegion* dst,
     56                                const SkPath* path, const SkRegion* clip) {
     57     SkASSERT(dst && path && clip);
     58     return dst->setPath(*path, *clip);
     59 }
     60 
     61 static jboolean Region_getBounds(JNIEnv* env, jobject, SkRegion* region, jobject rectBounds) {
     62     GraphicsJNI::irect_to_jrect(region->getBounds(), env, rectBounds);
     63     return !region->isEmpty();
     64 }
     65 
     66 static jboolean Region_getBoundaryPath(JNIEnv* env, jobject, const SkRegion* region, SkPath* path) {
     67     return region->getBoundaryPath(path);
     68 }
     69 
     70 static jboolean Region_op0(JNIEnv* env, jobject, SkRegion* dst, int left, int top, int right, int bottom, int op) {
     71     SkIRect ir;
     72 
     73     ir.set(left, top, right, bottom);
     74     return dst->op(ir, (SkRegion::Op)op);
     75 }
     76 
     77 static jboolean Region_op1(JNIEnv* env, jobject, SkRegion* dst, jobject rectObject, const SkRegion* region, int op) {
     78     SkIRect    ir;
     79     GraphicsJNI::jrect_to_irect(env, rectObject, &ir);
     80     return dst->op(ir, *region, (SkRegion::Op)op);
     81 }
     82 
     83 static jboolean Region_op2(JNIEnv* env, jobject, SkRegion* dst, const SkRegion* region1, const SkRegion* region2, int op) {
     84     return dst->op(*region1, *region2, (SkRegion::Op)op);
     85 }
     86 
     87 ////////////////////////////////////  These are methods, not static
     88 
     89 static jboolean Region_isEmpty(JNIEnv* env, jobject region) {
     90     return GetSkRegion(env, region)->isEmpty();
     91 }
     92 
     93 static jboolean Region_isRect(JNIEnv* env, jobject region) {
     94     return GetSkRegion(env, region)->isRect();
     95 }
     96 
     97 static jboolean Region_isComplex(JNIEnv* env, jobject region) {
     98     return GetSkRegion(env, region)->isComplex();
     99 }
    100 
    101 static jboolean Region_contains(JNIEnv* env, jobject region, int x, int y) {
    102     return GetSkRegion(env, region)->contains(x, y);
    103 }
    104 
    105 static jboolean Region_quickContains(JNIEnv* env, jobject region, int left, int top, int right, int bottom) {
    106     return GetSkRegion(env, region)->quickContains(left, top, right, bottom);
    107 }
    108 
    109 static jboolean Region_quickRejectIIII(JNIEnv* env, jobject region, int left, int top, int right, int bottom) {
    110     SkIRect ir;
    111     ir.set(left, top, right, bottom);
    112     return GetSkRegion(env, region)->quickReject(ir);
    113 }
    114 
    115 static jboolean Region_quickRejectRgn(JNIEnv* env, jobject region, jobject other) {
    116     return GetSkRegion(env, region)->quickReject(*GetSkRegion(env, other));
    117 }
    118 
    119 static void Region_translate(JNIEnv* env, jobject region, int x, int y, jobject dst) {
    120     SkRegion* rgn = GetSkRegion(env, region);
    121     if (dst)
    122         rgn->translate(x, y, GetSkRegion(env, dst));
    123     else
    124         rgn->translate(x, y);
    125 }
    126 
    127 // Scale the rectangle by given scale and set the reuslt to the dst.
    128 static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
    129    dst->fLeft = (int)::roundf(src.fLeft * scale);
    130    dst->fTop = (int)::roundf(src.fTop * scale);
    131    dst->fRight = (int)::roundf(src.fRight * scale);
    132    dst->fBottom = (int)::roundf(src.fBottom * scale);
    133 }
    134 
    135 // Scale the region by given scale and set the reuslt to the dst.
    136 // dest and src can be the same region instance.
    137 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
    138    SkRegion tmp;
    139    SkRegion::Iterator iter(src);
    140 
    141    for (; !iter.done(); iter.next()) {
    142        SkIRect r;
    143        scale_rect(&r, iter.rect(), scale);
    144        tmp.op(r, SkRegion::kUnion_Op);
    145    }
    146    dst->swap(tmp);
    147 }
    148 
    149 static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst) {
    150     SkRegion* rgn = GetSkRegion(env, region);
    151     if (dst)
    152         scale_rgn(GetSkRegion(env, dst), *rgn, scale);
    153     else
    154         scale_rgn(rgn, *rgn, scale);
    155 }
    156 
    157 static jstring Region_toString(JNIEnv* env, jobject clazz, SkRegion* region) {
    158     char* str = region->toString();
    159     if (str == NULL) {
    160         return NULL;
    161     }
    162     jstring result = env->NewStringUTF(str);
    163     free(str);
    164     return result;
    165 }
    166 
    167 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    168 
    169 static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
    170 {
    171     if (parcel == NULL) {
    172         return NULL;
    173     }
    174 
    175     android::Parcel* p = android::parcelForJavaObject(env, parcel);
    176 
    177     SkRegion* region = new SkRegion;
    178     size_t size = p->readInt32();
    179     region->unflatten(p->readInplace(size));
    180 
    181     return region;
    182 }
    183 
    184 static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, const SkRegion* region, jobject parcel)
    185 {
    186     if (parcel == NULL) {
    187         return false;
    188     }
    189 
    190     android::Parcel* p = android::parcelForJavaObject(env, parcel);
    191 
    192     size_t size = region->flatten(NULL);
    193     p->writeInt32(size);
    194     region->flatten(p->writeInplace(size));
    195 
    196     return true;
    197 }
    198 
    199 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    200 
    201 static jboolean Region_equals(JNIEnv* env, jobject clazz, const SkRegion *r1, const SkRegion* r2)
    202 {
    203   return (jboolean) (*r1 == *r2);
    204 }
    205 
    206 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    207 
    208 struct RgnIterPair {
    209     SkRegion            fRgn;   // a copy of the caller's region
    210     SkRegion::Iterator  fIter;  // an iterator acting upon the copy (fRgn)
    211 
    212     RgnIterPair(const SkRegion& rgn) : fRgn(rgn) {
    213         // have our iterator reference our copy (fRgn), so we know it will be
    214         // unchanged for the lifetime of the iterator
    215         fIter.reset(fRgn);
    216     }
    217 };
    218 
    219 static RgnIterPair* RegionIter_constructor(JNIEnv* env, jobject, const SkRegion* region)
    220 {
    221     SkASSERT(region);
    222     return new RgnIterPair(*region);
    223 }
    224 
    225 static void RegionIter_destructor(JNIEnv* env, jobject, RgnIterPair* pair)
    226 {
    227     SkASSERT(pair);
    228     delete pair;
    229 }
    230 
    231 static jboolean RegionIter_next(JNIEnv* env, jobject, RgnIterPair* pair, jobject rectObject)
    232 {
    233     // the caller has checked that rectObject is not nul
    234     SkASSERT(pair);
    235     SkASSERT(rectObject);
    236 
    237     if (!pair->fIter.done()) {
    238         GraphicsJNI::irect_to_jrect(pair->fIter.rect(), env, rectObject);
    239         pair->fIter.next();
    240         return true;
    241     }
    242     return false;
    243 }
    244 
    245 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
    246 
    247 static JNINativeMethod gRegionIterMethods[] = {
    248     { "nativeConstructor",  "(I)I",                         (void*)RegionIter_constructor   },
    249     { "nativeDestructor",   "(I)V",                         (void*)RegionIter_destructor    },
    250     { "nativeNext",         "(ILandroid/graphics/Rect;)Z",  (void*)RegionIter_next          }
    251 };
    252 
    253 static JNINativeMethod gRegionMethods[] = {
    254     // these are static methods
    255     { "nativeConstructor",      "()I",                              (void*)Region_constructor       },
    256     { "nativeDestructor",       "(I)V",                             (void*)Region_destructor        },
    257     { "nativeSetRegion",        "(II)Z",                            (void*)Region_setRegion         },
    258     { "nativeSetRect",          "(IIIII)Z",                         (void*)Region_setRect           },
    259     { "nativeSetPath",          "(III)Z",                           (void*)Region_setPath           },
    260     { "nativeGetBounds",        "(ILandroid/graphics/Rect;)Z",      (void*)Region_getBounds         },
    261     { "nativeGetBoundaryPath",  "(II)Z",                            (void*)Region_getBoundaryPath   },
    262     { "nativeOp",               "(IIIIII)Z",                        (void*)Region_op0               },
    263     { "nativeOp",               "(ILandroid/graphics/Rect;II)Z",    (void*)Region_op1               },
    264     { "nativeOp",               "(IIII)Z",                          (void*)Region_op2               },
    265     // these are methods that take the java region object
    266     { "isEmpty",                "()Z",                              (void*)Region_isEmpty           },
    267     { "isRect",                 "()Z",                              (void*)Region_isRect            },
    268     { "isComplex",              "()Z",                              (void*)Region_isComplex         },
    269     { "contains",               "(II)Z",                            (void*)Region_contains          },
    270     { "quickContains",          "(IIII)Z",                          (void*)Region_quickContains     },
    271     { "quickReject",            "(IIII)Z",                          (void*)Region_quickRejectIIII   },
    272     { "quickReject",            "(Landroid/graphics/Region;)Z",     (void*)Region_quickRejectRgn    },
    273     { "scale",                  "(FLandroid/graphics/Region;)V",    (void*)Region_scale             },
    274     { "translate",              "(IILandroid/graphics/Region;)V",   (void*)Region_translate         },
    275     { "nativeToString",         "(I)Ljava/lang/String;",            (void*)Region_toString          },
    276     // parceling methods
    277     { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I",           (void*)Region_createFromParcel  },
    278     { "nativeWriteToParcel",    "(ILandroid/os/Parcel;)Z",          (void*)Region_writeToParcel     },
    279     { "nativeEquals",           "(II)Z",                            (void*)Region_equals            },
    280 };
    281 
    282 int register_android_graphics_Region(JNIEnv* env)
    283 {
    284     jclass clazz = env->FindClass("android/graphics/Region");
    285     SkASSERT(clazz);
    286 
    287     gRegion_nativeInstanceFieldID = env->GetFieldID(clazz, "mNativeRegion", "I");
    288     SkASSERT(gRegion_nativeInstanceFieldID);
    289 
    290     int result = android::AndroidRuntime::registerNativeMethods(env, "android/graphics/Region",
    291                                                              gRegionMethods, SK_ARRAY_COUNT(gRegionMethods));
    292     if (result < 0)
    293         return result;
    294 
    295     return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/RegionIterator",
    296                                                        gRegionIterMethods, SK_ARRAY_COUNT(gRegionIterMethods));
    297 }
    298 
    299 SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) {
    300     return GetSkRegion(env, regionObj);
    301 }
    302 
    303 } // namespace android
    304