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 */
39JNIEXPORT void JNICALL
40Java_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. */
114static void
115fillAARect(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 */
327typedef 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 */
347static jboolean
348storeEdge(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 */
432static jboolean
433storePgram(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 */
545static void
546fillAAPgram(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 */
678JNIEXPORT void JNICALL
679Java_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 */
781static void
782drawAAPgram(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 */
943JNIEXPORT void JNICALL
944Java_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