1 /*
   2  * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <JNIUtil.h>
  27 
  28 #include <JAbstractSurface.h>
  29 #include <JPiscesRenderer.h>
  30 #include <JTransform.h>
  31 
  32 #include <PiscesBlit.h>
  33 #include <PiscesSysutils.h>
  34 
  35 #include <PiscesRenderer.inl>
  36 
  37 #define RENDERER_NATIVE_PTR 0
  38 #define RENDERER_SURFACE 1
  39 #define RENDERER_LAST RENDERER_SURFACE
  40 
  41 #define SURFACE_FROM_RENDERER(surface, env, surfaceHandle, rendererHandle)     \
  42         (surfaceHandle) = (*(env))->GetObjectField((env), (rendererHandle),    \
  43                                                    fieldIds[RENDERER_SURFACE]  \
  44                                                    );                          \
  45         (surface) = &surface_get((env), (surfaceHandle))->super;
  46 
  47 static jfieldID fieldIds[RENDERER_LAST + 1];
  48 static jboolean fieldIdsInitialized = JNI_FALSE;
  49 static jboolean initializeRendererFieldIds(JNIEnv *env, jobject objectHandle);
  50 
  51 static int toPiscesCoords(unsigned int ff);
  52 static void renderer_finalize(JNIEnv *env, jobject objectHandle);
  53 static void fillAlphaMask(Renderer* rdr, jint minX, jint minY, jint maxX, jint maxY,
  54     JNIEnv *env, jobject this, jint maskType, jbyteArray jmask, jint x, jint y,
  55     jint maskWidth, jint maskHeight, jint offset, jint stride);
  56 
  57 JNIEXPORT void JNICALL
  58 Java_com_sun_pisces_PiscesRenderer_initialize(JNIEnv* env, jobject objectHandle)
  59 {
  60     Renderer* rdr;
  61     Surface* surface;
  62     jboolean sfieldsOK;
  63 
  64     sfieldsOK = initializeRendererFieldIds(env, objectHandle);
  65     if (sfieldsOK) {
  66         jobject surfaceHandle = (*env)->GetObjectField(env, objectHandle,
  67                                 fieldIds[RENDERER_SURFACE]);
  68         surface = &surface_get(env, surfaceHandle)->super;
  69 
  70         rdr = renderer_create(surface);
  71 
  72         (*env)->SetLongField(env, objectHandle, fieldIds[RENDERER_NATIVE_PTR],
  73                              PointerToJLong(rdr));
  74         if (JNI_TRUE == readAndClearMemErrorFlag()) {
  75             JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
  76                          "Allocation of internal renderer buffer failed!!!");
  77         }
  78 
  79     } else {
  80         JNI_ThrowNew(env, "java/lang/IllegalStateException", "");
  81     }
  82 }
  83 
  84 JNIEXPORT void JNICALL
  85 Java_com_sun_pisces_PiscesRenderer_nativeFinalize(JNIEnv* env,
  86                                                   jobject objectHandle)
  87 {
  88     renderer_finalize(env, objectHandle);
  89 
  90     if (JNI_TRUE == readAndClearMemErrorFlag()) {
  91         JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
  92                      "Allocation of internal renderer buffer failed.");
  93     }
  94 }
  95 
  96 JNIEXPORT void JNICALL
  97 Java_com_sun_pisces_PiscesRenderer_setClipImpl(JNIEnv* env, jobject objectHandle,
  98         jint minX, jint minY, jint width, jint height) {
  99     Renderer* rdr;
 100     rdr = (Renderer*)JLongToPointer(
 101               (*env)->GetLongField(env, objectHandle,
 102                                    fieldIds[RENDERER_NATIVE_PTR]));
 103 
 104     renderer_setClip(rdr, minX, minY, width, height);
 105 
 106     if (JNI_TRUE == readAndClearMemErrorFlag()) {
 107         JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 108                      "Allocation of internal renderer buffer failed.");
 109     }
 110 }
 111 
 112 JNIEXPORT void JNICALL
 113 Java_com_sun_pisces_PiscesRenderer_setColorImpl(JNIEnv* env, jobject objectHandle,
 114         jint red, jint green, jint blue, jint alpha) {
 115     Renderer* rdr;
 116     rdr = (Renderer*)JLongToPointer(
 117               (*env)->GetLongField(env, objectHandle,
 118                                    fieldIds[RENDERER_NATIVE_PTR]));
 119 
 120     renderer_setColor(rdr, red, green, blue, alpha);
 121 
 122     if (JNI_TRUE == readAndClearMemErrorFlag()) {
 123         JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 124                      "Allocation of internal renderer buffer failed.");
 125     }
 126 }
 127 
 128 JNIEXPORT void JNICALL
 129 Java_com_sun_pisces_PiscesRenderer_setCompositeRuleImpl(JNIEnv* env,
 130     jobject objectHandle,
 131     jint compositeRule)
 132 {
 133     Renderer* rdr;
 134     rdr = (Renderer*)JLongToPointer(
 135               (*env)->GetLongField(env, objectHandle,
 136                                    fieldIds[RENDERER_NATIVE_PTR]));
 137 
 138     renderer_setCompositeRule(rdr, compositeRule);
 139 
 140     if (JNI_TRUE == readAndClearMemErrorFlag()) {
 141         JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 142                      "Allocation of internal renderer buffer failed.");
 143     }
 144 }
 145 
 146 JNIEXPORT void JNICALL Java_com_sun_pisces_PiscesRenderer_clearRectImpl(JNIEnv* env, jobject objectHandle,
 147         jint x, jint y, jint w, jint h) {
 148     Renderer* rdr;
 149     Surface* surface;
 150     jobject surfaceHandle;
 151 
 152     rdr = (Renderer*)JLongToPointer(
 153              (*env)->GetLongField(env, objectHandle,
 154                                    fieldIds[RENDERER_NATIVE_PTR]));
 155 
 156     SURFACE_FROM_RENDERER(surface, env, surfaceHandle, objectHandle);
 157     ACQUIRE_SURFACE(surface, env, surfaceHandle);
 158     INVALIDATE_RENDERER_SURFACE(rdr);
 159 
 160     rdr->_imagePixelStride = 1;
 161     rdr->_imageScanlineStride = surface->width;
 162     renderer_clearRect(rdr, x, y, w, h);
 163 
 164     RELEASE_SURFACE(surface, env, surfaceHandle);
 165 
 166     if (JNI_TRUE == readAndClearMemErrorFlag()) {
 167         JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 168                      "Allocation of internal renderer buffer failed.");
 169     }
 170 }
 171 
 172 /*
 173  * Class:     com_sun_pisces_PiscesRenderer
 174  * Method:    setLinearGradientImpl
 175  * Signature: (IIII[IILcom/sun/pisces/Transform6;)V
 176  */
 177 JNIEXPORT void JNICALL Java_com_sun_pisces_PiscesRenderer_setLinearGradientImpl(
 178     JNIEnv *env, jobject this, jint x0, jint y0, jint x1, jint y1,
 179     jintArray jramp, jint cycleMethod, jobject jTransform)
 180 {
 181     Renderer* rdr;
 182     Transform6 gradientTransform;
 183     jint *ramp;
 184 
 185     transform_get6(&gradientTransform, env, jTransform);
 186 
 187     rdr = (Renderer*)JLongToPointer((*env)->GetLongField(env, this,
 188                                     fieldIds[RENDERER_NATIVE_PTR]));
 189 
 190     ramp = (*env)->GetIntArrayElements(env, jramp, NULL);
 191     if (ramp != NULL) {
 192         rdr->_gradient_cycleMethod = cycleMethod;
 193         renderer_setLinearGradient(rdr, x0, y0, x1, y1,
 194                                    ramp, &gradientTransform);
 195         (*env)->ReleaseIntArrayElements(env, jramp, ramp, 0);
 196     } else {
 197         setMemErrorFlag();
 198     }
 199 
 200     if (JNI_TRUE == readAndClearMemErrorFlag()) {
 201         JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 202                      "Allocation of internal renderer buffer failed.");
 203     }
 204 }
 205 
 206 /*
 207  * Class:     com_sun_pisces_PiscesRenderer
 208  * Method:    setRadialGradientImpl
 209  * Signature: (IIIII[IILcom/sun/pisces/Transform6;)V
 210  */
 211 JNIEXPORT void JNICALL Java_com_sun_pisces_PiscesRenderer_setRadialGradientImpl(
 212     JNIEnv *env, jobject this, jint cx, jint cy, jint fx, jint fy, jint radius,
 213     jintArray jramp, jint cycleMethod, jobject jTransform)
 214 {
 215     Renderer* rdr;
 216     Transform6 gradientTransform;
 217 
 218     jint *ramp;
 219 
 220     transform_get6(&gradientTransform, env, jTransform);
 221 
 222     rdr = (Renderer*)JLongToPointer((*env)->GetLongField(env, this,
 223                                     fieldIds[RENDERER_NATIVE_PTR]));
 224 
 225     ramp = (*env)->GetIntArrayElements(env, jramp, NULL);
 226     if (ramp != NULL) {
 227         rdr->_gradient_cycleMethod = cycleMethod;
 228         renderer_setRadialGradient(rdr, cx, cy, fx, fy, radius,
 229                                    ramp, &gradientTransform);
 230         (*env)->ReleaseIntArrayElements(env, jramp, ramp, 0);
 231     } else {
 232         setMemErrorFlag();
 233     }
 234 
 235     if (JNI_TRUE == readAndClearMemErrorFlag()) {
 236         JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 237                      "Allocation of internal renderer buffer failed.");
 238     }
 239 }
 240 
 241 /*
 242  * Class:     com_sun_pisces_PiscesRenderer
 243  * Method:    setTextureImpl
 244  * Signature: (I[IIILcom/sun/pisces/Transform6;Z)V
 245  */
 246 JNIEXPORT void JNICALL Java_com_sun_pisces_PiscesRenderer_setTextureImpl
 247   (JNIEnv *env, jobject this, jint imageType, jintArray dataArray,
 248       jint width, jint height, jint stride,
 249       jobject jTransform, jboolean repeat, jboolean linearFiltering, jboolean hasAlpha)
 250 {
 251     Renderer* rdr;
 252     Transform6 textureTransform;
 253     jint *data;
 254 
 255     transform_get6(&textureTransform, env, jTransform);
 256 
 257     rdr = (Renderer*)JLongToPointer((*env)->GetLongField(env, this, fieldIds[RENDERER_NATIVE_PTR]));
 258 
 259     data = (jint*)(*env)->GetPrimitiveArrayCritical(env, dataArray, NULL);
 260     if (data != NULL) {
 261         jint *alloc_data = my_malloc(jint, width * height);
 262         if (alloc_data != NULL) {
 263             if (stride == width) {
 264                 memcpy(alloc_data, data, sizeof(jint) * width * height);
 265             } else {
 266                 jint i;
 267                 for (i = 0; i < height; i++) {
 268                     memcpy(alloc_data + (i*width), data + (i*stride), sizeof(jint) * width);
 269                 }
 270             }
 271             renderer_setTexture(rdr, IMAGE_MODE_NORMAL,
 272                 alloc_data, width, height, width, repeat, linearFiltering,
 273                 &textureTransform, JNI_TRUE, hasAlpha,
 274                 0, 0, width-1, height-1);
 275         } else {
 276             setMemErrorFlag();
 277         }
 278         (*env)->ReleasePrimitiveArrayCritical(env, dataArray, data, 0);
 279     } else {
 280         setMemErrorFlag();
 281     }
 282 
 283     if (JNI_TRUE == readAndClearMemErrorFlag()) {
 284         JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 285             "Allocation of internal renderer buffer failed.");
 286     }
 287 }
 288 
 289 Renderer*
 290 renderer_get(JNIEnv* env, jobject objectHandle) {
 291     return (Renderer*)JLongToPointer(
 292                 (*env)->GetLongField(env, objectHandle,
 293                                      fieldIds[RENDERER_NATIVE_PTR]));
 294 }
 295 
 296 static void
 297 renderer_finalize(JNIEnv *env, jobject objectHandle) {
 298     Renderer* rdr;
 299 
 300     if (!fieldIdsInitialized) {
 301         return;
 302     }
 303 
 304     rdr = (Renderer*)JLongToPointer((*env)->GetLongField(env, objectHandle,
 305                                     fieldIds[RENDERER_NATIVE_PTR]));
 306 
 307     if (rdr != (Renderer*)0) {
 308         renderer_dispose(rdr);
 309         (*env)->SetLongField(env, objectHandle, fieldIds[RENDERER_NATIVE_PTR],
 310                          (jlong)0);
 311     }
 312 }
 313 
 314 static jboolean
 315 initializeObjectFieldIds(JNIEnv *env,
 316     jobject objectHandle,
 317     const char * className,
 318     FieldDesc * fieldDesc,
 319     jfieldID * fieldIds,
 320     jboolean * initializedField)
 321 {
 322     jboolean retVal;
 323     jclass classHandle;
 324 
 325     if (*initializedField) {
 326         return JNI_TRUE;
 327     }
 328 
 329     retVal = JNI_FALSE;
 330 
 331     if (objectHandle != 0) {
 332         classHandle = (*env)->GetObjectClass(env, objectHandle);
 333     } else if (className != 0) {
 334         classHandle = (*env)->FindClass(env, className);
 335         if (checkAndClearException(env)) return JNI_FALSE;
 336     } else {
 337         return JNI_FALSE;
 338     }
 339 
 340     if (initializeFieldIds(fieldIds, env, classHandle, fieldDesc)) {
 341         retVal = JNI_TRUE;
 342         *initializedField = JNI_TRUE;
 343     }
 344 
 345     return retVal;
 346 }
 347 
 348 static jboolean
 349 initializeRendererFieldIds(JNIEnv *env, jobject objectHandle) {
 350     static FieldDesc rendererFieldDesc[] = {
 351                 { "nativePtr", "J" },
 352                 { "surface", "Lcom/sun/pisces/AbstractSurface;" },
 353                 { NULL, NULL }
 354             };
 355 
 356     return initializeObjectFieldIds(env, objectHandle, 0, rendererFieldDesc,
 357         fieldIds, &fieldIdsInitialized);
 358 }
 359 
 360 /**
 361  * Converts floating point number into S15.16 format
 362  * [= (int)(f * 65536.0f)]. Doesn't correctly handle INF, NaN and -0.
 363  *
 364  * @param ff number encoded as sign [1 bit], exponent + 127 [8 bits], mantisa
 365  *           without the implicit 1 at the beginning [23 bits]
 366  * @return ff in S15.16 format
 367  */
 368 static int
 369 toPiscesCoords(unsigned int ff) {
 370     int shift;
 371     unsigned int gg;
 372 
 373     /* get mantisa */
 374     gg = ((ff & 0xffffff) | 0x800000);
 375     /* calculate shift from exponent */
 376     shift = 134 - ((ff >> 23) & 0xff);
 377     /* do left or right shift to get value to S15.16 format */
 378     gg = (shift < 0) ? (gg << -shift) : (gg >> shift);
 379     /* fix sign */
 380     gg = (gg ^ -(int)(ff >> 31)) + (ff >> 31);
 381     /* handle zero */
 382     gg &= -(ff != 0);
 383 
 384     return (int)gg;
 385 }
 386 
 387 static void
 388 fillRect(JNIEnv *env, jobject this, Renderer* rdr,
 389     jint x, jint y, jint w, jint h,
 390     jint lEdge, jint rEdge, jint tEdge, jint bEdge)
 391 {
 392     Surface* surface;
 393     jobject surfaceHandle;
 394     jint x_from, x_to, y_from, y_to;
 395     jint lfrac, rfrac, tfrac, bfrac;
 396     jint rows_to_render_by_loop, rows_being_rendered;
 397 
 398     lfrac = (0x10000 - (x & 0xFFFF)) & 0xFFFF;
 399     rfrac = (x + w) & 0xFFFF;
 400     tfrac = (0x10000 - (y & 0xFFFF)) & 0xFFFF;
 401     bfrac = (y + h) & 0xFFFF;
 402 
 403     x_from = x >> 16;
 404     x_to = x + w;
 405     x_to = (rfrac) ? x_to >> 16 : (x_to >> 16) - 1;
 406     y_from = y >> 16;
 407     y_to = y + h;
 408     y_to = (bfrac) ? y_to >> 16 : (y_to >> 16) - 1;
 409 
 410     rdr->_rectX = x_from;
 411     rdr->_rectY = y_from;
 412 
 413     switch (lEdge) {
 414     case IMAGE_FRAC_EDGE_PAD:
 415         lfrac = 0;
 416         break;
 417     case IMAGE_FRAC_EDGE_TRIM:
 418         if (lfrac) { x_from++; }
 419         lfrac = 0;
 420         break;
 421     }
 422 
 423     switch (rEdge) {
 424     case IMAGE_FRAC_EDGE_PAD:
 425         rfrac = 0;
 426         break;
 427     case IMAGE_FRAC_EDGE_TRIM:
 428         if (rfrac) { x_to--; }
 429         rfrac = 0;
 430         break;
 431     }
 432 
 433     switch (tEdge) {
 434     case IMAGE_FRAC_EDGE_PAD:
 435         tfrac = 0;
 436         break;
 437     case IMAGE_FRAC_EDGE_TRIM:
 438         if (tfrac) { y_from++; }
 439         tfrac = 0;
 440         break;
 441     }
 442 
 443     switch (bEdge) {
 444     case IMAGE_FRAC_EDGE_PAD:
 445         bfrac = 0;
 446         break;
 447     case IMAGE_FRAC_EDGE_TRIM:
 448         if (bfrac) { y_to--; }
 449         bfrac = 0;
 450         break;
 451     }
 452 
 453     // apply clip
 454     if (x_from < rdr->_clip_bbMinX) {
 455         x_from = rdr->_clip_bbMinX;
 456         lfrac = 0;
 457     }
 458     if (y_from < rdr->_clip_bbMinY) {
 459         y_from = rdr->_clip_bbMinY;
 460         tfrac = 0;
 461     }
 462     if (x_to > rdr->_clip_bbMaxX) {
 463         x_to = rdr->_clip_bbMaxX;
 464         rfrac = 0;
 465     }
 466     if (y_to > rdr->_clip_bbMaxY) {
 467         y_to = rdr->_clip_bbMaxY;
 468         bfrac = 0;
 469     }
 470 
 471     if ((x_from <= x_to) && (y_from <= y_to)) {
 472         rows_to_render_by_loop = y_to - y_from + 1;
 473 
 474         SURFACE_FROM_RENDERER(surface, env, surfaceHandle, this);
 475         ACQUIRE_SURFACE(surface, env, surfaceHandle);
 476         INVALIDATE_RENDERER_SURFACE(rdr);
 477         VALIDATE_BLITTING(rdr);
 478 
 479         rdr->_minTouched = x_from;
 480         rdr->_maxTouched = x_to;
 481         rdr->_currX = x_from;
 482         rdr->_currY = y_from;
 483 
 484         rdr->_alphaWidth = x_to - x_from + 1;
 485 
 486         rdr->_currImageOffset = y_from * surface->width;
 487         rdr->_imageScanlineStride = surface->width;
 488         rdr->_imagePixelStride = 1;
 489         rdr->_rowNum = 0;
 490 
 491         if (y_from == y_to && (tfrac | bfrac)) {
 492             // rendering single horizontal fractional line bfrac > (y & 0xFFFF)
 493             tfrac = (bfrac - 0x10000 + tfrac) & 0xFFFF;
 494             bfrac = 0;
 495         }
 496         if (x_from == x_to && (lfrac | rfrac)) {
 497             // rendering single vertival fractional line rfrac > (x & 0xFFFF)
 498             lfrac = (rfrac - 0x10000 + lfrac) & 0xFFFF;
 499             rfrac = 0;
 500         }
 501 
 502         rdr->_el_lfrac = lfrac;
 503         rdr->_el_rfrac = rfrac;
 504 
 505         if (bfrac) {
 506             // one "full" line less -> will be rendered at the end
 507             rows_to_render_by_loop--;
 508         }
 509 
 510         // emit fractional top line
 511         if (tfrac) {
 512             if (rdr->_genPaint) {
 513                 size_t l = (x_to - x_from + 1);
 514                 ALLOC3(rdr->_paint, jint, l);
 515                 rdr->_genPaint(rdr, 1);
 516             }
 517             rdr->_emitLine(rdr, 1, tfrac);
 518             rows_to_render_by_loop--;
 519             rdr->_currX = x_from;
 520             rdr->_currY++;
 521             rdr->_currImageOffset = rdr->_currY * surface->width;
 522             rdr->_rowNum++;
 523         }
 524 
 525         // emit "full" lines that are in the middle
 526         while (rows_to_render_by_loop > 0) {
 527             rows_being_rendered = MIN(rows_to_render_by_loop, NUM_ALPHA_ROWS);
 528 
 529             if (rdr->_genPaint) {
 530                 size_t l = (x_to - x_from + 1) * rows_being_rendered;
 531                 ALLOC3(rdr->_paint, jint, l);
 532                 rdr->_genPaint(rdr, rows_being_rendered);
 533             }
 534             rdr->_emitLine(rdr, rows_being_rendered, 0x10000);
 535 
 536             rows_to_render_by_loop -= rows_being_rendered;
 537             rdr->_currX = x_from;
 538             rdr->_currY += rows_being_rendered;
 539             rdr->_currImageOffset = rdr->_currY * surface->width;
 540             rdr->_rowNum += rows_being_rendered;
 541         }
 542 
 543         // emit fractional bottom line
 544         if (bfrac) {
 545             if (rdr->_genPaint) {
 546                 size_t l = (x_to - x_from + 1);
 547                 ALLOC3(rdr->_paint, jint, l);
 548                 rdr->_genPaint(rdr, 1);
 549             }
 550             rdr->_emitLine(rdr, 1, bfrac);
 551         }
 552         RELEASE_SURFACE(surface, env, surfaceHandle);
 553 
 554         if (JNI_TRUE == readAndClearMemErrorFlag()) {
 555             JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 556                 "Allocation of internal renderer buffer failed.");
 557         }
 558     }
 559 }
 560 
 561 /*
 562  * Class:     com_sun_pisces_PiscesRenderer
 563  * Method:    fillRect
 564  * Signature: (IIII)V
 565  * x, y, w, h are already transformed (is surface coordinates)
 566  * and rectangle is in an up-right position ie. no rotate or shear
 567  */
 568 JNIEXPORT void JNICALL Java_com_sun_pisces_PiscesRenderer_fillRectImpl
 569   (JNIEnv *env, jobject this, jint x, jint y, jint w, jint h)
 570 {
 571     Renderer* rdr;
 572     rdr = (Renderer*)JLongToPointer((*env)->GetLongField(env, this, fieldIds[RENDERER_NATIVE_PTR]));
 573     fillRect(env, this, rdr, x, y, w, h,
 574         IMAGE_FRAC_EDGE_KEEP, IMAGE_FRAC_EDGE_KEEP,
 575         IMAGE_FRAC_EDGE_KEEP, IMAGE_FRAC_EDGE_KEEP);
 576 }
 577 
 578 /*
 579  * Class:     com_sun_pisces_PiscesRenderer
 580  * Method:    emitAndClearAlphaRowImpl
 581  * Signature: ([B[IIII)V
 582  */
 583 JNIEXPORT void JNICALL Java_com_sun_pisces_PiscesRenderer_emitAndClearAlphaRowImpl
 584   (JNIEnv *env, jobject this, jbyteArray jAlphaMap, jintArray jAlphaDeltas, jint y, jint x_from, jint x_to,
 585    jint x_off, jint rowNum)
 586 {
 587     Renderer* rdr;
 588     Surface* surface;
 589     jobject surfaceHandle;
 590     jbyte* alphaMap;
 591 
 592     rdr = (Renderer*)JLongToPointer((*env)->GetLongField(env, this, fieldIds[RENDERER_NATIVE_PTR]));
 593 
 594     SURFACE_FROM_RENDERER(surface, env, surfaceHandle, this);
 595     ACQUIRE_SURFACE(surface, env, surfaceHandle);
 596     INVALIDATE_RENDERER_SURFACE(rdr);
 597     VALIDATE_BLITTING(rdr);
 598 
 599     alphaMap = (jbyte*)(*env)->GetPrimitiveArrayCritical(env, jAlphaMap, NULL);
 600     if (alphaMap != NULL)
 601     {
 602         jint* alphaRow = (jint*)(*env)->GetPrimitiveArrayCritical(env, jAlphaDeltas, NULL);
 603         if (alphaRow != NULL)
 604         {
 605             x_from = MAX(x_from, rdr->_clip_bbMinX);
 606             x_to = MIN(x_to, rdr->_clip_bbMaxX);
 607 
 608             if (x_to >= x_from &&
 609                 y >= rdr->_clip_bbMinY &&
 610                 y <= rdr->_clip_bbMaxY)
 611             {
 612                 rdr->_minTouched = x_from;
 613                 rdr->_maxTouched = x_to;
 614                 rdr->_currX = x_from;
 615                 rdr->_currY = y;
 616 
 617                 rdr->_rowNum = rowNum;
 618 
 619                 rdr->alphaMap = alphaMap;
 620                 rdr->_rowAAInt = alphaRow + x_off; /* add offset in alpha buffer */
 621                 rdr->_alphaWidth = x_to - x_from + 1;
 622 
 623                 rdr->_currImageOffset = y * surface->width;
 624                 rdr->_imageScanlineStride = surface->width;
 625                 rdr->_imagePixelStride = 1;
 626 
 627                 if (rdr->_genPaint) {
 628                     size_t l = (x_to - x_from + 1);
 629                     ALLOC3(rdr->_paint, jint, l);
 630                     rdr->_genPaint(rdr, 1);
 631                 }
 632                 rdr->_emitRows(rdr, 1);
 633                 rdr->_rowAAInt = NULL;
 634             }
 635             (*env)->ReleasePrimitiveArrayCritical(env, jAlphaDeltas, alphaRow, 0);
 636         } else {
 637             setMemErrorFlag();
 638         }
 639         (*env)->ReleasePrimitiveArrayCritical(env, jAlphaMap, alphaMap, 0);
 640     } else {
 641         setMemErrorFlag();
 642     }
 643 
 644     RELEASE_SURFACE(surface, env, surfaceHandle);
 645 
 646     if (JNI_TRUE == readAndClearMemErrorFlag()) {
 647         JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 648             "Allocation of internal renderer buffer failed.");
 649     }
 650 }
 651 
 652 /*
 653  * Class:     com_sun_pisces_PiscesRenderer
 654  * Method:    drawImageImpl
 655  * Signature: (I[IIIIILcom/sun/pisces/Transform6;ZIIII)V
 656  */
 657 JNIEXPORT void JNICALL Java_com_sun_pisces_PiscesRenderer_drawImageImpl
 658 (JNIEnv *env, jobject this, jint imageType, jint imageMode,
 659     jintArray dataArray, jint width, jint height, jint offset, jint stride,
 660     jobject jTransform, jboolean repeat, jboolean linearFiltering,
 661     jint bboxX, jint bboxY, jint bboxW, jint bboxH,
 662     jint lEdge, jint rEdge, jint tEdge, jint bEdge,
 663     jint txMin, jint tyMin, jint txMax, jint tyMax,
 664     jboolean hasAlpha)
 665 {
 666     Renderer* rdr;
 667     jint* data;
 668 
 669     rdr = (Renderer*)JLongToPointer((*env)->GetLongField(env, this, fieldIds[RENDERER_NATIVE_PTR]));
 670     data = (jint*)(*env)->GetPrimitiveArrayCritical(env, dataArray, NULL);
 671     if (data != NULL) {
 672         Transform6 textureTransform;
 673 
 674         transform_get6(&textureTransform, env, jTransform);
 675         renderer_setTexture(rdr, imageMode, data + offset, width, height, stride,
 676             repeat, linearFiltering, &textureTransform, JNI_FALSE, hasAlpha,
 677             txMin, tyMin, txMax, tyMax);
 678 
 679         fillRect(env, this, rdr,
 680             bboxX, bboxY, bboxW, bboxH,
 681             lEdge, rEdge, tEdge, bEdge);
 682 
 683         rdr->_texture_intData = NULL;
 684         (*env)->ReleasePrimitiveArrayCritical(env, dataArray, data, 0);
 685     } else {
 686         setMemErrorFlag();
 687     }
 688 
 689     if (JNI_TRUE == readAndClearMemErrorFlag()) {
 690         JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 691                      "Allocation of internal renderer buffer failed.");
 692     }
 693     PISCES_DEBUG_FLUSH(stdout);
 694 }
 695 
 696 /*
 697  * Class:     com_sun_pisces_PiscesRenderer
 698  * Method:    fillAlphaMaskImpl
 699  * Signature: ([BIIIIII)V
 700  */
 701 JNIEXPORT void JNICALL Java_com_sun_pisces_PiscesRenderer_fillAlphaMaskImpl
 702 (JNIEnv *env, jobject this, jbyteArray jmask, jint x, jint y, jint maskWidth, jint maskHeight, jint offset, jint stride)
 703 {
 704     Renderer* rdr;
 705     jint minX, minY, maxX, maxY;
 706     jint maskOffset;
 707     rdr = (Renderer*)JLongToPointer((*env)->GetLongField(env, this, fieldIds[RENDERER_NATIVE_PTR]));
 708 
 709     minX = MAX(x, rdr->_clip_bbMinX);
 710     minY = MAX(y, rdr->_clip_bbMinY);
 711     maxX = MIN(x + maskWidth - 1, rdr->_clip_bbMaxX);
 712     maxY = MIN(y + maskHeight - 1, rdr->_clip_bbMaxY);
 713 
 714     maskOffset = offset + (minY - y) * maskWidth + minX - x;
 715 
 716     fillAlphaMask(rdr, minX, minY, maxX, maxY, env, this, ALPHA_MASK, jmask,
 717         x, y, maskWidth, maskHeight, maskOffset, stride);
 718 }
 719 
 720 /*
 721  * Class:     com_sun_pisces_PiscesRenderer
 722  * Method:    setLCDGammaCorrection
 723  * Signature: (F)V
 724  */
 725 JNIEXPORT void JNICALL Java_com_sun_pisces_PiscesRenderer_setLCDGammaCorrectionImpl
 726 (JNIEnv *env, jobject this, jfloat gamma)
 727 {
 728     initGammaArrays(gamma);
 729 }
 730 
 731 /*
 732  * Class:     com_sun_pisces_PiscesRenderer
 733  * Method:    fillLCDAlphaMaskImpl
 734  * Signature: ([BIIIIII)V
 735  */
 736 JNIEXPORT void JNICALL Java_com_sun_pisces_PiscesRenderer_fillLCDAlphaMaskImpl
 737 (JNIEnv *env, jobject this, jbyteArray jmask, jint x, jint y,
 738     jint maskWidth, jint maskHeight,
 739     jint offset, jint stride)
 740 {
 741     Renderer* rdr;
 742     jint minX, minY, maxX, maxY;
 743     jint maskOffset;
 744     rdr = (Renderer*)JLongToPointer((*env)->GetLongField(env, this, fieldIds[RENDERER_NATIVE_PTR]));
 745 
 746     minX = MAX(x, rdr->_clip_bbMinX);
 747     minY = MAX(y, rdr->_clip_bbMinY);
 748     maxX = MIN(x + (maskWidth/3) - 1, rdr->_clip_bbMaxX);
 749     maxY = MIN(y + maskHeight - 1, rdr->_clip_bbMaxY);
 750 
 751     maskOffset = offset + (minY - y) * maskWidth + (minX - x) * 3;
 752 
 753     fillAlphaMask(rdr, minX, minY, maxX, maxY, env, this, LCD_ALPHA_MASK, jmask,
 754         x, y, maskWidth, maskHeight, maskOffset, stride);
 755 }
 756 
 757 static void fillAlphaMask(Renderer* rdr, jint minX, jint minY, jint maxX, jint maxY,
 758     JNIEnv *env, jobject this, jint maskType, jbyteArray jmask,
 759     jint x, jint y, jint maskWidth, jint maskHeight, jint offset, jint stride)
 760 {
 761     jint rowsToBeRendered, rowsBeingRendered;
 762 
 763     Surface* surface;
 764     jobject surfaceHandle;
 765 
 766     if (maxX >= minX && maxY >= minY)
 767     {
 768         jbyte* mask;
 769 
 770         SURFACE_FROM_RENDERER(surface, env, surfaceHandle, this);
 771         ACQUIRE_SURFACE(surface, env, surfaceHandle);
 772 
 773         mask = (jbyte*)(*env)->GetPrimitiveArrayCritical(env, jmask, NULL);
 774         if (mask != NULL) {
 775             jint width = maxX - minX + 1;
 776             jint height = maxY - minY + 1;
 777 
 778             renderer_setMask(rdr, maskType, mask, maskWidth, maskHeight, JNI_FALSE);
 779 
 780             INVALIDATE_RENDERER_SURFACE(rdr);
 781             VALIDATE_BLITTING(rdr);
 782 
 783             rdr->_minTouched = minX;
 784             rdr->_maxTouched = maxX;
 785             rdr->_currX = minX;
 786             rdr->_currY = minY;
 787 
 788             rdr->_alphaWidth = width;
 789 
 790             rdr->_imageScanlineStride = surface->width;
 791             rdr->_imagePixelStride = 1;
 792             rdr->_rowNum = 0;
 793             rdr->_maskOffset = offset;
 794 
 795             rowsToBeRendered = height;
 796 
 797             while (rowsToBeRendered > 0) {
 798                 rowsBeingRendered = 1; //MIN(rowsToBeRendered, NUM_ALPHA_ROWS);
 799 
 800                 rdr->_currImageOffset = rdr->_currY * surface->width;
 801                 if (rdr->_genPaint) {
 802                     size_t l = (width * rowsBeingRendered);
 803                     ALLOC3(rdr->_paint, jint, l);
 804                     rdr->_genPaint(rdr, rowsBeingRendered);
 805                 }
 806                 rdr->_emitRows(rdr, rowsBeingRendered);
 807 
 808                 rdr->_maskOffset += maskWidth;
 809                 rdr->_rowNum += rowsBeingRendered;
 810                 rowsToBeRendered -= rowsBeingRendered;
 811                 rdr->_currX = x;
 812                 rdr->_currY += rowsBeingRendered;
 813             }
 814 
 815             renderer_removeMask(rdr);
 816             (*env)->ReleasePrimitiveArrayCritical(env, jmask, mask, 0);
 817         } else {
 818             setMemErrorFlag();
 819         }
 820 
 821         RELEASE_SURFACE(surface, env, surfaceHandle);
 822 
 823         if (JNI_TRUE == readAndClearMemErrorFlag()) {
 824             JNI_ThrowNew(env, "java/lang/OutOfMemoryError",
 825                          "Allocation of internal renderer buffer failed.");
 826         }
 827     }
 828 }
 829