1 /*
   2  * Copyright (c) 2004, 2014, 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 <stdlib.h>
  27 #include "jni_util.h"
  28 #include "math.h"
  29 
  30 #include "GraphicsPrimitiveMgr.h"
  31 #include "Region.h"
  32 
  33 #include "sun_java2d_loops_TransformHelper.h"
  34 #include "java_awt_image_AffineTransformOp.h"
  35 
  36 /*
  37  * The stub functions replace the bilinear and bicubic interpolation
  38  * functions with NOP versions so that the performance of the helper
  39  * functions that fetch the data can be more directly tested.  They
  40  * are not compiled or enabled by default.  Change the following
  41  * #undef to a #define to build the stub functions.
  42  *
  43  * When compiled, they are enabled by the environment variable TXSTUB.
  44  * When compiled, there is also code to disable the VIS versions and
  45  * use the C versions in this file in their place by defining the TXNOVIS
  46  * environment variable.
  47  */
  48 #undef MAKE_STUBS
  49 
  50 /* The number of IntArgbPre samples to store in the temporary buffer. */
  51 #define LINE_SIZE       2048
  52 
  53 /* The size of a stack allocated buffer to hold edge coordinates (see below). */
  54 #define MAXEDGES 1024
  55 
  56 /* Declare the software interpolation functions. */
  57 static TransformInterpFunc BilinearInterp;
  58 static TransformInterpFunc BicubicInterp;
  59 
  60 #ifdef MAKE_STUBS
  61 /* Optionally Declare the stub interpolation functions. */
  62 static TransformInterpFunc BilinearInterpStub;
  63 static TransformInterpFunc BicubicInterpStub;
  64 #endif /* MAKE_STUBS */
  65 
  66 /*
  67  * Initially choose the software interpolation functions.
  68  * These choices can be overridden by platform code that runs during the
  69  * primitive registration phase of initialization by storing pointers to
  70  * better functions in these pointers.
  71  * Compiling the stubs also turns on code below that can re-install the
  72  * software functions or stub functions on the first call to this primitive.
  73  */
  74 TransformInterpFunc *pBilinearFunc = BilinearInterp;
  75 TransformInterpFunc *pBicubicFunc = BicubicInterp;
  76 
  77 /*
  78  * The dxydxy parameters of the inverse transform determine how
  79  * quickly we step through the source image.  For tiny scale
  80  * factors (on the order of 1E-16 or so) the stepping distances
  81  * are huge.  The image has been scaled so small that stepping
  82  * a single pixel in device space moves the sampling point by
  83  * billions (or more) pixels in the source image space.  These
  84  * huge stepping values can overflow the whole part of the longs
  85  * we use for the fixed point stepping equations and so we need
  86  * a more robust solution.  We could simply iterate over every
  87  * device pixel, use the inverse transform to transform it back
  88  * into the source image coordinate system and then test it for
  89  * being in range and sample pixel-by-pixel, but that is quite
  90  * a bit more expensive.  Fortunately, if the scale factors are
  91  * so tiny that we overflow our long values then the number of
  92  * pixels we are planning to visit should be very tiny.  The only
  93  * exception to that rule is if the scale factor along one
  94  * dimension is tiny (creating the huge stepping values), and
  95  * the scale factor along the other dimension is fairly regular
  96  * or an up-scale.  In that case we have a lot of pixels along
  97  * the direction of the larger axis to sample, but few along the
  98  * smaller axis.  Though, pessimally, with an added shear factor
  99  * such a linearly tiny image could have bounds that cover a large
 100  * number of pixels.  Such odd transformations should be very
 101  * rare and the absolute limit on calculations would involve a
 102  * single reverse transform of every pixel in the output image
 103  * which is not fast, but it should not cause an undue stall
 104  * of the rendering software.
 105  *
 106  * The specific test we will use is to calculate the inverse
 107  * transformed values of every corner of the destination bounds
 108  * (in order to be user-clip independent) and if we can
 109  * perform a fixed-point-long inverse transform of all of
 110  * those points without overflowing we will use the fast
 111  * fixed point algorithm.  Otherwise we will use the safe
 112  * per-pixel transform algorithm.
 113  * The 4 corners are 0,0, 0,dsth, dstw,0, dstw,dsth
 114  * Transformed they are:
 115  *     tx,               ty
 116  *     tx       +dxdy*H, ty       +dydy*H
 117  *     tx+dxdx*W,        ty+dydx*W
 118  *     tx+dxdx*W+dxdy*H, ty+dydx*W+dydy*H
 119  */
 120 /* We reject coordinates not less than 1<<30 so that the distance between */
 121 /* any 2 of them is less than 1<<31 which would overflow into the sign */
 122 /* bit of a signed long value used to represent fixed point coordinates. */
 123 #define TX_FIXED_UNSAFE(v)  (fabs(v) >= (1<<30))
 124 static jboolean
 125 checkOverflow(jint dxoff, jint dyoff,
 126               SurfaceDataBounds *pBounds,
 127               TransformInfo *pItxInfo,
 128               jdouble *retx, jdouble *rety)
 129 {
 130     jdouble x, y;
 131 
 132     x = dxoff+pBounds->x1+0.5; /* Center of pixel x1 */
 133     y = dyoff+pBounds->y1+0.5; /* Center of pixel y1 */
 134     Transform_transform(pItxInfo, &x, &y);
 135     *retx = x;
 136     *rety = y;
 137     if (TX_FIXED_UNSAFE(x) || TX_FIXED_UNSAFE(y)) {
 138         return JNI_TRUE;
 139     }
 140 
 141     x = dxoff+pBounds->x2-0.5; /* Center of pixel x2-1 */
 142     y = dyoff+pBounds->y1+0.5; /* Center of pixel y1 */
 143     Transform_transform(pItxInfo, &x, &y);
 144     if (TX_FIXED_UNSAFE(x) || TX_FIXED_UNSAFE(y)) {
 145         return JNI_TRUE;
 146     }
 147 
 148     x = dxoff+pBounds->x1+0.5; /* Center of pixel x1 */
 149     y = dyoff+pBounds->y2-0.5; /* Center of pixel y2-1 */
 150     Transform_transform(pItxInfo, &x, &y);
 151     if (TX_FIXED_UNSAFE(x) || TX_FIXED_UNSAFE(y)) {
 152         return JNI_TRUE;
 153     }
 154 
 155     x = dxoff+pBounds->x2-0.5; /* Center of pixel x2-1 */
 156     y = dyoff+pBounds->y2-0.5; /* Center of pixel y2-1 */
 157     Transform_transform(pItxInfo, &x, &y);
 158     if (TX_FIXED_UNSAFE(x) || TX_FIXED_UNSAFE(y)) {
 159         return JNI_TRUE;
 160     }
 161 
 162     return JNI_FALSE;
 163 }
 164 
 165 /*
 166  * Fill the edge buffer with pairs of coordinates representing the maximum
 167  * left and right pixels of the destination surface that should be processed
 168  * on each scanline, clipped to the bounds parameter.
 169  * The number of scanlines to calculate is implied by the bounds parameter.
 170  * Only pixels that map back through the specified (inverse) transform to a
 171  * source coordinate that falls within the (0, 0, sw, sh) bounds of the
 172  * source image should be processed.
 173  * pEdges points to an array of jints that holds 2 + numedges*2 values where
 174  * numedges should match (pBounds->y2 - pBounds->y1).
 175  * The first two jints in pEdges should be set to y1 and y2 and every pair
 176  * of jints after that represent the xmin,xmax of all pixels in range of
 177  * the transformed blit for the corresponding scanline.
 178  */
 179 static void
 180 calculateEdges(jint *pEdges,
 181                SurfaceDataBounds *pBounds,
 182                TransformInfo *pItxInfo,
 183                jlong xbase, jlong ybase,
 184                juint sw, juint sh)
 185 {
 186     jlong dxdxlong, dydxlong;
 187     jlong dxdylong, dydylong;
 188     jlong drowxlong, drowylong;
 189     jint dx1, dy1, dx2, dy2;
 190 
 191     dxdxlong = DblToLong(pItxInfo->dxdx);
 192     dydxlong = DblToLong(pItxInfo->dydx);
 193     dxdylong = DblToLong(pItxInfo->dxdy);
 194     dydylong = DblToLong(pItxInfo->dydy);
 195 
 196     dx1 = pBounds->x1;
 197     dy1 = pBounds->y1;
 198     dx2 = pBounds->x2;
 199     dy2 = pBounds->y2;
 200     *pEdges++ = dy1;
 201     *pEdges++ = dy2;
 202 
 203     drowxlong = (dx2-dx1-1) * dxdxlong;
 204     drowylong = (dx2-dx1-1) * dydxlong;
 205 
 206     while (dy1 < dy2) {
 207         jlong xlong, ylong;
 208 
 209         dx1 = pBounds->x1;
 210         dx2 = pBounds->x2;
 211 
 212         xlong = xbase;
 213         ylong = ybase;
 214         while (dx1 < dx2 &&
 215                (((juint) WholeOfLong(ylong)) >= sh ||
 216                 ((juint) WholeOfLong(xlong)) >= sw))
 217         {
 218             dx1++;
 219             xlong += dxdxlong;
 220             ylong += dydxlong;
 221         }
 222 
 223         xlong = xbase + drowxlong;
 224         ylong = ybase + drowylong;
 225         while (dx2 > dx1 &&
 226                (((juint) WholeOfLong(ylong)) >= sh ||
 227                 ((juint) WholeOfLong(xlong)) >= sw))
 228         {
 229             dx2--;
 230             xlong -= dxdxlong;
 231             ylong -= dydxlong;
 232         }
 233 
 234         *pEdges++ = dx1;
 235         *pEdges++ = dx2;
 236 
 237         /* Increment to next scanline */
 238         xbase += dxdylong;
 239         ybase += dydylong;
 240         dy1++;
 241     }
 242 }
 243 
 244 static void
 245 Transform_SafeHelper(JNIEnv *env,
 246                      SurfaceDataOps *srcOps,
 247                      SurfaceDataOps *dstOps,
 248                      SurfaceDataRasInfo *pSrcInfo,
 249                      SurfaceDataRasInfo *pDstInfo,
 250                      NativePrimitive *pMaskBlitPrim,
 251                      CompositeInfo *pCompInfo,
 252                      TransformHelperFunc *pHelperFunc,
 253                      TransformInterpFunc *pInterpFunc,
 254                      RegionData *pClipInfo, TransformInfo *pItxInfo,
 255                      jint *pData, jint *pEdges,
 256                      jint dxoff, jint dyoff, jint sw, jint sh);
 257 
 258 /*
 259  * Class:     sun_java2d_loops_TransformHelper
 260  * Method:    Transform
 261  * Signature: (Lsun/java2d/loops/MaskBlit;Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;Ljava/awt/Composite;Lsun/java2d/pipe/Region;Ljava/awt/geom/AffineTransform;IIIIIIIII[I)V
 262  */
 263 JNIEXPORT void JNICALL
 264 Java_sun_java2d_loops_TransformHelper_Transform
 265     (JNIEnv *env, jobject self,
 266      jobject maskblit,
 267      jobject srcData, jobject dstData,
 268      jobject comp, jobject clip,
 269      jobject itxform, jint txtype,
 270      jint sx1, jint sy1, jint sx2, jint sy2,
 271      jint dx1, jint dy1, jint dx2, jint dy2,
 272      jintArray edgeArray, jint dxoff, jint dyoff)
 273 {
 274     SurfaceDataOps *srcOps;
 275     SurfaceDataOps *dstOps;
 276     SurfaceDataRasInfo srcInfo;
 277     SurfaceDataRasInfo dstInfo;
 278     NativePrimitive *pHelperPrim;
 279     NativePrimitive *pMaskBlitPrim;
 280     CompositeInfo compInfo;
 281     RegionData clipInfo;
 282     TransformInfo itxInfo;
 283     jint maxlinepix;
 284     TransformHelperFunc *pHelperFunc;
 285     TransformInterpFunc *pInterpFunc;
 286     jdouble xorig, yorig;
 287     jlong numedges;
 288     jint *pEdges;
 289     jint edgebuf[2 + MAXEDGES * 2];
 290     union {
 291         jlong align;
 292         jint data[LINE_SIZE];
 293     } rgb;
 294 
 295 #ifdef MAKE_STUBS
 296     static int th_initialized;
 297 
 298     /* For debugging only - used to swap in alternate funcs for perf testing */
 299     if (!th_initialized) {
 300         if (getenv("TXSTUB") != 0) {
 301             pBilinearFunc = BilinearInterpStub;
 302             pBicubicFunc = BicubicInterpStub;
 303         } else if (getenv("TXNOVIS") != 0) {
 304             pBilinearFunc = BilinearInterp;
 305             pBicubicFunc = BicubicInterp;
 306         }
 307         th_initialized = 1;
 308     }
 309 #endif /* MAKE_STUBS */
 310 
 311     pHelperPrim = GetNativePrim(env, self);
 312     if (pHelperPrim == NULL) {
 313         /* Should never happen... */
 314         return;
 315     }
 316     pMaskBlitPrim = GetNativePrim(env, maskblit);
 317     if (pMaskBlitPrim == NULL) {
 318         /* Exception was thrown by GetNativePrim */
 319         return;
 320     }
 321     if (pMaskBlitPrim->pCompType->getCompInfo != NULL) {
 322         (*pMaskBlitPrim->pCompType->getCompInfo)(env, &compInfo, comp);
 323     }
 324     if (Region_GetInfo(env, clip, &clipInfo)) {
 325         return;
 326     }
 327 
 328     srcOps = SurfaceData_GetOps(env, srcData);
 329     if (srcOps == 0) {
 330         return;
 331     }
 332     dstOps = SurfaceData_GetOps(env, dstData);
 333     if (dstOps == 0) {
 334         return;
 335     }
 336 
 337     /*
 338      * Grab the appropriate pointer to the helper and interpolation
 339      * routines and calculate the maximum number of destination pixels
 340      * that can be processed in one intermediate buffer based on the
 341      * size of the buffer and the number of samples needed per pixel.
 342      */
 343     switch (txtype) {
 344     case java_awt_image_AffineTransformOp_TYPE_NEAREST_NEIGHBOR:
 345         pHelperFunc = pHelperPrim->funcs.transformhelpers->nnHelper;
 346         pInterpFunc = NULL;
 347         maxlinepix = LINE_SIZE;
 348         break;
 349     case java_awt_image_AffineTransformOp_TYPE_BILINEAR:
 350         pHelperFunc = pHelperPrim->funcs.transformhelpers->blHelper;
 351         pInterpFunc = pBilinearFunc;
 352         maxlinepix = LINE_SIZE / 4;
 353         break;
 354     case java_awt_image_AffineTransformOp_TYPE_BICUBIC:
 355         pHelperFunc = pHelperPrim->funcs.transformhelpers->bcHelper;
 356         pInterpFunc = pBicubicFunc;
 357         maxlinepix = LINE_SIZE / 16;
 358         break;
 359     default:
 360         // Should not happen, but just in case.
 361         return;
 362     }
 363 
 364     srcInfo.bounds.x1 = sx1;
 365     srcInfo.bounds.y1 = sy1;
 366     srcInfo.bounds.x2 = sx2;
 367     srcInfo.bounds.y2 = sy2;
 368     dstInfo.bounds.x1 = dx1;
 369     dstInfo.bounds.y1 = dy1;
 370     dstInfo.bounds.x2 = dx2;
 371     dstInfo.bounds.y2 = dy2;
 372     SurfaceData_IntersectBounds(&dstInfo.bounds, &clipInfo.bounds);
 373     if (srcOps->Lock(env, srcOps, &srcInfo, pHelperPrim->srcflags)
 374         != SD_SUCCESS)
 375     {
 376         /* edgeArray should already contain zeros for min/maxy */
 377         return;
 378     }
 379     if (dstOps->Lock(env, dstOps, &dstInfo, pMaskBlitPrim->dstflags)
 380         != SD_SUCCESS)
 381     {
 382         SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
 383         /* edgeArray should already contain zeros for min/maxy */
 384         return;
 385     }
 386     Region_IntersectBounds(&clipInfo, &dstInfo.bounds);
 387     Transform_GetInfo(env, itxform, &itxInfo);
 388 
 389     numedges = (((jlong) dstInfo.bounds.y2) - ((jlong) dstInfo.bounds.y1));
 390     if (numedges <= 0) {
 391         pEdges = NULL;
 392     } else if (!JNU_IsNull(env, edgeArray)) {
 393         /*
 394          * Ideally Java should allocate an array large enough, but if
 395          * we ever have a miscommunication about the number of edge
 396          * lines, or if the Java array calculation should overflow to
 397          * a positive number and succeed in allocating an array that
 398          * is too small, we need to verify that it can still hold the
 399          * number of integers that we plan to store to be safe.
 400          */
 401         jsize edgesize = (*env)->GetArrayLength(env, edgeArray);
 402         /* (edgesize/2 - 1) should avoid any overflow or underflow. */
 403         pEdges = (((edgesize / 2) - 1) >= numedges)
 404             ? (*env)->GetPrimitiveArrayCritical(env, edgeArray, NULL)
 405             : NULL;
 406     } else if (numedges > MAXEDGES) {
 407         /* numedges variable (jlong) can be at most ((1<<32)-1) */
 408         /* memsize can overflow a jint, but not a jlong */
 409         jlong memsize = ((numedges * 2) + 2) * sizeof(*pEdges);
 410         pEdges = (memsize == ((size_t) memsize))
 411             ? malloc((size_t) memsize)
 412             : NULL;
 413     } else {
 414         pEdges = edgebuf;
 415     }
 416 
 417     if (pEdges == NULL) {
 418         if (!(*env)->ExceptionCheck(env) && numedges > 0) {
 419             JNU_ThrowInternalError(env, "Unable to allocate edge list");
 420         }
 421         SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
 422         SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
 423         /* edgeArray should already contain zeros for min/maxy */
 424         return;
 425     }
 426 
 427 
 428     if (!Region_IsEmpty(&clipInfo)) {
 429         srcOps->GetRasInfo(env, srcOps, &srcInfo);
 430         dstOps->GetRasInfo(env, dstOps, &dstInfo);
 431         if (srcInfo.rasBase == NULL || dstInfo.rasBase == NULL) {
 432             pEdges[0] = pEdges[1] = 0;
 433         } else if (checkOverflow(dxoff, dyoff, &dstInfo.bounds,
 434                                  &itxInfo, &xorig, &yorig))
 435         {
 436             Transform_SafeHelper(env, srcOps, dstOps,
 437                                  &srcInfo, &dstInfo,
 438                                  pMaskBlitPrim, &compInfo,
 439                                  pHelperFunc, pInterpFunc,
 440                                  &clipInfo, &itxInfo, rgb.data, pEdges,
 441                                  dxoff, dyoff, sx2-sx1, sy2-sy1);
 442         } else {
 443             SurfaceDataBounds span;
 444             jlong dxdxlong, dydxlong;
 445             jlong dxdylong, dydylong;
 446             jlong xbase, ybase;
 447 
 448             dxdxlong = DblToLong(itxInfo.dxdx);
 449             dydxlong = DblToLong(itxInfo.dydx);
 450             dxdylong = DblToLong(itxInfo.dxdy);
 451             dydylong = DblToLong(itxInfo.dydy);
 452             xbase = DblToLong(xorig);
 453             ybase = DblToLong(yorig);
 454 
 455             calculateEdges(pEdges, &dstInfo.bounds, &itxInfo,
 456                            xbase, ybase, sx2-sx1, sy2-sy1);
 457 
 458             Region_StartIteration(env, &clipInfo);
 459             while (Region_NextIteration(&clipInfo, &span)) {
 460                 jlong rowxlong, rowylong;
 461                 void *pDst;
 462 
 463                 dy1 = span.y1;
 464                 dy2 = span.y2;
 465                 rowxlong = xbase + (dy1 - dstInfo.bounds.y1) * dxdylong;
 466                 rowylong = ybase + (dy1 - dstInfo.bounds.y1) * dydylong;
 467 
 468                 while (dy1 < dy2) {
 469                     jlong xlong, ylong;
 470 
 471                     /* Note - process at most one scanline at a time. */
 472 
 473                     dx1 = pEdges[(dy1 - dstInfo.bounds.y1) * 2 + 2];
 474                     dx2 = pEdges[(dy1 - dstInfo.bounds.y1) * 2 + 3];
 475                     if (dx1 < span.x1) dx1 = span.x1;
 476                     if (dx2 > span.x2) dx2 = span.x2;
 477 
 478                     /* All pixels from dx1 to dx2 have centers in bounds */
 479                     while (dx1 < dx2) {
 480                         /* Can process at most one buffer full at a time */
 481                         jint numpix = dx2 - dx1;
 482                         if (numpix > maxlinepix) {
 483                             numpix = maxlinepix;
 484                         }
 485 
 486                         xlong =
 487                             rowxlong + ((dx1 - dstInfo.bounds.x1) * dxdxlong);
 488                         ylong =
 489                             rowylong + ((dx1 - dstInfo.bounds.x1) * dydxlong);
 490 
 491                         /* Get IntArgbPre pixel data from source */
 492                         (*pHelperFunc)(&srcInfo,
 493                                        rgb.data, numpix,
 494                                        xlong, dxdxlong,
 495                                        ylong, dydxlong);
 496 
 497                         /* Interpolate result pixels if needed */
 498                         if (pInterpFunc) {
 499                             (*pInterpFunc)(rgb.data, numpix,
 500                                            FractOfLong(xlong-LongOneHalf),
 501                                            FractOfLong(dxdxlong),
 502                                            FractOfLong(ylong-LongOneHalf),
 503                                            FractOfLong(dydxlong));
 504                         }
 505 
 506                         /* Store/Composite interpolated pixels into dest */
 507                         pDst = PtrCoord(dstInfo.rasBase,
 508                                         dx1, dstInfo.pixelStride,
 509                                         dy1, dstInfo.scanStride);
 510                         (*pMaskBlitPrim->funcs.maskblit)(pDst, rgb.data,
 511                                                          0, 0, 0,
 512                                                          numpix, 1,
 513                                                          &dstInfo, &srcInfo,
 514                                                          pMaskBlitPrim,
 515                                                          &compInfo);
 516 
 517                         /* Increment to next buffer worth of input pixels */
 518                         dx1 += maxlinepix;
 519                     }
 520 
 521                     /* Increment to next scanline */
 522                     rowxlong += dxdylong;
 523                     rowylong += dydylong;
 524                     dy1++;
 525                 }
 526             }
 527             Region_EndIteration(env, &clipInfo);
 528         }
 529         SurfaceData_InvokeRelease(env, dstOps, &dstInfo);
 530         SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
 531     } else {
 532         pEdges[0] = pEdges[1] = 0;
 533     }
 534 
 535     if (!JNU_IsNull(env, edgeArray)) {
 536         (*env)->ReleasePrimitiveArrayCritical(env, edgeArray, pEdges, 0);
 537     } else if (pEdges != edgebuf) {
 538         free(pEdges);
 539     }
 540     SurfaceData_InvokeUnlock(env, dstOps, &dstInfo);
 541     SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
 542 }
 543 
 544 static void
 545 Transform_SafeHelper(JNIEnv *env,
 546                      SurfaceDataOps *srcOps,
 547                      SurfaceDataOps *dstOps,
 548                      SurfaceDataRasInfo *pSrcInfo,
 549                      SurfaceDataRasInfo *pDstInfo,
 550                      NativePrimitive *pMaskBlitPrim,
 551                      CompositeInfo *pCompInfo,
 552                      TransformHelperFunc *pHelperFunc,
 553                      TransformInterpFunc *pInterpFunc,
 554                      RegionData *pClipInfo, TransformInfo *pItxInfo,
 555                      jint *pData, jint *pEdges,
 556                      jint dxoff, jint dyoff, jint sw, jint sh)
 557 {
 558     SurfaceDataBounds span;
 559     jint dx1, dx2;
 560     jint dy1, dy2;
 561     jint i, iy;
 562 
 563     dy1 = pDstInfo->bounds.y1;
 564     dy2 = pDstInfo->bounds.y2;
 565     dx1 = pDstInfo->bounds.x1;
 566     dx2 = pDstInfo->bounds.x2;
 567     pEdges[0] = dy1;
 568     pEdges[1] = dy2;
 569     for (iy = dy1; iy < dy2; iy++) {
 570         jint i = (iy - dy1) * 2;
 571         /* row spans are set to max,min until we find a pixel in range below */
 572         pEdges[i + 2] = dx2;
 573         pEdges[i + 3] = dx1;
 574     }
 575 
 576     Region_StartIteration(env, pClipInfo);
 577     while (Region_NextIteration(pClipInfo, &span)) {
 578         dy1 = span.y1;
 579         dy2 = span.y2;
 580         while (dy1 < dy2) {
 581             dx1 = span.x1;
 582             dx2 = span.x2;
 583             i = (dy1 - pDstInfo->bounds.y1) * 2;
 584             while (dx1 < dx2) {
 585                 jdouble x, y;
 586                 jlong xlong, ylong;
 587 
 588                 x = dxoff + dx1 + 0.5;
 589                 y = dyoff + dy1 + 0.5;
 590                 Transform_transform(pItxInfo, &x, &y);
 591                 xlong = DblToLong(x);
 592                 ylong = DblToLong(y);
 593 
 594                 /* Process only pixels with centers in bounds
 595                  * Test double values to avoid overflow in conversion
 596                  * to long values and then also test the long values
 597                  * in case they rounded up and out of bounds during
 598                  * the conversion.
 599                  */
 600                 if (x >= 0 && y >= 0 && x < sw && y < sh &&
 601                     WholeOfLong(xlong) < sw &&
 602                     WholeOfLong(ylong) < sh)
 603                 {
 604                     void *pDst;
 605 
 606                     if (pEdges[i + 2] > dx1) {
 607                         pEdges[i + 2] = dx1;
 608                     }
 609                     if (pEdges[i + 3] <= dx1) {
 610                         pEdges[i + 3] = dx1 + 1;
 611                     }
 612 
 613                     /* Get IntArgbPre pixel data from source */
 614                     (*pHelperFunc)(pSrcInfo,
 615                                    pData, 1,
 616                                    xlong, 0,
 617                                    ylong, 0);
 618 
 619                     /* Interpolate result pixels if needed */
 620                     if (pInterpFunc) {
 621                         (*pInterpFunc)(pData, 1,
 622                                        FractOfLong(xlong-LongOneHalf), 0,
 623                                        FractOfLong(ylong-LongOneHalf), 0);
 624                     }
 625 
 626                     /* Store/Composite interpolated pixels into dest */
 627                     pDst = PtrCoord(pDstInfo->rasBase,
 628                                     dx1, pDstInfo->pixelStride,
 629                                     dy1, pDstInfo->scanStride);
 630                     (*pMaskBlitPrim->funcs.maskblit)(pDst, pData,
 631                                                      0, 0, 0,
 632                                                      1, 1,
 633                                                      pDstInfo, pSrcInfo,
 634                                                      pMaskBlitPrim,
 635                                                      pCompInfo);
 636                 }
 637 
 638                 /* Increment to next input pixel */
 639                 dx1++;
 640             }
 641 
 642             /* Increment to next scanline */
 643             dy1++;
 644         }
 645     }
 646     Region_EndIteration(env, pClipInfo);
 647 }
 648 
 649 #define BL_INTERP_V1_to_V2_by_F(v1, v2, f) \
 650     (((v1)<<8) + ((v2)-(v1))*(f))
 651 
 652 #define BL_ACCUM(comp) \
 653     do { \
 654         jint c1 = ((jubyte *) pRGB)[comp]; \
 655         jint c2 = ((jubyte *) pRGB)[comp+4]; \
 656         jint cR = BL_INTERP_V1_to_V2_by_F(c1, c2, xfactor); \
 657         c1 = ((jubyte *) pRGB)[comp+8]; \
 658         c2 = ((jubyte *) pRGB)[comp+12]; \
 659         c2 = BL_INTERP_V1_to_V2_by_F(c1, c2, xfactor); \
 660         cR = BL_INTERP_V1_to_V2_by_F(cR, c2, yfactor); \
 661         ((jubyte *)pRes)[comp] = (jubyte) ((cR + (1<<15)) >> 16); \
 662     } while (0)
 663 
 664 static void
 665 BilinearInterp(jint *pRGB, jint numpix,
 666                jint xfract, jint dxfract,
 667                jint yfract, jint dyfract)
 668 {
 669     jint j;
 670     jint *pRes = pRGB;
 671 
 672     for (j = 0; j < numpix; j++) {
 673         jint xfactor;
 674         jint yfactor;
 675         xfactor = URShift(xfract, 32-8);
 676         yfactor = URShift(yfract, 32-8);
 677         BL_ACCUM(0);
 678         BL_ACCUM(1);
 679         BL_ACCUM(2);
 680         BL_ACCUM(3);
 681         pRes++;
 682         pRGB += 4;
 683         xfract += dxfract;
 684         yfract += dyfract;
 685     }
 686 }
 687 
 688 #define SAT(val, max) \
 689     do { \
 690         val &= ~(val >> 31);  /* negatives become 0 */ \
 691         val -= max;           /* only overflows are now positive */ \
 692         val &= (val >> 31);   /* positives become 0 */ \
 693         val += max;           /* range is now [0 -> max] */ \
 694     } while (0)
 695 
 696 /* For x86, integer multiplies are faster than floating point */
 697 /* Note that on x86 Linux the choice of best algorithm varies
 698  * depending on the compiler optimization and the processor type.
 699  * Currently, the sun/awt x86 Linux builds are not optimized so
 700  * all the variations produce mediocre performance.
 701  * For now we will use the choice that works best for the Windows
 702  * build until the (lack of) optimization issues on Linux are resolved.
 703  */
 704 #define BICUBIC_USE_INT_MATH
 705 
 706 #ifdef BICUBIC_USE_DBL_CAST
 707 
 708 #define BC_DblToCoeff(v)        (v)
 709 #define BC_COEFF_ONE            1.0
 710 #define BC_TYPE                 jdouble
 711 #define BC_V_HALF               0.5
 712 #define BC_CompToV(v)           ((jdouble) (v))
 713 #define BC_STORE_COMPS(pRes) \
 714     do { \
 715         jint a = (jint) accumA; \
 716         jint r = (jint) accumR; \
 717         jint g = (jint) accumG; \
 718         jint b = (jint) accumB; \
 719         SAT(a, 255); \
 720         SAT(r, a); \
 721         SAT(g, a); \
 722         SAT(b, a); \
 723         *pRes = ((a << 24) | (r << 16) | (g <<  8) | (b)); \
 724     } while (0)
 725 
 726 #endif /* BICUBIC_USE_DBL_CAST */
 727 
 728 #ifdef BICUBIC_USE_DBL_LUT
 729 
 730 #define ItoD1(v)    ((jdouble) (v))
 731 #define ItoD4(v)    ItoD1(v),  ItoD1(v+1),   ItoD1(v+2),   ItoD1(v+3)
 732 #define ItoD16(v)   ItoD4(v),  ItoD4(v+4),   ItoD4(v+8),   ItoD4(v+12)
 733 #define ItoD64(v)   ItoD16(v), ItoD16(v+16), ItoD16(v+32), ItoD16(v+48)
 734 
 735 static jdouble ItoD_table[] = {
 736     ItoD64(0), ItoD64(64), ItoD64(128), ItoD64(192)
 737 };
 738 
 739 #define BC_DblToCoeff(v)        (v)
 740 #define BC_COEFF_ONE            1.0
 741 #define BC_TYPE                 jdouble
 742 #define BC_V_HALF               0.5
 743 #define BC_CompToV(v)           ItoD_table[v]
 744 #define BC_STORE_COMPS(pRes) \
 745     do { \
 746         jint a = (jint) accumA; \
 747         jint r = (jint) accumR; \
 748         jint g = (jint) accumG; \
 749         jint b = (jint) accumB; \
 750         SAT(a, 255); \
 751         SAT(r, a); \
 752         SAT(g, a); \
 753         SAT(b, a); \
 754         *pRes = ((a << 24) | (r << 16) | (g <<  8) | (b)); \
 755     } while (0)
 756 
 757 #endif /* BICUBIC_USE_DBL_LUT */
 758 
 759 #ifdef BICUBIC_USE_INT_MATH
 760 
 761 #define BC_DblToCoeff(v)        ((jint) ((v) * 256))
 762 #define BC_COEFF_ONE            256
 763 #define BC_TYPE                 jint
 764 #define BC_V_HALF               (1 << 15)
 765 #define BC_CompToV(v)           ((jint) v)
 766 #define BC_STORE_COMPS(pRes) \
 767     do { \
 768         accumA >>= 16; \
 769         accumR >>= 16; \
 770         accumG >>= 16; \
 771         accumB >>= 16; \
 772         SAT(accumA, 255); \
 773         SAT(accumR, accumA); \
 774         SAT(accumG, accumA); \
 775         SAT(accumB, accumA); \
 776         *pRes = ((accumA << 24) | (accumR << 16) | (accumG << 8) | (accumB)); \
 777     } while (0)
 778 
 779 #endif /* BICUBIC_USE_INT_MATH */
 780 
 781 #define BC_ACCUM(index, ycindex, xcindex) \
 782     do { \
 783         BC_TYPE factor = bicubic_coeff[xcindex] * bicubic_coeff[ycindex]; \
 784         int rgb; \
 785         rgb = pRGB[index]; \
 786         accumB += BC_CompToV((rgb >>  0) & 0xff) * factor; \
 787         accumG += BC_CompToV((rgb >>  8) & 0xff) * factor; \
 788         accumR += BC_CompToV((rgb >> 16) & 0xff) * factor; \
 789         accumA += BC_CompToV((rgb >> 24) & 0xff) * factor; \
 790     } while (0)
 791 
 792 static BC_TYPE bicubic_coeff[513];
 793 static jboolean bicubictableinited;
 794 
 795 static void
 796 init_bicubic_table(jdouble A)
 797 {
 798     /*
 799      * The following formulas are designed to give smooth
 800      * results when 'A' is -0.5 or -1.0.
 801      */
 802     int i;
 803     for (i = 0; i < 256; i++) {
 804         /* r(x) = (A + 2)|x|^3 - (A + 3)|x|^2 + 1 , 0 <= |x| < 1 */
 805         jdouble x = i / 256.0;
 806         x = ((A+2)*x - (A+3))*x*x + 1;
 807         bicubic_coeff[i] = BC_DblToCoeff(x);
 808     }
 809 
 810     for (; i < 384; i++) {
 811         /* r(x) = A|x|^3 - 5A|x|^2 + 8A|x| - 4A , 1 <= |x| < 2 */
 812         jdouble x = i / 256.0;
 813         x = ((A*x - 5*A)*x + 8*A)*x - 4*A;
 814         bicubic_coeff[i] = BC_DblToCoeff(x);
 815     }
 816 
 817     bicubic_coeff[384] = (BC_COEFF_ONE - bicubic_coeff[128]*2) / 2;
 818 
 819     for (i++; i <= 512; i++) {
 820         bicubic_coeff[i] = BC_COEFF_ONE - (bicubic_coeff[512-i] +
 821                                            bicubic_coeff[i-256] +
 822                                            bicubic_coeff[768-i]);
 823     }
 824 
 825     bicubictableinited = JNI_TRUE;
 826 }
 827 
 828 static void
 829 BicubicInterp(jint *pRGB, jint numpix,
 830               jint xfract, jint dxfract,
 831               jint yfract, jint dyfract)
 832 {
 833     jint i;
 834     jint *pRes = pRGB;
 835 
 836     if (!bicubictableinited) {
 837         init_bicubic_table(-0.5);
 838     }
 839 
 840     for (i = 0; i < numpix; i++) {
 841         BC_TYPE accumA, accumR, accumG, accumB;
 842         jint xfactor, yfactor;
 843 
 844         xfactor = URShift(xfract, 32-8);
 845         yfactor = URShift(yfract, 32-8);
 846         accumA = accumR = accumG = accumB = BC_V_HALF;
 847         BC_ACCUM(0, yfactor+256, xfactor+256);
 848         BC_ACCUM(1, yfactor+256, xfactor+  0);
 849         BC_ACCUM(2, yfactor+256, 256-xfactor);
 850         BC_ACCUM(3, yfactor+256, 512-xfactor);
 851         BC_ACCUM(4, yfactor+  0, xfactor+256);
 852         BC_ACCUM(5, yfactor+  0, xfactor+  0);
 853         BC_ACCUM(6, yfactor+  0, 256-xfactor);
 854         BC_ACCUM(7, yfactor+  0, 512-xfactor);
 855         BC_ACCUM(8, 256-yfactor, xfactor+256);
 856         BC_ACCUM(9, 256-yfactor, xfactor+  0);
 857         BC_ACCUM(10, 256-yfactor, 256-xfactor);
 858         BC_ACCUM(11, 256-yfactor, 512-xfactor);
 859         BC_ACCUM(12, 512-yfactor, xfactor+256);
 860         BC_ACCUM(13, 512-yfactor, xfactor+  0);
 861         BC_ACCUM(14, 512-yfactor, 256-xfactor);
 862         BC_ACCUM(15, 512-yfactor, 512-xfactor);
 863         BC_STORE_COMPS(pRes);
 864         pRes++;
 865         pRGB += 16;
 866         xfract += dxfract;
 867         yfract += dyfract;
 868     }
 869 }
 870 
 871 #ifdef MAKE_STUBS
 872 
 873 static void
 874 BilinearInterpStub(jint *pRGBbase, jint numpix,
 875                    jint xfract, jint dxfract,
 876                    jint yfract, jint dyfract)
 877 {
 878     jint *pRGB = pRGBbase;
 879     while (--numpix >= 0) {
 880         *pRGBbase = *pRGB;
 881         pRGBbase += 1;
 882         pRGB += 4;
 883     }
 884 }
 885 
 886 static void
 887 BicubicInterpStub(jint *pRGBbase, jint numpix,
 888                   jint xfract, jint dxfract,
 889                   jint yfract, jint dyfract)
 890 {
 891     jint *pRGB = pRGBbase+5;
 892     while (--numpix >= 0) {
 893         *pRGBbase = *pRGB;
 894         pRGBbase += 1;
 895         pRGB += 16;
 896     }
 897 }
 898 
 899 #endif /* MAKE_STUBS */