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 "jni_util.h"
27 
28 #include "GraphicsPrimitiveMgr.h"
29 #include "LineUtils.h"
30 
31 #include "sun_java2d_loops_DrawPolygons.h"
32 
33 static void
RefineBounds(SurfaceDataBounds * bounds,jint transX,jint transY,jint * xPointsPtr,jint * yPointsPtr,jint pointsNeeded)34 RefineBounds(SurfaceDataBounds *bounds, jint transX, jint transY,
35              jint *xPointsPtr, jint *yPointsPtr, jint pointsNeeded)
36 {
37     jint xmin, ymin, xmax, ymax;
38     if (pointsNeeded > 0) {
39         xmin = xmax = transX + *xPointsPtr++;
40         ymin = ymax = transY + *yPointsPtr++;
41         while (--pointsNeeded > 0) {
42             jint x = transX + *xPointsPtr++;
43             jint y = transY + *yPointsPtr++;
44             if (xmin > x) xmin = x;
45             if (ymin > y) ymin = y;
46             if (xmax < x) xmax = x;
47             if (ymax < y) ymax = y;
48         }
49         if (++xmax < xmin) xmax--;
50         if (++ymax < ymin) ymax--;
51         if (bounds->x1 < xmin) bounds->x1 = xmin;
52         if (bounds->y1 < ymin) bounds->y1 = ymin;
53         if (bounds->x2 > xmax) bounds->x2 = xmax;
54         if (bounds->y2 > ymax) bounds->y2 = ymax;
55     } else {
56         bounds->x2 = bounds->x1;
57         bounds->y2 = bounds->y1;
58     }
59 }
60 
61 static void
ProcessPoly(SurfaceDataRasInfo * pRasInfo,DrawLineFunc * pLine,NativePrimitive * pPrim,CompositeInfo * pCompInfo,jint pixel,jint transX,jint transY,jint * xPointsPtr,jint * yPointsPtr,jint * nPointsPtr,jint numPolys,jboolean close)62 ProcessPoly(SurfaceDataRasInfo *pRasInfo,
63             DrawLineFunc *pLine,
64             NativePrimitive *pPrim,
65             CompositeInfo *pCompInfo,
66             jint pixel, jint transX, jint transY,
67             jint *xPointsPtr, jint *yPointsPtr,
68             jint *nPointsPtr, jint numPolys,
69             jboolean close)
70 {
71     int i;
72     for (i = 0; i < numPolys; i++) {
73         jint numPts = nPointsPtr[i];
74         if (numPts > 1) {
75             jint x0, y0, x1, y1;
76             jboolean empty = JNI_TRUE;
77             x0 = x1 = transX + *xPointsPtr++;
78             y0 = y1 = transY + *yPointsPtr++;
79             while (--numPts > 0) {
80                 jint x2 = transX + *xPointsPtr++;
81                 jint y2 = transY + *yPointsPtr++;
82                 empty = (empty && x1 == x2 && y1 == y2);
83                 LineUtils_ProcessLine(pRasInfo, pixel, pLine,
84                                       pPrim, pCompInfo,
85                                       x1, y1, x2, y2,
86                                       (numPts > 1 || close));
87                 x1 = x2;
88                 y1 = y2;
89             }
90             if (close && (empty || x1 != x0 || y1 != y0)) {
91                 LineUtils_ProcessLine(pRasInfo, pixel, pLine,
92                                       pPrim, pCompInfo,
93                                       x1, y1, x0, y0, !empty);
94             }
95         } else if (numPts == 1) {
96             xPointsPtr++;
97             yPointsPtr++;
98         }
99     }
100 }
101 
102 /*
103  * Class:     sun_java2d_loops_DrawPolygons
104  * Method:    DrawPolygons
105  * Signature: (Lsun/java2d/SunGraphics2D;Lsun/java2d/SurfaceData;[I[I[IIIIZ)V
106  */
107 JNIEXPORT void JNICALL
Java_sun_java2d_loops_DrawPolygons_DrawPolygons(JNIEnv * env,jobject self,jobject sg2d,jobject sData,jintArray xPointsArray,jintArray yPointsArray,jintArray nPointsArray,jint numPolys,jint transX,jint transY,jboolean close)108 Java_sun_java2d_loops_DrawPolygons_DrawPolygons
109     (JNIEnv *env, jobject self,
110      jobject sg2d, jobject sData,
111      jintArray xPointsArray, jintArray yPointsArray,
112      jintArray nPointsArray, jint numPolys,
113      jint transX, jint transY, jboolean close)
114 {
115     SurfaceDataOps *sdOps;
116     SurfaceDataRasInfo rasInfo;
117     NativePrimitive *pPrim;
118     CompositeInfo compInfo;
119     jsize nPointsLen, xPointsLen, yPointsLen;
120     jint *nPointsPtr = NULL;
121     jint *xPointsPtr = NULL;
122     jint *yPointsPtr = NULL;
123     jint pointsNeeded;
124     jint i, ret;
125     jboolean ok = JNI_TRUE;
126     jint pixel = GrPrim_Sg2dGetPixel(env, sg2d);
127 
128     if (JNU_IsNull(env, xPointsArray) || JNU_IsNull(env, yPointsArray)) {
129         JNU_ThrowNullPointerException(env, "coordinate array");
130         return;
131     }
132     if (JNU_IsNull(env, nPointsArray)) {
133         JNU_ThrowNullPointerException(env, "polygon length array");
134         return;
135     }
136 
137     nPointsLen = (*env)->GetArrayLength(env, nPointsArray);
138     xPointsLen = (*env)->GetArrayLength(env, xPointsArray);
139     yPointsLen = (*env)->GetArrayLength(env, yPointsArray);
140     if (nPointsLen < numPolys) {
141         JNU_ThrowArrayIndexOutOfBoundsException(env,
142                                                 "polygon length array size");
143         return;
144     }
145 
146     pPrim = GetNativePrim(env, self);
147     if (pPrim == NULL) {
148         return;
149     }
150     if (pPrim->pCompType->getCompInfo != NULL) {
151         GrPrim_Sg2dGetCompInfo(env, sg2d, pPrim, &compInfo);
152     }
153 
154     sdOps = SurfaceData_GetOps(env, sData);
155     if (sdOps == 0) {
156         return;
157     }
158 
159     GrPrim_Sg2dGetClip(env, sg2d, &rasInfo.bounds);
160 
161     ret = sdOps->Lock(env, sdOps, &rasInfo, SD_LOCK_FASTEST | pPrim->dstflags);
162     if (ret == SD_FAILURE) {
163         return;
164     }
165 
166     nPointsPtr = (*env)->GetPrimitiveArrayCritical(env, nPointsArray, NULL);
167     if (!nPointsPtr) {
168         ok = JNI_FALSE;
169     }
170 
171     if (ok) {
172         pointsNeeded = 0;
173         for (i = 0; i < numPolys; i++) {
174             if (nPointsPtr[i] > 0) {
175                 pointsNeeded += nPointsPtr[i];
176             }
177         }
178 
179         if (yPointsLen < pointsNeeded || xPointsLen < pointsNeeded) {
180             (*env)->ReleasePrimitiveArrayCritical(env, nPointsArray,
181                                                   nPointsPtr, JNI_ABORT);
182             SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
183             JNU_ThrowArrayIndexOutOfBoundsException(env,
184                                                     "coordinate array length");
185             return;
186         }
187 
188         xPointsPtr = (*env)->GetPrimitiveArrayCritical(env, xPointsArray, NULL);
189         if (!xPointsPtr) {
190             ok = JNI_FALSE;
191         }
192         if (ok) {
193             yPointsPtr = (*env)->GetPrimitiveArrayCritical(env, yPointsArray, NULL);
194             if (!yPointsPtr) {
195                 ok = JNI_FALSE;
196             }
197         }
198     }
199 
200     if (ok) {
201         if (ret == SD_SLOWLOCK) {
202             RefineBounds(&rasInfo.bounds, transX, transY,
203                          xPointsPtr, yPointsPtr, pointsNeeded);
204             ok = (rasInfo.bounds.x2 > rasInfo.bounds.x1 &&
205                   rasInfo.bounds.y2 > rasInfo.bounds.y1);
206         }
207     }
208 
209     if (ok) {
210         sdOps->GetRasInfo(env, sdOps, &rasInfo);
211         if (rasInfo.rasBase &&
212             rasInfo.bounds.x2 > rasInfo.bounds.x1 &&
213             rasInfo.bounds.y2 > rasInfo.bounds.y1)
214         {
215             ProcessPoly(&rasInfo, pPrim->funcs.drawline, pPrim, &compInfo,
216                         pixel, transX, transY,
217                         xPointsPtr, yPointsPtr,
218                         nPointsPtr, numPolys,
219                         close);
220         }
221         SurfaceData_InvokeRelease(env, sdOps, &rasInfo);
222     }
223 
224     if (nPointsPtr) {
225         (*env)->ReleasePrimitiveArrayCritical(env, nPointsArray,
226                                               nPointsPtr, JNI_ABORT);
227     }
228     if (xPointsPtr) {
229         (*env)->ReleasePrimitiveArrayCritical(env, xPointsArray,
230                                               xPointsPtr, JNI_ABORT);
231     }
232     if (yPointsPtr) {
233         (*env)->ReleasePrimitiveArrayCritical(env, yPointsArray,
234                                               yPointsPtr, JNI_ABORT);
235     }
236     SurfaceData_InvokeUnlock(env, sdOps, &rasInfo);
237 }
238