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
33static void
34RefineBounds(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
61static void
62ProcessPoly(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 */
107JNIEXPORT void JNICALL
108Java_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