| 1 | /* |
| 2 | * Copyright (c) 2000, 2013, 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 <stdlib.h> |
| 28 | #include <string.h> |
| 29 | #include "GraphicsPrimitiveMgr.h" |
| 30 | #include "ParallelogramUtils.h" |
| 31 | |
| 32 | #include "sun_java2d_loops_MaskFill.h" |
| 33 | |
| 34 | /* |
| 35 | * Class: sun_java2d_loops_MaskFill |
| 36 | * Method: MaskFill |
| 37 | * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;IIII[BII)V |
| 38 | */ |
| 39 | JNIEXPORT void JNICALL |
| 40 | Java_sun_java2d_loops_MaskFill_MaskFill |
| 41 | (JNIEnv *env, jobject self, |
| 42 | jobject sg2d, jobject sData, jobject comp, |
| 43 | jint x, jint y, jint w, jint h, |
| 44 | jbyteArray maskArray, jint maskoff, jint maskscan) |
| 45 | { |
| 46 | SurfaceDataOps *sdOps; |
| 47 | SurfaceDataRasInfo rasInfo; |
| 48 | NativePrimitive *pPrim; |
| 49 | CompositeInfo compInfo; |
| 50 | |
| 51 | pPrim = GetNativePrim(env, self); |
| 52 | if (pPrim == NULL) { |
| 53 | return; |
| 54 | } |
| 55 | if (pPrim->pCompType->getCompInfo != NULL) { |
| 56 | (*pPrim->pCompType->getCompInfo)(env, &compInfo, comp); |
| 57 | } |
| 58 | |
| 59 | sdOps = SurfaceData_GetOps(env, sData); |
| 60 | if (sdOps == 0) { |
| 61 | return; |
| 62 | } |
| 63 | |
| 64 | rasInfo.bounds.x1 = x; |
| 65 | rasInfo.bounds.y1 = y; |
| 66 | rasInfo.bounds.x2 = x + w; |
| 67 | rasInfo.bounds.y2 = y + h; |
| 68 | if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) { |
| 69 | return; |
| 70 | } |
| 71 | |
| 72 | if (rasInfo.bounds.x2 > rasInfo.bounds.x1 && |
| 73 | rasInfo.bounds.y2 > rasInfo.bounds.y1) |
| 74 | { |
| 75 | jint color = GrPrim_Sg2dGetEaRGB(env, sg2d); |
| 76 | sdOps->GetRasInfo(env, sdOps, &rasInfo); |
| 77 | if (rasInfo.rasBase) { |
| 78 | jint width = rasInfo.bounds.x2 - rasInfo.bounds.x1; |
| 79 | jint height = rasInfo.bounds.y2 - rasInfo.bounds.y1; |
| 80 | void *pDst = PtrCoord(rasInfo.rasBase, |
| 81 | rasInfo.bounds.x1, rasInfo.pixelStride, |
| 82 | rasInfo.bounds.y1, rasInfo.scanStride); |
| 83 | unsigned char *pMask = |
| 84 | (maskArray |
| 85 | ? (*env)->GetPrimitiveArrayCritical(env, maskArray, 0) |
| 86 | : 0); |
| 87 | if (maskArray != NULL && pMask == NULL) { |
| 88 | SurfaceData_InvokeRelease(env, sdOps, &rasInfo); |
| 89 | SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); |
| 90 | return; |
| 91 | } |
| 92 | maskoff += ((rasInfo.bounds.y1 - y) * maskscan + |
| 93 | (rasInfo.bounds.x1 - x)); |
| 94 | (*pPrim->funcs.maskfill)(pDst, |
| 95 | pMask, maskoff, maskscan, |
| 96 | width, height, |
| 97 | color, &rasInfo, |
| 98 | pPrim, &compInfo); |
| 99 | if (pMask) { |
| 100 | (*env)->ReleasePrimitiveArrayCritical(env, maskArray, |
| 101 | pMask, JNI_ABORT); |
| 102 | } |
| 103 | } |
| 104 | SurfaceData_InvokeRelease(env, sdOps, &rasInfo); |
| 105 | } |
| 106 | SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); |
| 107 | } |
| 108 | |
| 109 | #define MASK_BUF_LEN 1024 |
| 110 | |
| 111 | #define DblToMask(v) ((unsigned char) ((v)*255.9999)) |
| 112 | |
| 113 | /* Fills an aligned rectangle with potentially translucent edges. */ |
| 114 | static void |
| 115 | fillAARect(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo, |
| 116 | CompositeInfo *pCompInfo, jint color, unsigned char *pMask, |
| 117 | void *pDst, |
| 118 | jdouble x1, jdouble y1, jdouble x2, jdouble y2) |
| 119 | { |
| 120 | jint cx1 = pRasInfo->bounds.x1; |
| 121 | jint cy1 = pRasInfo->bounds.y1; |
| 122 | jint cx2 = pRasInfo->bounds.x2; |
| 123 | jint cy2 = pRasInfo->bounds.y2; |
| 124 | jint rx1 = (jint) ceil(x1); |
| 125 | jint ry1 = (jint) ceil(y1); |
| 126 | jint rx2 = (jint) floor(x2); |
| 127 | jint ry2 = (jint) floor(y2); |
| 128 | jint width = cx2 - cx1; |
| 129 | jint scan = pRasInfo->scanStride; |
| 130 | /* Convert xy12 into the edge coverage fractions for those edges. */ |
| 131 | x1 = rx1-x1; |
| 132 | y1 = ry1-y1; |
| 133 | x2 = x2-rx2; |
| 134 | y2 = y2-ry2; |
| 135 | if (ry2 < ry1) { |
| 136 | /* Accumulate bottom coverage into top coverage. */ |
| 137 | y1 = y1 + y2 - 1.0; |
| 138 | /* prevent processing of "bottom fractional row" */ |
| 139 | ry2 = cy2; |
| 140 | } |
| 141 | if (rx2 < rx1) { |
| 142 | /* Accumulate right coverage into left coverage. */ |
| 143 | x1 = x1 + x2 - 1.0; |
| 144 | /* prevent processing of "right fractional column" */ |
| 145 | rx2 = cx2; |
| 146 | } |
| 147 | /* Check for a visible "top fractional row" and process it */ |
| 148 | if (cy1 < ry1) { |
| 149 | unsigned char midcov = DblToMask(y1); |
| 150 | jint x; |
| 151 | for (x = 0; x < width; x++) { |
| 152 | pMask[x] = midcov; |
| 153 | } |
| 154 | if (cx1 < rx1) { |
| 155 | pMask[0] = DblToMask(y1 * x1); |
| 156 | } |
| 157 | if (cx2 > rx2) { |
| 158 | pMask[width-1] = DblToMask(y1 * x2); |
| 159 | } |
| 160 | (*pPrim->funcs.maskfill)(pDst, |
| 161 | pMask, 0, 0, |
| 162 | width, 1, |
| 163 | color, pRasInfo, |
| 164 | pPrim, pCompInfo); |
| 165 | pDst = PtrAddBytes(pDst, scan); |
| 166 | cy1++; |
| 167 | } |
| 168 | /* Check for a visible "left fract, solid middle, right fract" section. */ |
| 169 | if (cy1 < ry2 && cy1 < cy2) { |
| 170 | jint midh = ((ry2 < cy2) ? ry2 : cy2) - cy1; |
| 171 | jint midx = cx1; |
| 172 | void *pMid = pDst; |
| 173 | /* First process the left "fractional column" if it is visible. */ |
| 174 | if (midx < rx1) { |
| 175 | pMask[0] = DblToMask(x1); |
| 176 | /* Note: maskscan == 0 means we reuse this value for every row. */ |
| 177 | (*pPrim->funcs.maskfill)(pMid, |
| 178 | pMask, 0, 0, |
| 179 | 1, midh, |
| 180 | color, pRasInfo, |
| 181 | pPrim, pCompInfo); |
| 182 | pMid = PtrAddBytes(pMid, pRasInfo->pixelStride); |
| 183 | midx++; |
| 184 | } |
| 185 | /* Process the central solid section if it is visible. */ |
| 186 | if (midx < rx2 && midx < cx2) { |
| 187 | jint midw = ((rx2 < cx2) ? rx2 : cx2) - midx; |
| 188 | /* A NULL mask buffer means "all coverages are 0xff" */ |
| 189 | (*pPrim->funcs.maskfill)(pMid, |
| 190 | NULL, 0, 0, |
| 191 | midw, midh, |
| 192 | color, pRasInfo, |
| 193 | pPrim, pCompInfo); |
| 194 | pMid = PtrCoord(pMid, midw, pRasInfo->pixelStride, 0, 0); |
| 195 | midx += midw; |
| 196 | } |
| 197 | /* Finally process the right "fractional column" if it is visible. */ |
| 198 | if (midx < cx2) { |
| 199 | pMask[0] = DblToMask(x2); |
| 200 | /* Note: maskscan == 0 means we reuse this value for every row. */ |
| 201 | (*pPrim->funcs.maskfill)(pMid, |
| 202 | pMask, 0, 0, |
| 203 | 1, midh, |
| 204 | color, pRasInfo, |
| 205 | pPrim, pCompInfo); |
| 206 | } |
| 207 | cy1 += midh; |
| 208 | pDst = PtrCoord(pDst, 0, 0, midh, scan); |
| 209 | } |
| 210 | /* Check for a visible "bottom fractional row" and process it */ |
| 211 | if (cy1 < cy2) { |
| 212 | unsigned char midcov = DblToMask(y2); |
| 213 | jint x; |
| 214 | for (x = 0; x < width; x++) { |
| 215 | pMask[x] = midcov; |
| 216 | } |
| 217 | if (cx1 < rx1) { |
| 218 | pMask[0] = DblToMask(y2 * x1); |
| 219 | } |
| 220 | if (cx2 > rx2) { |
| 221 | pMask[width-1] = DblToMask(y2 * x2); |
| 222 | } |
| 223 | (*pPrim->funcs.maskfill)(pDst, |
| 224 | pMask, 0, 0, |
| 225 | width, 1, |
| 226 | color, pRasInfo, |
| 227 | pPrim, pCompInfo); |
| 228 | } |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 | * Support code for arbitrary tracing and MaskFill filling of |
| 233 | * non-rectilinear (diagonal) parallelograms. |
| 234 | * |
| 235 | * This code is based upon the following model of AA coverage. |
| 236 | * |
| 237 | * Each edge of a parallelogram (for fillPgram) or a double |
| 238 | * parallelogram (inner and outer parallelograms for drawPgram) |
| 239 | * can be rasterized independently because the geometry is well |
| 240 | * defined in such a way that none of the sides will ever cross |
| 241 | * each other and they have a fixed ordering that is fairly |
| 242 | * well predetermined. |
| 243 | * |
| 244 | * So, for each edge we will look at the diagonal line that |
| 245 | * the edge makes as it passes through a row of pixels. Some |
| 246 | * such diagonal lines may pass entirely through the row of |
| 247 | * pixels in a single pixel column. Some may cut across the |
| 248 | * row and pass through several pixel columns before they pass |
| 249 | * on to the next row. |
| 250 | * |
| 251 | * As the edge passes through the row of pixels it will affect |
| 252 | * the coverage of the pixels it passes through as well as all |
| 253 | * of the pixels to the right of the edge. The coverage will |
| 254 | * either be increased (by a left edge of a parallelogram) or |
| 255 | * decreased (by a right edge) for all pixels to the right, until |
| 256 | * another edge passing the opposite direction is encountered. |
| 257 | * |
| 258 | * The coverage added or subtracted by an edge as it crosses a |
| 259 | * given pixel is calculated using a trapezoid formula in the |
| 260 | * following manner: |
| 261 | * |
| 262 | * / |
| 263 | * +-----+---/-+-----+ |
| 264 | * | | / | | |
| 265 | * | | / | | |
| 266 | * +-----+/----+-----+ |
| 267 | * / |
| 268 | * |
| 269 | * The area to the right of that edge for the pixel where it |
| 270 | * crosses is given as: |
| 271 | * |
| 272 | * trapheight * (topedge + bottomedge)/2 |
| 273 | * |
| 274 | * Another thing to note is that the above formula gives the |
| 275 | * contribution of that edge to the given pixel where it crossed, |
| 276 | * but in so crossing the pixel row, it also created 100% coverage |
| 277 | * for all of the pixels to the right. |
| 278 | * |
| 279 | * This example was simplified in that the edge depicted crossed |
| 280 | * the complete pixel row and it did so entirely within the bounds |
| 281 | * of a single pixel column. In practice, many edges may start or |
| 282 | * end in a given row and thus provide only partial row coverage |
| 283 | * (i.e. the total "trapheight" in the formula never reaches 1.0). |
| 284 | * And in other cases, edges may travel sideways through several |
| 285 | * pixel columns on a given pixel row from where they enter it to |
| 286 | * where the leave it (which also mans that the trapheight for a |
| 287 | * given pixel will be less than 1.0, but by the time the edge |
| 288 | * completes its journey through the pixel row the "coverage shadow" |
| 289 | * that it casts on all pixels to the right eventually reaches 100%). |
| 290 | * |
| 291 | * In order to simplify the calculations so that we don't have to |
| 292 | * keep propagating coverages we calculate for one edge "until we |
| 293 | * reach another edge" we will process one edge at a time and |
| 294 | * simply record in a buffer the amount that an edge added to |
| 295 | * or subtracted from the coverage for a given pixel and its |
| 296 | * following right-side neighbors. Thus, the true total coverage |
| 297 | * of a given pixel is only determined by summing the deltas for |
| 298 | * that pixel and all of the pixels to its left. Since we already |
| 299 | * have to scan the buffer to change floating point coverages into |
| 300 | * mask values for a MaskFill loop, it is simple enough to sum the |
| 301 | * values as we perform that scan from left to right. |
| 302 | * |
| 303 | * In the above example, note that 2 deltas need to be recorded even |
| 304 | * though the edge only intersected a single pixel. The delta recorded |
| 305 | * for the pixel where the edge crossed will be approximately 55% |
| 306 | * (guesstimating by examining the poor ascii art) which is fine for |
| 307 | * determining how to render that pixel, but the rest of the pixels |
| 308 | * to its right should have their coverage modified by a full 100% |
| 309 | * and the 55% delta value we recorded for the pixel that the edge |
| 310 | * crossed will not get them there. We adjust for this by adding |
| 311 | * the "remainder" of the coverage implied by the shadow to the |
| 312 | * pixel immediately to the right of where we record a trapezoidal |
| 313 | * contribution. In this case a delta of 45% will be recorded in |
| 314 | * the pixel immediately to the right to raise the total to 100%. |
| 315 | * |
| 316 | * As we sum these delta values as we process the line from left |
| 317 | * to right, these delta values will typically drive the sum from |
| 318 | * 0% up to 100% and back down to 0% over the course of a single |
| 319 | * pixel row. In the case of a drawn (double) parallelogram the |
| 320 | * sum will go to 100% and back to 0% twice on most scanlines. |
| 321 | * |
| 322 | * The fillAAPgram and drawAAPgram functions drive the main flow |
| 323 | * of the algorithm with help from the following structures, |
| 324 | * macros, and functions. It is probably best to start with |
| 325 | * those 2 functions to gain an understanding of the algorithm. |
| 326 | */ |
| 327 | typedef struct { |
| 328 | jdouble x; |
| 329 | jdouble y; |
| 330 | jdouble xbot; |
| 331 | jdouble ybot; |
| 332 | jdouble xnexty; |
| 333 | jdouble ynextx; |
| 334 | jdouble xnextx; |
| 335 | jdouble linedx; |
| 336 | jdouble celldx; |
| 337 | jdouble celldy; |
| 338 | jboolean isTrailing; |
| 339 | } EdgeInfo; |
| 340 | |
| 341 | #define MIN_DELTA (1.0/256.0) |
| 342 | |
| 343 | /* |
| 344 | * Calculates slopes and deltas for an edge and stores results in an EdgeInfo. |
| 345 | * Returns true if the edge was valid (i.e. not ignored for some reason). |
| 346 | */ |
| 347 | static jboolean |
| 348 | storeEdge(EdgeInfo *pEdge, |
| 349 | jdouble x, jdouble y, jdouble dx, jdouble dy, |
| 350 | jint cx1, jint cy1, jint cx2, jint cy2, |
| 351 | jboolean isTrailing) |
| 352 | { |
| 353 | jdouble xbot = x + dx; |
| 354 | jdouble ybot = y + dy; |
| 355 | jboolean ret; |
| 356 | |
| 357 | pEdge->x = x; |
| 358 | pEdge->y = y; |
| 359 | pEdge->xbot = xbot; |
| 360 | pEdge->ybot = ybot; |
| 361 | |
| 362 | /* Note that parallelograms are sorted so dy is always non-negative */ |
| 363 | if (dy > MIN_DELTA && /* NaN and horizontal protection */ |
| 364 | ybot > cy1 && /* NaN and "OUT_ABOVE" protection */ |
| 365 | y < cy2 && /* NaN and "OUT_BELOW" protection */ |
| 366 | xbot == xbot && /* NaN protection */ |
| 367 | (x < cx2 || xbot < cx2)) /* "OUT_RIGHT" protection */ |
| 368 | /* Note: "OUT_LEFT" segments may still contribute coverage... */ |
| 369 | { |
| 370 | /* no NaNs, dy is not horizontal, and segment contributes to clip */ |
| 371 | if (dx < -MIN_DELTA || dx > MIN_DELTA) { |
| 372 | /* dx is not vertical */ |
| 373 | jdouble linedx; |
| 374 | jdouble celldy; |
| 375 | jdouble nextx; |
| 376 | |
| 377 | linedx = dx / dy; |
| 378 | celldy = dy / dx; |
| 379 | if (y < cy1) { |
| 380 | pEdge->x = x = x + (cy1 - y) * linedx; |
| 381 | pEdge->y = y = cy1; |
| 382 | } |
| 383 | pEdge->linedx = linedx; |
| 384 | if (dx < 0) { |
| 385 | pEdge->celldx = -1.0; |
| 386 | pEdge->celldy = -celldy; |
| 387 | pEdge->xnextx = nextx = ceil(x) - 1.0; |
| 388 | } else { |
| 389 | pEdge->celldx = +1.0; |
| 390 | pEdge->celldy = celldy; |
| 391 | pEdge->xnextx = nextx = floor(x) + 1.0; |
| 392 | } |
| 393 | pEdge->ynextx = y + (nextx - x) * celldy; |
| 394 | pEdge->xnexty = x + ((floor(y) + 1) - y) * linedx; |
| 395 | } else { |
| 396 | /* dx is essentially vertical */ |
| 397 | if (y < cy1) { |
| 398 | pEdge->y = y = cy1; |
| 399 | } |
| 400 | pEdge->xbot = x; |
| 401 | pEdge->linedx = 0.0; |
| 402 | pEdge->celldx = 0.0; |
| 403 | pEdge->celldy = 1.0; |
| 404 | pEdge->xnextx = x; |
| 405 | pEdge->xnexty = x; |
| 406 | pEdge->ynextx = ybot; |
| 407 | } |
| 408 | ret = JNI_TRUE; |
| 409 | } else { |
| 410 | /* There is some reason to ignore this segment, "celldy=0" omits it */ |
| 411 | pEdge->ybot = y; |
| 412 | pEdge->linedx = dx; |
| 413 | pEdge->celldx = dx; |
| 414 | pEdge->celldy = 0.0; |
| 415 | pEdge->xnextx = xbot; |
| 416 | pEdge->xnexty = xbot; |
| 417 | pEdge->ynextx = y; |
| 418 | ret = JNI_FALSE; |
| 419 | } |
| 420 | pEdge->isTrailing = isTrailing; |
| 421 | return ret; |
| 422 | } |
| 423 | |
| 424 | /* |
| 425 | * Calculates and stores slopes and deltas for all edges of a parallelogram. |
| 426 | * Returns true if at least 1 edge was valid (i.e. not ignored for some reason). |
| 427 | * |
| 428 | * The inverted flag is true for an outer parallelogram (left and right |
| 429 | * edges are leading and trailing) and false for an inner parallelogram |
| 430 | * (where the left edge is trailing and the right edge is leading). |
| 431 | */ |
| 432 | static jboolean |
| 433 | storePgram(EdgeInfo *pLeftEdge, EdgeInfo *pRightEdge, |
| 434 | jdouble x, jdouble y, |
| 435 | jdouble dx1, jdouble dy1, |
| 436 | jdouble dx2, jdouble dy2, |
| 437 | jint cx1, jint cy1, jint cx2, jint cy2, |
| 438 | jboolean inverted) |
| 439 | { |
| 440 | jboolean ret = JNI_FALSE; |
| 441 | ret = (storeEdge(pLeftEdge + 0, |
| 442 | x , y , dx1, dy1, |
| 443 | cx1, cy1, cx2, cy2, inverted) || ret); |
| 444 | ret = (storeEdge(pLeftEdge + 1, |
| 445 | x+dx1, y+dy1, dx2, dy2, |
| 446 | cx1, cy1, cx2, cy2, inverted) || ret); |
| 447 | ret = (storeEdge(pRightEdge + 0, |
| 448 | x , y , dx2, dy2, |
| 449 | cx1, cy1, cx2, cy2, !inverted) || ret); |
| 450 | ret = (storeEdge(pRightEdge + 1, |
| 451 | x+dx2, y+dy2, dx1, dy1, |
| 452 | cx1, cy1, cx2, cy2, !inverted) || ret); |
| 453 | return ret; |
| 454 | } |
| 455 | |
| 456 | /* |
| 457 | * The X0,Y0,X1,Y1 values represent a trapezoidal fragment whose |
| 458 | * coverage must be accounted for in the accum buffer. |
| 459 | * |
| 460 | * All four values are assumed to fall within (or on the edge of) |
| 461 | * a single pixel. |
| 462 | * |
| 463 | * The trapezoid area is accumulated into the proper element of |
| 464 | * the accum buffer and the remainder of the "slice height" is |
| 465 | * accumulated into the element to its right. |
| 466 | */ |
| 467 | #define INSERT_ACCUM(pACCUM, IMIN, IMAX, X0, Y0, X1, Y1, CX1, CX2, MULT) \ |
| 468 | do { \ |
| 469 | jdouble xmid = ((X0) + (X1)) * 0.5; \ |
| 470 | if (xmid <= (CX2)) { \ |
| 471 | jdouble sliceh = ((Y1) - (Y0)); \ |
| 472 | jdouble slicearea; \ |
| 473 | jint i; \ |
| 474 | if (xmid < (CX1)) { \ |
| 475 | /* Accumulate the entire slice height into accum[0]. */ \ |
| 476 | i = 0; \ |
| 477 | slicearea = sliceh; \ |
| 478 | } else { \ |
| 479 | jdouble xpos = floor(xmid); \ |
| 480 | i = ((jint) xpos) - (CX1); \ |
| 481 | slicearea = (xpos+1-xmid) * sliceh; \ |
| 482 | } \ |
| 483 | if (IMIN > i) { \ |
| 484 | IMIN = i; \ |
| 485 | } \ |
| 486 | (pACCUM)[i++] += (jfloat) ((MULT) * slicearea); \ |
| 487 | (pACCUM)[i++] += (jfloat) ((MULT) * (sliceh - slicearea)); \ |
| 488 | if (IMAX < i) { \ |
| 489 | IMAX = i; \ |
| 490 | } \ |
| 491 | } \ |
| 492 | } while (0) |
| 493 | |
| 494 | /* |
| 495 | * Accumulate the contributions for a given edge crossing a given |
| 496 | * scan line into the corresponding entries of the accum buffer. |
| 497 | * CY1 is the Y coordinate of the top edge of the scanline and CY2 |
| 498 | * is equal to (CY1 + 1) and is the Y coordinate of the bottom edge |
| 499 | * of the scanline. CX1 and CX2 are the left and right edges of the |
| 500 | * clip (or area of interest) being rendered. |
| 501 | * |
| 502 | * The edge is processed from the top edge to the bottom edge and |
| 503 | * a single pixel column at a time. |
| 504 | */ |
| 505 | #define ACCUM_EDGE(pEDGE, pACCUM, IMIN, IMAX, CX1, CY1, CX2, CY2) \ |
| 506 | do { \ |
| 507 | jdouble x, y, xnext, ynext, xlast, ylast, dx, dy, mult; \ |
| 508 | y = (pEDGE)->y; \ |
| 509 | dy = (pEDGE)->celldy; \ |
| 510 | ylast = (pEDGE)->ybot; \ |
| 511 | if (ylast <= (CY1) || y >= (CY2) || dy == 0.0) { \ |
| 512 | break; \ |
| 513 | } \ |
| 514 | x = (pEDGE)->x; \ |
| 515 | dx = (pEDGE)->celldx; \ |
| 516 | if (ylast > (CY2)) { \ |
| 517 | ylast = (CY2); \ |
| 518 | xlast = (pEDGE)->xnexty; \ |
| 519 | } else { \ |
| 520 | xlast = (pEDGE)->xbot; \ |
| 521 | } \ |
| 522 | xnext = (pEDGE)->xnextx; \ |
| 523 | ynext = (pEDGE)->ynextx; \ |
| 524 | mult = ((pEDGE)->isTrailing) ? -1.0 : 1.0; \ |
| 525 | while (ynext <= ylast) { \ |
| 526 | INSERT_ACCUM(pACCUM, IMIN, IMAX, \ |
| 527 | x, y, xnext, ynext, \ |
| 528 | CX1, CX2, mult); \ |
| 529 | x = xnext; \ |
| 530 | y = ynext; \ |
| 531 | xnext += dx; \ |
| 532 | ynext += dy; \ |
| 533 | } \ |
| 534 | (pEDGE)->ynextx = ynext; \ |
| 535 | (pEDGE)->xnextx = xnext; \ |
| 536 | INSERT_ACCUM(pACCUM, IMIN, IMAX, \ |
| 537 | x, y, xlast, ylast, \ |
| 538 | CX1, CX2, mult); \ |
| 539 | (pEDGE)->x = xlast; \ |
| 540 | (pEDGE)->y = ylast; \ |
| 541 | (pEDGE)->xnexty = xlast + (pEDGE)->linedx; \ |
| 542 | } while(0) |
| 543 | |
| 544 | /* Main function to fill a single Parallelogram */ |
| 545 | static void |
| 546 | fillAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo, |
| 547 | CompositeInfo *pCompInfo, jint color, unsigned char *pMask, |
| 548 | void *pDst, |
| 549 | jdouble x1, jdouble y1, |
| 550 | jdouble dx1, jdouble dy1, |
| 551 | jdouble dx2, jdouble dy2) |
| 552 | { |
| 553 | jint cx1 = pRasInfo->bounds.x1; |
| 554 | jint cy1 = pRasInfo->bounds.y1; |
| 555 | jint cx2 = pRasInfo->bounds.x2; |
| 556 | jint cy2 = pRasInfo->bounds.y2; |
| 557 | jint width = cx2 - cx1; |
| 558 | EdgeInfo edges[4]; |
| 559 | jfloat localaccum[MASK_BUF_LEN + 1]; |
| 560 | jfloat *pAccum; |
| 561 | |
| 562 | if (!storePgram(edges + 0, edges + 2, |
| 563 | x1, y1, dx1, dy1, dx2, dy2, |
| 564 | cx1, cy1, cx2, cy2, |
| 565 | JNI_FALSE)) |
| 566 | { |
| 567 | return; |
| 568 | } |
| 569 | |
| 570 | pAccum = ((width > MASK_BUF_LEN) |
| 571 | ? malloc((width + 1) * sizeof(jfloat)) |
| 572 | : localaccum); |
| 573 | if (pAccum == NULL) { |
| 574 | return; |
| 575 | } |
| 576 | memset(pAccum, 0, (width+1) * sizeof(jfloat)); |
| 577 | |
| 578 | while (cy1 < cy2) { |
| 579 | jint lmin, lmax, rmin, rmax; |
| 580 | jint moff, x; |
| 581 | jdouble accum; |
| 582 | unsigned char lastcov; |
| 583 | |
| 584 | lmin = rmin = width + 2; |
| 585 | lmax = rmax = 0; |
| 586 | ACCUM_EDGE(&edges[0], pAccum, lmin, lmax, |
| 587 | cx1, cy1, cx2, cy1+1); |
| 588 | ACCUM_EDGE(&edges[1], pAccum, lmin, lmax, |
| 589 | cx1, cy1, cx2, cy1+1); |
| 590 | ACCUM_EDGE(&edges[2], pAccum, rmin, rmax, |
| 591 | cx1, cy1, cx2, cy1+1); |
| 592 | ACCUM_EDGE(&edges[3], pAccum, rmin, rmax, |
| 593 | cx1, cy1, cx2, cy1+1); |
| 594 | if (lmax > width) { |
| 595 | lmax = width; /* Extra col has data we do not need. */ |
| 596 | } |
| 597 | if (rmax > width) { |
| 598 | rmax = width; /* Extra col has data we do not need. */ |
| 599 | } |
| 600 | /* If ranges overlap, handle both in the first pass. */ |
| 601 | if (rmin <= lmax) { |
| 602 | lmax = rmax; |
| 603 | } |
| 604 | |
| 605 | x = lmin; |
| 606 | accum = 0.0; |
| 607 | moff = 0; |
| 608 | lastcov = 0; |
| 609 | while (x < lmax) { |
| 610 | accum += pAccum[x]; |
| 611 | pAccum[x] = 0.0f; |
| 612 | pMask[moff++] = lastcov = DblToMask(accum); |
| 613 | x++; |
| 614 | } |
| 615 | /* Check for a solid center section. */ |
| 616 | if (lastcov == 0xFF) { |
| 617 | jint endx; |
| 618 | void *pRow; |
| 619 | |
| 620 | /* First process the existing partial coverage data. */ |
| 621 | if (moff > 0) { |
| 622 | pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0); |
| 623 | (*pPrim->funcs.maskfill)(pRow, |
| 624 | pMask, 0, 0, |
| 625 | moff, 1, |
| 626 | color, pRasInfo, |
| 627 | pPrim, pCompInfo); |
| 628 | moff = 0; |
| 629 | } |
| 630 | |
| 631 | /* Where does the center section end? */ |
| 632 | /* If there is no right AA edge in the accum buffer, then */ |
| 633 | /* the right edge was beyond the clip, so fill out to width */ |
| 634 | endx = (rmin < rmax) ? rmin : width; |
| 635 | if (x < endx) { |
| 636 | pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0); |
| 637 | (*pPrim->funcs.maskfill)(pRow, |
| 638 | NULL, 0, 0, |
| 639 | endx - x, 1, |
| 640 | color, pRasInfo, |
| 641 | pPrim, pCompInfo); |
| 642 | x = endx; |
| 643 | } |
| 644 | } else if (lastcov > 0 && rmin >= rmax) { |
| 645 | /* We are not at 0 coverage, but there is no right edge, */ |
| 646 | /* force a right edge so we process pixels out to width. */ |
| 647 | rmax = width; |
| 648 | } |
| 649 | /* The following loop will process the right AA edge and/or any */ |
| 650 | /* partial coverage center section not processed above. */ |
| 651 | while (x < rmax) { |
| 652 | accum += pAccum[x]; |
| 653 | pAccum[x] = 0.0f; |
| 654 | pMask[moff++] = DblToMask(accum); |
| 655 | x++; |
| 656 | } |
| 657 | if (moff > 0) { |
| 658 | void *pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0); |
| 659 | (*pPrim->funcs.maskfill)(pRow, |
| 660 | pMask, 0, 0, |
| 661 | moff, 1, |
| 662 | color, pRasInfo, |
| 663 | pPrim, pCompInfo); |
| 664 | } |
| 665 | pDst = PtrAddBytes(pDst, pRasInfo->scanStride); |
| 666 | cy1++; |
| 667 | } |
| 668 | if (pAccum != localaccum) { |
| 669 | free(pAccum); |
| 670 | } |
| 671 | } |
| 672 | |
| 673 | /* |
| 674 | * Class: sun_java2d_loops_MaskFill |
| 675 | * Method: FillAAPgram |
| 676 | * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;DDDDDD)V |
| 677 | */ |
| 678 | JNIEXPORT void JNICALL |
| 679 | Java_sun_java2d_loops_MaskFill_FillAAPgram |
| 680 | (JNIEnv *env, jobject self, |
| 681 | jobject sg2d, jobject sData, jobject comp, |
| 682 | jdouble x0, jdouble y0, |
| 683 | jdouble dx1, jdouble dy1, |
| 684 | jdouble dx2, jdouble dy2) |
| 685 | { |
| 686 | SurfaceDataOps *sdOps; |
| 687 | SurfaceDataRasInfo rasInfo; |
| 688 | NativePrimitive *pPrim; |
| 689 | CompositeInfo compInfo; |
| 690 | jint ix1, iy1, ix2, iy2; |
| 691 | |
| 692 | if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) { |
| 693 | return; |
| 694 | } |
| 695 | |
| 696 | /* |
| 697 | * Sort parallelogram by y values, ensure that each delta vector |
| 698 | * has a non-negative y delta. |
| 699 | */ |
| 700 | SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, ); |
| 701 | |
| 702 | PGRAM_MIN_MAX(ix1, ix2, x0, dx1, dx2, JNI_TRUE); |
| 703 | iy1 = (jint) floor(y0); |
| 704 | iy2 = (jint) ceil(y0 + dy1 + dy2); |
| 705 | |
| 706 | pPrim = GetNativePrim(env, self); |
| 707 | if (pPrim == NULL) { |
| 708 | return; |
| 709 | } |
| 710 | if (pPrim->pCompType->getCompInfo != NULL) { |
| 711 | (*pPrim->pCompType->getCompInfo)(env, &compInfo, comp); |
| 712 | } |
| 713 | |
| 714 | sdOps = SurfaceData_GetOps(env, sData); |
| 715 | if (sdOps == 0) { |
| 716 | return; |
| 717 | } |
| 718 | |
| 719 | GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); |
| 720 | SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2); |
| 721 | if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 || |
| 722 | rasInfo.bounds.x2 <= rasInfo.bounds.x1) |
| 723 | { |
| 724 | return; |
| 725 | } |
| 726 | |
| 727 | if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) { |
| 728 | return; |
| 729 | } |
| 730 | |
| 731 | ix1 = rasInfo.bounds.x1; |
| 732 | iy1 = rasInfo.bounds.y1; |
| 733 | ix2 = rasInfo.bounds.x2; |
| 734 | iy2 = rasInfo.bounds.y2; |
| 735 | if (ix2 > ix1 && iy2 > iy1) { |
| 736 | jint width = ix2 - ix1; |
| 737 | jint color = GrPrim_Sg2dGetEaRGB(env, sg2d); |
| 738 | unsigned char localmask[MASK_BUF_LEN]; |
| 739 | unsigned char *pMask = ((width > MASK_BUF_LEN) |
| 740 | ? malloc(width) |
| 741 | : localmask); |
| 742 | |
| 743 | sdOps->GetRasInfo(env, sdOps, &rasInfo); |
| 744 | if (rasInfo.rasBase != NULL && pMask != NULL) { |
| 745 | void *pDst = PtrCoord(rasInfo.rasBase, |
| 746 | ix1, rasInfo.pixelStride, |
| 747 | iy1, rasInfo.scanStride); |
| 748 | if (dy1 == 0 && dx2 == 0) { |
| 749 | if (dx1 < 0) { |
| 750 | // We sorted by Y above, but not by X |
| 751 | x0 += dx1; |
| 752 | dx1 = -dx1; |
| 753 | } |
| 754 | fillAARect(pPrim, &rasInfo, &compInfo, |
| 755 | color, pMask, pDst, |
| 756 | x0, y0, x0+dx1, y0+dy2); |
| 757 | } else if (dx1 == 0 && dy2 == 0) { |
| 758 | if (dx2 < 0) { |
| 759 | // We sorted by Y above, but not by X |
| 760 | x0 += dx2; |
| 761 | dx2 = -dx2; |
| 762 | } |
| 763 | fillAARect(pPrim, &rasInfo, &compInfo, |
| 764 | color, pMask, pDst, |
| 765 | x0, y0, x0+dx2, y0+dy1); |
| 766 | } else { |
| 767 | fillAAPgram(pPrim, &rasInfo, &compInfo, |
| 768 | color, pMask, pDst, |
| 769 | x0, y0, dx1, dy1, dx2, dy2); |
| 770 | } |
| 771 | } |
| 772 | SurfaceData_InvokeRelease(env, sdOps, &rasInfo); |
| 773 | if (pMask != NULL && pMask != localmask) { |
| 774 | free(pMask); |
| 775 | } |
| 776 | } |
| 777 | SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); |
| 778 | } |
| 779 | |
| 780 | /* Main function to fill a double pair of (inner and outer) parallelograms */ |
| 781 | static void |
| 782 | drawAAPgram(NativePrimitive *pPrim, SurfaceDataRasInfo *pRasInfo, |
| 783 | CompositeInfo *pCompInfo, jint color, unsigned char *pMask, |
| 784 | void *pDst, |
| 785 | jdouble ox0, jdouble oy0, |
| 786 | jdouble dx1, jdouble dy1, |
| 787 | jdouble dx2, jdouble dy2, |
| 788 | jdouble ldx1, jdouble ldy1, |
| 789 | jdouble ldx2, jdouble ldy2) |
| 790 | { |
| 791 | jint cx1 = pRasInfo->bounds.x1; |
| 792 | jint cy1 = pRasInfo->bounds.y1; |
| 793 | jint cx2 = pRasInfo->bounds.x2; |
| 794 | jint cy2 = pRasInfo->bounds.y2; |
| 795 | jint width = cx2 - cx1; |
| 796 | EdgeInfo edges[8]; |
| 797 | jfloat localaccum[MASK_BUF_LEN + 1]; |
| 798 | jfloat *pAccum; |
| 799 | |
| 800 | if (!storePgram(edges + 0, edges + 6, |
| 801 | ox0, oy0, |
| 802 | dx1 + ldx1, dy1 + ldy1, |
| 803 | dx2 + ldx2, dy2 + ldy2, |
| 804 | cx1, cy1, cx2, cy2, |
| 805 | JNI_FALSE)) |
| 806 | { |
| 807 | /* If outer pgram does not contribute, then inner cannot either. */ |
| 808 | return; |
| 809 | } |
| 810 | storePgram(edges + 2, edges + 4, |
| 811 | ox0 + ldx1 + ldx2, oy0 + ldy1 + ldy2, |
| 812 | dx1 - ldx1, dy1 - ldy1, |
| 813 | dx2 - ldx2, dy2 - ldy2, |
| 814 | cx1, cy1, cx2, cy2, |
| 815 | JNI_TRUE); |
| 816 | |
| 817 | pAccum = ((width > MASK_BUF_LEN) |
| 818 | ? malloc((width + 1) * sizeof(jfloat)) |
| 819 | : localaccum); |
| 820 | if (pAccum == NULL) { |
| 821 | return; |
| 822 | } |
| 823 | memset(pAccum, 0, (width+1) * sizeof(jfloat)); |
| 824 | |
| 825 | while (cy1 < cy2) { |
| 826 | jint lmin, lmax, rmin, rmax; |
| 827 | jint moff, x; |
| 828 | jdouble accum; |
| 829 | unsigned char lastcov; |
| 830 | |
| 831 | lmin = rmin = width + 2; |
| 832 | lmax = rmax = 0; |
| 833 | ACCUM_EDGE(&edges[0], pAccum, lmin, lmax, |
| 834 | cx1, cy1, cx2, cy1+1); |
| 835 | ACCUM_EDGE(&edges[1], pAccum, lmin, lmax, |
| 836 | cx1, cy1, cx2, cy1+1); |
| 837 | ACCUM_EDGE(&edges[2], pAccum, lmin, lmax, |
| 838 | cx1, cy1, cx2, cy1+1); |
| 839 | ACCUM_EDGE(&edges[3], pAccum, lmin, lmax, |
| 840 | cx1, cy1, cx2, cy1+1); |
| 841 | ACCUM_EDGE(&edges[4], pAccum, rmin, rmax, |
| 842 | cx1, cy1, cx2, cy1+1); |
| 843 | ACCUM_EDGE(&edges[5], pAccum, rmin, rmax, |
| 844 | cx1, cy1, cx2, cy1+1); |
| 845 | ACCUM_EDGE(&edges[6], pAccum, rmin, rmax, |
| 846 | cx1, cy1, cx2, cy1+1); |
| 847 | ACCUM_EDGE(&edges[7], pAccum, rmin, rmax, |
| 848 | cx1, cy1, cx2, cy1+1); |
| 849 | if (lmax > width) { |
| 850 | lmax = width; /* Extra col has data we do not need. */ |
| 851 | } |
| 852 | if (rmax > width) { |
| 853 | rmax = width; /* Extra col has data we do not need. */ |
| 854 | } |
| 855 | /* If ranges overlap, handle both in the first pass. */ |
| 856 | if (rmin <= lmax) { |
| 857 | lmax = rmax; |
| 858 | } |
| 859 | |
| 860 | x = lmin; |
| 861 | accum = 0.0; |
| 862 | moff = 0; |
| 863 | lastcov = 0; |
| 864 | while (x < lmax) { |
| 865 | accum += pAccum[x]; |
| 866 | pAccum[x] = 0.0f; |
| 867 | pMask[moff++] = lastcov = DblToMask(accum); |
| 868 | x++; |
| 869 | } |
| 870 | /* Check for an empty or solidcenter section. */ |
| 871 | if (lastcov == 0 || lastcov == 0xFF) { |
| 872 | jint endx; |
| 873 | void *pRow; |
| 874 | |
| 875 | /* First process the existing partial coverage data. */ |
| 876 | if (moff > 0) { |
| 877 | pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0); |
| 878 | (*pPrim->funcs.maskfill)(pRow, |
| 879 | pMask, 0, 0, |
| 880 | moff, 1, |
| 881 | color, pRasInfo, |
| 882 | pPrim, pCompInfo); |
| 883 | moff = 0; |
| 884 | } |
| 885 | |
| 886 | /* Where does the center section end? */ |
| 887 | /* If there is no right AA edge in the accum buffer, then */ |
| 888 | /* the right edge was beyond the clip, so fill out to width */ |
| 889 | endx = (rmin < rmax) ? rmin : width; |
| 890 | if (x < endx) { |
| 891 | if (lastcov == 0xFF) { |
| 892 | pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0); |
| 893 | (*pPrim->funcs.maskfill)(pRow, |
| 894 | NULL, 0, 0, |
| 895 | endx - x, 1, |
| 896 | color, pRasInfo, |
| 897 | pPrim, pCompInfo); |
| 898 | } |
| 899 | x = endx; |
| 900 | } |
| 901 | } else if (rmin >= rmax) { |
| 902 | /* We are not at 0 coverage, but there is no right edge, */ |
| 903 | /* force a right edge so we process pixels out to width. */ |
| 904 | rmax = width; |
| 905 | } |
| 906 | /* The following loop will process the right AA edge and/or any */ |
| 907 | /* partial coverage center section not processed above. */ |
| 908 | while (x < rmax) { |
| 909 | accum += pAccum[x]; |
| 910 | pAccum[x] = 0.0f; |
| 911 | pMask[moff++] = lastcov = DblToMask(accum); |
| 912 | x++; |
| 913 | } |
| 914 | if (moff > 0) { |
| 915 | void *pRow = PtrCoord(pDst, x-moff, pRasInfo->pixelStride, 0, 0); |
| 916 | (*pPrim->funcs.maskfill)(pRow, |
| 917 | pMask, 0, 0, |
| 918 | moff, 1, |
| 919 | color, pRasInfo, |
| 920 | pPrim, pCompInfo); |
| 921 | } |
| 922 | if (lastcov == 0xFF && x < width) { |
| 923 | void *pRow = PtrCoord(pDst, x, pRasInfo->pixelStride, 0, 0); |
| 924 | (*pPrim->funcs.maskfill)(pRow, |
| 925 | NULL, 0, 0, |
| 926 | width - x, 1, |
| 927 | color, pRasInfo, |
| 928 | pPrim, pCompInfo); |
| 929 | } |
| 930 | pDst = PtrAddBytes(pDst, pRasInfo->scanStride); |
| 931 | cy1++; |
| 932 | } |
| 933 | if (pAccum != localaccum) { |
| 934 | free(pAccum); |
| 935 | } |
| 936 | } |
| 937 | |
| 938 | /* |
| 939 | * Class: sun_java2d_loops_MaskFill |
| 940 | * Method: DrawAAPgram |
| 941 | * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;Ljava/awt/Composite;DDDDDDDD)V |
| 942 | */ |
| 943 | JNIEXPORT void JNICALL |
| 944 | Java_sun_java2d_loops_MaskFill_DrawAAPgram |
| 945 | (JNIEnv *env, jobject self, |
| 946 | jobject sg2d, jobject sData, jobject comp, |
| 947 | jdouble x0, jdouble y0, |
| 948 | jdouble dx1, jdouble dy1, |
| 949 | jdouble dx2, jdouble dy2, |
| 950 | jdouble lw1, jdouble lw2) |
| 951 | { |
| 952 | SurfaceDataOps *sdOps; |
| 953 | SurfaceDataRasInfo rasInfo; |
| 954 | NativePrimitive *pPrim; |
| 955 | CompositeInfo compInfo; |
| 956 | jint ix1, iy1, ix2, iy2; |
| 957 | jdouble ldx1, ldy1, ldx2, ldy2; |
| 958 | jdouble ox0, oy0; |
| 959 | |
| 960 | if ((dy1 == 0 && dx1 == 0) || (dy2 == 0 && dx2 == 0)) { |
| 961 | return; |
| 962 | } |
| 963 | |
| 964 | /* |
| 965 | * Sort parallelogram by y values, ensure that each delta vector |
| 966 | * has a non-negative y delta. |
| 967 | */ |
| 968 | SORT_PGRAM(x0, y0, dx1, dy1, dx2, dy2, |
| 969 | v = lw1; lw1 = lw2; lw2 = v;); |
| 970 | |
| 971 | // dx,dy for line width in the "1" and "2" directions. |
| 972 | ldx1 = dx1 * lw1; |
| 973 | ldy1 = dy1 * lw1; |
| 974 | ldx2 = dx2 * lw2; |
| 975 | ldy2 = dy2 * lw2; |
| 976 | |
| 977 | // calculate origin of the outer parallelogram |
| 978 | ox0 = x0 - (ldx1 + ldx2) / 2.0; |
| 979 | oy0 = y0 - (ldy1 + ldy2) / 2.0; |
| 980 | |
| 981 | if (lw1 >= 1.0 || lw2 >= 1.0) { |
| 982 | /* Only need to fill an outer pgram if the interior no longer |
| 983 | * has a hole in it (i.e. if either of the line width ratios |
| 984 | * were greater than or equal to 1.0). |
| 985 | */ |
| 986 | Java_sun_java2d_loops_MaskFill_FillAAPgram(env, self, |
| 987 | sg2d, sData, comp, |
| 988 | ox0, oy0, |
| 989 | dx1 + ldx1, dy1 + ldy1, |
| 990 | dx2 + ldx2, dy2 + ldy2); |
| 991 | return; |
| 992 | } |
| 993 | |
| 994 | PGRAM_MIN_MAX(ix1, ix2, ox0, dx1+ldx1, dx2+ldx2, JNI_TRUE); |
| 995 | iy1 = (jint) floor(oy0); |
| 996 | iy2 = (jint) ceil(oy0 + dy1 + ldy1 + dy2 + ldy2); |
| 997 | |
| 998 | pPrim = GetNativePrim(env, self); |
| 999 | if (pPrim == NULL) { |
| 1000 | return; |
| 1001 | } |
| 1002 | if (pPrim->pCompType->getCompInfo != NULL) { |
| 1003 | (*pPrim->pCompType->getCompInfo)(env, &compInfo, comp); |
| 1004 | } |
| 1005 | |
| 1006 | sdOps = SurfaceData_GetOps(env, sData); |
| 1007 | if (sdOps == 0) { |
| 1008 | return; |
| 1009 | } |
| 1010 | |
| 1011 | GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds); |
| 1012 | SurfaceData_IntersectBoundsXYXY(&rasInfo.bounds, ix1, iy1, ix2, iy2); |
| 1013 | if (rasInfo.bounds.y2 <= rasInfo.bounds.y1 || |
| 1014 | rasInfo.bounds.x2 <= rasInfo.bounds.x1) |
| 1015 | { |
| 1016 | return; |
| 1017 | } |
| 1018 | |
| 1019 | if (sdOps->Lock(env, sdOps, &rasInfo, pPrim->dstflags) != SD_SUCCESS) { |
| 1020 | return; |
| 1021 | } |
| 1022 | |
| 1023 | ix1 = rasInfo.bounds.x1; |
| 1024 | iy1 = rasInfo.bounds.y1; |
| 1025 | ix2 = rasInfo.bounds.x2; |
| 1026 | iy2 = rasInfo.bounds.y2; |
| 1027 | if (ix2 > ix1 && iy2 > iy1) { |
| 1028 | jint width = ix2 - ix1; |
| 1029 | jint color = GrPrim_Sg2dGetEaRGB(env, sg2d); |
| 1030 | unsigned char localmask[MASK_BUF_LEN]; |
| 1031 | unsigned char *pMask = ((width > MASK_BUF_LEN) |
| 1032 | ? malloc(width) |
| 1033 | : localmask); |
| 1034 | |
| 1035 | sdOps->GetRasInfo(env, sdOps, &rasInfo); |
| 1036 | if (rasInfo.rasBase != NULL && pMask != NULL) { |
| 1037 | void *pDst = PtrCoord(rasInfo.rasBase, |
| 1038 | ix1, rasInfo.pixelStride, |
| 1039 | iy1, rasInfo.scanStride); |
| 1040 | /* |
| 1041 | * NOTE: aligned rects could probably be drawn |
| 1042 | * even faster with a little work here. |
| 1043 | * if (dy1 == 0 && dx2 == 0) { |
| 1044 | * drawAARect(pPrim, &rasInfo, &compInfo, |
| 1045 | * color, pMask, pDst, |
| 1046 | * ox0, oy0, ox0+dx1+ldx1, oy0+dy2+ldy2, ldx1, ldy2); |
| 1047 | * } else if (dx1 == 0 && dy2 == 0) { |
| 1048 | * drawAARect(pPrim, &rasInfo, &compInfo, |
| 1049 | * color, pMask, pDst, |
| 1050 | * ox0, oy0, ox0+dx2+ldx2, oy0+dy1+ldy1, ldx2, ldy1); |
| 1051 | * } else { |
| 1052 | */ |
| 1053 | drawAAPgram(pPrim, &rasInfo, &compInfo, |
| 1054 | color, pMask, pDst, |
| 1055 | ox0, oy0, |
| 1056 | dx1, dy1, dx2, dy2, |
| 1057 | ldx1, ldy1, ldx2, ldy2); |
| 1058 | /* |
| 1059 | * } |
| 1060 | */ |
| 1061 | } |
| 1062 | SurfaceData_InvokeRelease(env, sdOps, &rasInfo); |
| 1063 | if (pMask != NULL && pMask != localmask) { |
| 1064 | free(pMask); |
| 1065 | } |
| 1066 | } |
| 1067 | SurfaceData_InvokeUnlock(env, sdOps, &rasInfo); |
| 1068 | } |
| 1069 | |