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