1 /*
   2  * Copyright (c) 2008, 2010, 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 "math.h"
  27 #include "GraphicsPrimitiveMgr.h"
  28 
  29 #include "sun_java2d_loops_FillParallelogram.h"
  30 
  31 #define PGRAM_MIN_MAX(bmin, bmax, v0, dv1, dv2) \
  32     do { \
  33         double vmin, vmax; \
  34         if (dv1 < 0) { \
  35             vmin = v0+dv1; \
  36             vmax = v0; \
  37         } else { \
  38             vmin = v0; \
  39             vmax = v0+dv1; \
  40         } \
  41         if (dv2 < 0) { \
  42             vmin -= dv2; \
  43         } else { \
  44             vmax += dv2; \
  45         } \
  46         bmin = (jint) floor(vmin + 0.5); \
  47         bmax = (jint) floor(vmax + 0.5); \
  48     } while(0)
  49 
  50 #define PGRAM_INIT_X(starty, x, y, slope) \
  51     (DblToLong((x) + (slope) * ((starty)+0.5 - (y))) + LongOneHalf - 1)
  52 
  53 /*
  54  * Class:     sun_java2d_loops_FillParallelogram
  55  * Method:    FillParallelogram
  56  * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;DDDDDD)V
  57  */
  58 JNIEXPORT void JNICALL
  59 Java_sun_java2d_loops_FillParallelogram_FillParallelogram
  60     (JNIEnv *env, jobject self,
  61      jobject sg2d, jobject sData,
  62      jdouble x0, jdouble y0,
  63      jdouble dx1, jdouble dy1,
  64      jdouble dx2, jdouble dy2)
  65 {
  66     SurfaceDataOps *sdOps;
  67     SurfaceDataRasInfo rasInfo;
  68     NativePrimitive *pPrim;
  69     CompositeInfo compInfo;
  70     jint pixel;
  71     jint ix1, iy1, ix2, iy2;
  72 
  73     if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) {
  74         return;
  75     }
  76 
  77     /*
  78      * Sort parallelogram by y values, ensure that each delta vector
  79      * has a non-negative y delta, and eliminate degenerate parallelograms.
  80      */
  81     if (dy1 < 0) {
  82         x0 += dx1;  y0 += dy1;
  83         dx1 = -dx1; dy1 = -dy1;
  84     }
  85     if (dy2 < 0) {
  86         x0 += dx2;  y0 += dy2;
  87         dx2 = -dx2; dy2 = -dy2;
  88     }
  89     /* Sort delta vectors so dxy1 is left of dxy2. */
  90     if (dx1 * dy2 > dx2 * dy1) {
  91         double v = dx1; dx1 = dx2; dx2 = v;
  92                v = dy1; dy1 = dy2; dy2 = v;
  93     }
  94     PGRAM_MIN_MAX(ix1, ix2, x0, dx1, dx2);
  95     iy1 = (jint) floor(y0 + 0.5);
  96     iy2 = (jint) floor(y0 + dy1 + dy2 + 0.5);
  97 
  98     pPrim = GetNativePrim(env, self);
  99     if (pPrim == NULL) {
 100         return;
 101     }
 102     pixel = GrPrim_Sg2dGetPixel(env, sg2d);
 103     if (pPrim->pCompType->getCompInfo != NULL) {
 104         GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo);
 105     }
 106 
 107     sdOps = SurfaceData_GetOps(env, sData);
 108     if (sdOps == NULL) {
 109         return;
 110     }
 111 
 112     GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);
 113     SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2);
 114     if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 ||
 115         rasInfo.bounds.x2 <= rasInfo.bounds.x1)
 116     {
 117         return;
 118     }
 119 
 120     if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) {
 121         return;
 122     }
 123 
 124     ix1 = rasInfo.bounds.x1;
 125     iy1 = rasInfo.bounds.y1;
 126     ix2 = rasInfo.bounds.x2;
 127     iy2 = rasInfo.bounds.y2;
 128     if (ix2 > ix1 && iy2 > iy1) {
 129         sdOps->GetRasInfo(env, sdOps, &rasInfo);
 130         if (rasInfo.rasBase) {
 131             jdouble lslope = (dy1 == 0) ? 0 : dx1 / dy1;
 132             jdouble rslope = (dy2 == 0) ? 0 : dx2 / dy2;
 133             jlong ldx = DblToLong(lslope);
 134             jlong rdx = DblToLong(rslope);
 135             jint cy1, cy2, loy, hiy;
 136             dx1 += x0;
 137             dy1 += y0;
 138             dx2 += x0;
 139             dy2 += y0;
 140             cy1 = (jint) floor(dy1 + 0.5);
 141             cy2 = (jint) floor(dy2 + 0.5);
 142 
 143             /* Top triangular portion. */
 144             loy = iy1;
 145             hiy = (cy1 < cy2) ? cy1 : cy2;
 146             if (hiy > iy2) hiy = iy2;
 147             if (loy < hiy) {
 148                 jlong lx = PGRAM_INIT_X(loy, x0, y0, lslope);
 149                 jlong rx = PGRAM_INIT_X(loy, x0, y0, rslope);
 150                 (*pPrim->funcs.fillparallelogram)(&rasInfo,
 151                                                   ix1, loy, ix2, hiy,
 152                                                   lx, ldx, rx, rdx,
 153                                                   pixel, pPrim, &compInfo);
 154             }
 155 
 156             /* Middle parallelogram portion, which way does it slant? */
 157             if (cy1 < cy2) {
 158                 /* Middle parallelogram portion, slanted to right. */
 159                 /* left leg turned a corner at y0+dy1 */
 160                 /* right leg continuing on its initial trajectory from y0 */
 161                 loy = cy1;
 162                 hiy = cy2;
 163                 if (loy < iy1) loy = iy1;
 164                 if (hiy > iy2) hiy = iy2;
 165                 if (loy < hiy) {
 166                     jlong lx = PGRAM_INIT_X(loy, dx1, dy1, rslope);
 167                     jlong rx = PGRAM_INIT_X(loy,  x0,  y0, rslope);
 168                     (*pPrim->funcs.fillparallelogram)(&rasInfo,
 169                                                       ix1, loy, ix2, hiy,
 170                                                       lx, rdx, rx, rdx,
 171                                                       pixel, pPrim, &compInfo);
 172                 }
 173             } else if (cy2 < cy1) {
 174                 /* Middle parallelogram portion, slanted to left. */
 175                 /* left leg continuing on its initial trajectory from y0 */
 176                 /* right leg turned a corner at y0+dy2 */
 177                 loy = cy2;
 178                 hiy = cy1;
 179                 if (loy < iy1) loy = iy1;
 180                 if (hiy > iy2) hiy = iy2;
 181                 if (loy < hiy) {
 182                     jlong lx = PGRAM_INIT_X(loy,  x0,  y0, lslope);
 183                     jlong rx = PGRAM_INIT_X(loy, dx2, dy2, lslope);
 184                     (*pPrim->funcs.fillparallelogram)(&rasInfo,
 185                                                       ix1, loy, ix2, hiy,
 186                                                       lx, ldx, rx, ldx,
 187                                                       pixel, pPrim, &compInfo);
 188                 }
 189             }
 190 
 191             /* Bottom triangular portion. */
 192             loy = (cy1 > cy2) ? cy1 : cy2;
 193             if (loy < iy1) loy = iy1;
 194             hiy = iy2;
 195             if (loy < hiy) {
 196                 /* left leg turned its corner at y0+dy1, now moving right */
 197                 /* right leg turned its corner at y0+dy2, now moving left */
 198                 jlong lx = PGRAM_INIT_X(loy, dx1, dy1, rslope);
 199                 jlong rx = PGRAM_INIT_X(loy, dx2, dy2, lslope);
 200                 (*pPrim->funcs.fillparallelogram)(&rasInfo,
 201                                                   ix1, loy, ix2, hiy,
 202                                                   lx, rdx, rx, ldx,
 203                                                   pixel, pPrim, &compInfo);
 204             }
 205         }
 206         SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
 207     }
 208     SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
 209 }