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
Java_sun_java2d_loops_MaskFill_MaskFill(JNIEnv * env,jobject self,jobject sg2d,jobject sData,jobject comp,jint x,jint y,jint w,jint h,jbyteArray maskArray,jint maskoff,jint maskscan)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
fillAARect(NativePrimitive * pPrim,SurfaceDataRasInfo * pRasInfo,CompositeInfo * pCompInfo,jint color,unsigned char * pMask,void * pDst,jdouble x1,jdouble y1,jdouble x2,jdouble y2)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
storeEdge(EdgeInfo * pEdge,jdouble x,jdouble y,jdouble dx,jdouble dy,jint cx1,jint cy1,jint cx2,jint cy2,jboolean isTrailing)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
storePgram(EdgeInfo * pLeftEdge,EdgeInfo * pRightEdge,jdouble x,jdouble y,jdouble dx1,jdouble dy1,jdouble dx2,jdouble dy2,jint cx1,jint cy1,jint cx2,jint cy2,jboolean inverted)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
fillAAPgram(NativePrimitive * pPrim,SurfaceDataRasInfo * pRasInfo,CompositeInfo * pCompInfo,jint color,unsigned char * pMask,void * pDst,jdouble x1,jdouble y1,jdouble dx1,jdouble dy1,jdouble dx2,jdouble dy2)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
Java_sun_java2d_loops_MaskFill_FillAAPgram(JNIEnv * env,jobject self,jobject sg2d,jobject sData,jobject comp,jdouble x0,jdouble y0,jdouble dx1,jdouble dy1,jdouble dx2,jdouble dy2)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
drawAAPgram(NativePrimitive * pPrim,SurfaceDataRasInfo * pRasInfo,CompositeInfo * pCompInfo,jint color,unsigned char * pMask,void * pDst,jdouble ox0,jdouble oy0,jdouble dx1,jdouble dy1,jdouble dx2,jdouble dy2,jdouble ldx1,jdouble ldy1,jdouble ldx2,jdouble ldy2)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
Java_sun_java2d_loops_MaskFill_DrawAAPgram(JNIEnv * env,jobject self,jobject sg2d,jobject sData,jobject comp,jdouble x0,jdouble y0,jdouble dx1,jdouble dy1,jdouble dx2,jdouble dy2,jdouble lw1,jdouble lw2)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