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#include "LineUtils.h" 29#include "Trace.h" 30#include "ParallelogramUtils.h" 31 32#include "sun_java2d_loops_DrawParallelogram.h" 33 34#define HANDLE_PGRAM_EDGE(X1, Y1, X2, Y2, \ 35 pRasInfo, pixel, pPrim, pFunc, pCompInfo) \ 36 do { \ 37 jint ix1 = (jint) floor(X1); \ 38 jint ix2 = (jint) floor(X2); \ 39 jint iy1 = (jint) floor(Y1); \ 40 jint iy2 = (jint) floor(Y2); \ 41 LineUtils_ProcessLine(pRasInfo, pixel, \ 42 pFunc, pPrim, pCompInfo, \ 43 ix1, iy1, ix2, iy2, JNI_TRUE); \ 44 } while (0) 45 46typedef struct { 47 jdouble x0; 48 jdouble y0; 49 jdouble y1; 50 jdouble slope; 51 jlong dx; 52 jint ystart; 53 jint yend; 54} EdgeInfo; 55 56#define STORE_EDGE(pEDGE, X0, Y0, Y1, SLOPE, DELTAX) \ 57 do { \ 58 (pEDGE)->x0 = (X0); \ 59 (pEDGE)->y0 = (Y0); \ 60 (pEDGE)->y1 = (Y1); \ 61 (pEDGE)->slope = (SLOPE); \ 62 (pEDGE)->dx = (DELTAX); \ 63 (pEDGE)->ystart = (jint) floor((Y0) + 0.5); \ 64 (pEDGE)->yend = (jint) floor((Y1) + 0.5); \ 65 } while (0) 66 67#define STORE_PGRAM(pLTEDGE, pRTEDGE, \ 68 X0, Y0, dX1, dY1, dX2, dY2, \ 69 SLOPE1, SLOPE2, DELTAX1, DELTAX2) \ 70 do { \ 71 STORE_EDGE((pLTEDGE)+0, \ 72 (X0), (Y0), (Y0) + (dY1), \ 73 (SLOPE1), (DELTAX1)); \ 74 STORE_EDGE((pRTEDGE)+0, \ 75 (X0), (Y0), (Y0) + (dY2), \ 76 (SLOPE2), (DELTAX2)); \ 77 STORE_EDGE((pLTEDGE)+1, \ 78 (X0) + (dX1), (Y0) + (dY1), (Y0) + (dY1) + (dY2), \ 79 (SLOPE2), (DELTAX2)); \ 80 STORE_EDGE((pRTEDGE)+1, \ 81 (X0) + (dX2), (Y0) + (dY2), (Y0) + (dY1) + (dY2), \ 82 (SLOPE1), (DELTAX1)); \ 83 } while (0) 84 85/* 86 * Class: sun_java2d_loops_DrawParallelogram 87 * Method: DrawParallelogram 88 * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;DDDDDDDD)V 89 */ 90JNIEXPORT void JNICALL 91Java_sun_java2d_loops_DrawParallelogram_DrawParallelogram 92 (JNIEnv *env, jobject self, 93 jobject sg2d, jobject sData, 94 jdouble x0, jdouble y0, 95 jdouble dx1, jdouble dy1, 96 jdouble dx2, jdouble dy2, 97 jdouble lw1, jdouble lw2) 98{ 99 SurfaceDataOps *sdOps; 100 SurfaceDataRasInfo rasInfo; 101 NativePrimitive *pPrim; 102 CompositeInfo compInfo; 103 jint pixel; 104 EdgeInfo edges[8]; 105 EdgeInfo *active[4]; 106 jint ix1, iy1, ix2, iy2; 107 jdouble ldx1, ldy1, ldx2, ldy2; 108 jdouble ox0, oy0; 109 110 /* 111 * Sort parallelogram by y values, ensure that each delta vector 112 * has a non-negative y delta. 113 */ 114 SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, 115 v = lw1; lw1 = lw2; lw2 = v;); 116 117 // dx,dy for line width in the "1" and "2" directions. 118 ldx1 = dx1 * lw1; 119 ldy1 = dy1 * lw1; 120 ldx2 = dx2 * lw2; 121 ldy2 = dy2 * lw2; 122 123 // calculate origin of the outer parallelogram 124 ox0 = x0 - (ldx1 + ldx2) / 2.0; 125 oy0 = y0 - (ldy1 + ldy2) / 2.0; 126 127 PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2, JNI_FALSE); 128 iy1 = (jint) floor(oy0 + 0.5); 129 iy2 = (jint) floor(oy0 + dy1 + ldy1 + dy2 + ldy2 + 0.5); 130 131 pPrim = GetNativePrim(env, self); 132 if (pPrim == NULL) { 133 return; 134 } 135 pixel = GrPrim_Sg2dGetPixel(env, sg2d); 136 if (pPrim->pCompType->getCompInfo != NULL) { 137 GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo); 138 } 139 140 sdOps = SurfaceData_GetOps(env, sData); 141 if (sdOps == NULL) { 142 return; 143 } 144 145 GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); 146 SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2); 147 if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 || 148 rasInfo.bounds.x2 <= rasInfo.bounds.x1) 149 { 150 return; 151 } 152 153 if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) { 154 return; 155 } 156 157 ix1 = rasInfo.bounds.x1; 158 iy1 = rasInfo.bounds.y1; 159 ix2 = rasInfo.bounds.x2; 160 iy2 = rasInfo.bounds.y2; 161 if (ix2 > ix1 && iy2 > iy1) { 162 sdOps->GetRasInfo(env, sdOps, &rasInfo); 163 if (rasInfo.rasBase) { 164 jdouble lslope, rslope; 165 jlong ldx, rdx; 166 jint loy, hiy, numedges; 167 FillParallelogramFunc *pFill = 168 pPrim->funcs.drawparallelogram->fillpgram; 169 170 lslope = (dy1 == 0) ? 0 : dx1 / dy1; 171 rslope = (dy2 == 0) ? 0 : dx2 / dy2; 172 ldx = DblToLong(lslope); 173 rdx = DblToLong(rslope); 174 175 // Only need to generate 4 quads if the interior still 176 // has a hole in it (i.e. if the line width ratios were 177 // both less than 1.0) 178 if (lw1 < 1.0 && lw2 < 1.0) { 179 // If the line widths are both less than a pixel wide 180 // then we can use a drawline function instead for even 181 // more performance. 182 lw1 = sqrt(ldx1*ldx1 + ldy1*ldy1); 183 lw2 = sqrt(ldx2*ldx2 + ldy2*ldy2); 184 if (lw1 <= 1.0001 && lw2 <= 1.0001) { 185 jdouble x3, y3; 186 DrawLineFunc *pLine = 187 pPrim->funcs.drawparallelogram->drawline; 188 189 x3 = (dx1 += x0); 190 y3 = (dy1 += y0); 191 x3 += dx2; 192 y3 += dy2; 193 dx2 += x0; 194 dy2 += y0; 195 196 HANDLE_PGRAM_EDGE( x0, y0, dx1, dy1, 197 &rasInfo, pixel, pPrim, pLine, &compInfo); 198 HANDLE_PGRAM_EDGE(dx1, dy1, x3, y3, 199 &rasInfo, pixel, pPrim, pLine, &compInfo); 200 HANDLE_PGRAM_EDGE( x3, y3, dx2, dy2, 201 &rasInfo, pixel, pPrim, pLine, &compInfo); 202 HANDLE_PGRAM_EDGE(dx2, dy2, x0, y0, 203 &rasInfo, pixel, pPrim, pLine, &compInfo); 204 SurfaceData_InvokeRelease(env, sdOps, &rasInfo); 205 SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); 206 return; 207 } 208 209 // To simplify the edge management below we presort the 210 // inner and outer edges so that they are globally sorted 211 // from left to right. If you scan across the array of 212 // edges for a given Y range then the edges you encounter 213 // will be sorted in X as well. 214 // If AB are left top and bottom edges of outer parallelogram, 215 // and CD are the right pair of edges, and abcd are the 216 // corresponding inner parallelogram edges then we want them 217 // sorted as ABabcdCD to ensure this horizontal ordering. 218 // Conceptually it is like 2 pairs of nested parentheses. 219 STORE_PGRAM(edges + 2, edges + 4, 220 ox0 + ldx1 + ldx2, oy0 + ldy1 + ldy2, 221 dx1 - ldx1, dy1 - ldy1, 222 dx2 - ldx2, dy2 - ldy2, 223 lslope, rslope, ldx, rdx); 224 numedges = 8; 225 } else { 226 // The line width ratios were large enough to consume 227 // the entire hole in the middle of the parallelogram 228 // so we can just issue one large quad for the outer 229 // parallelogram. 230 numedges = 4; 231 } 232 233 // The outer parallelogram always goes in the first two 234 // and last two entries in the array so we either have 235 // ABabcdCD ordering for 8 edges or ABCD ordering for 4 236 // edges. See comment above where we store the inner 237 // parallelogram for a more complete description. 238 STORE_PGRAM(edges + 0, edges + numedges-2, 239 ox0, oy0, 240 dx1 + ldx1, dy1 + ldy1, 241 dx2 + ldx2, dy2 + ldy2, 242 lslope, rslope, ldx, rdx); 243 244 loy = edges[0].ystart; 245 if (loy < iy1) loy = iy1; 246 while (loy < iy2) { 247 jint numactive = 0; 248 jint cur; 249 250 hiy = iy2; 251 // Maintaining a sorted edge list is probably overkill for 252 // 4 or 8 edges. The indices chosen above for storing the 253 // inner and outer left and right edges already guarantee 254 // left to right ordering so we just need to scan for edges 255 // that overlap the current Y range (and also determine the 256 // maximum Y value for which the range is valid). 257 for (cur = 0; cur < numedges; cur++) { 258 EdgeInfo *pEdge = &edges[cur]; 259 jint yend = pEdge->yend; 260 if (loy < yend) { 261 // This edge is still in play, have we reached it yet? 262 jint ystart = pEdge->ystart; 263 if (loy < ystart) { 264 // This edge is not active (yet) 265 // Stop before we get to the top of it 266 if (hiy > ystart) hiy = ystart; 267 } else { 268 // This edge is active, store it 269 active[numactive++] = pEdge; 270 // And stop when we get to the bottom of it 271 if (hiy > yend) hiy = yend; 272 } 273 } 274 } 275#ifdef DEBUG 276 if ((numactive & 1) != 0) { 277 J2dTraceLn1(J2D_TRACE_ERROR, 278 "DrawParallelogram: " 279 "ODD NUMBER OF PGRAM EDGES (%d)!!", 280 numactive); 281 } 282#endif 283 for (cur = 0; cur < numactive; cur += 2) { 284 EdgeInfo *pLeft = active[cur+0]; 285 EdgeInfo *pRight = active[cur+1]; 286 jlong lx = PGRAM_INIT_X(loy, 287 pLeft->x0, pLeft->y0, 288 pLeft->slope); 289 jlong rx = PGRAM_INIT_X(loy, 290 pRight->x0, pRight->y0, 291 pRight->slope); 292 (*pFill)(&rasInfo, 293 ix1, loy, ix2, hiy, 294 lx, pLeft->dx, 295 rx, pRight->dx, 296 pixel, pPrim, &compInfo); 297 } 298 loy = hiy; 299 } 300 } 301 SurfaceData_InvokeRelease(env, sdOps, &rasInfo); 302 } 303 SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); 304} 305