File: | jdk/src/java.desktop/share/native/libawt/java2d/loops/ProcessPath.c |
Warning: | line 1298, column 20 The left operand of '>' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 2005, 2018, 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 <assert.h> | |||
28 | #include <stdlib.h> | |||
29 | #include <string.h> | |||
30 | ||||
31 | #include "jni.h" | |||
32 | #include "j2d_md.h" | |||
33 | #include "java_awt_geom_PathIterator.h" | |||
34 | ||||
35 | #include "ProcessPath.h" | |||
36 | ||||
37 | /* | |||
38 | * This framework performs filling and drawing of paths with sub-pixel | |||
39 | * precision. Also, it performs clipping by the specified view area. | |||
40 | * | |||
41 | * Drawing of the shapes is performed not pixel by pixel but segment by segment | |||
42 | * except several pixels near endpoints of the drawn line. This approach saves | |||
43 | * lot's of cpu cycles especially in case of large primitives (like ovals with | |||
44 | * sizes more than 50) and helps in achieving appropriate visual quality. Also, | |||
45 | * such method of drawing is useful for the accelerated pipelines where | |||
46 | * overhead of the per-pixel drawing could eliminate all benefits of the | |||
47 | * hardware acceleration. | |||
48 | * | |||
49 | * Filling of the path was taken from | |||
50 | * | |||
51 | * [Graphics Gems, edited by Andrew S Glassner. Academic Press 1990, | |||
52 | * ISBN 0-12-286165-5 (Concave polygon scan conversion), 87-91] | |||
53 | * | |||
54 | * and modified to work with sub-pixel precision and non-continuous paths. | |||
55 | * It's also speeded up by using hash table by rows of the filled objects. | |||
56 | * | |||
57 | * Here is high level scheme showing the rendering process: | |||
58 | * | |||
59 | * doDrawPath doFillPath | |||
60 | * \ / | |||
61 | * ProcessPath | |||
62 | * | | |||
63 | * CheckPathSegment | |||
64 | * | | |||
65 | * --------+------ | |||
66 | * | | | |||
67 | * | | | |||
68 | * | | | |||
69 | * _->ProcessCurve | | |||
70 | * / / | | | |||
71 | * \___/ | | | |||
72 | * | | | |||
73 | * DrawCurve ProcessLine | |||
74 | * \ / | |||
75 | * \ / | |||
76 | * \ / | |||
77 | * \ / | |||
78 | * ------+------ | |||
79 | * (filling) / \ (drawing) | |||
80 | * / \ | |||
81 | * Clipping and Clipping | |||
82 | * clamping \ | |||
83 | * | \ | |||
84 | * StoreFixedLine ProcessFixedLine | |||
85 | * | / \ | |||
86 | * | / \ | |||
87 | * FillPolygon PROCESS_LINE PROCESS_POINT | |||
88 | * | |||
89 | * | |||
90 | * | |||
91 | * CheckPathSegment - rough checking and skipping path's segments in case of | |||
92 | * invalid or huge coordinates of the control points to | |||
93 | * avoid calculation problems with NaNs and values close | |||
94 | * to the FLT_MAX | |||
95 | * | |||
96 | * ProcessCurve - (ProcessQuad, ProcessCubic) Splitting the curve into | |||
97 | * monotonic parts having appropriate size (calculated as | |||
98 | * boundary box of the control points) | |||
99 | * | |||
100 | * DrawMonotonicCurve - (DrawMonotonicQuad, DrawMonotonicCubic) flattening | |||
101 | * monotonic curve using adaptive forward differencing | |||
102 | * | |||
103 | * StoreFixedLine - storing segment from the flattened path to the | |||
104 | * FillData structure. Performing clipping and clamping if | |||
105 | * necessary. | |||
106 | * | |||
107 | * PROCESS_LINE, PROCESS_POINT - Helpers for calling appropriate primitive from | |||
108 | * DrawHandler structure | |||
109 | * | |||
110 | * ProcessFixedLine - Drawing line segment with subpixel precision. | |||
111 | * | |||
112 | */ | |||
113 | ||||
114 | #define PROCESS_LINE(hnd, fX0, fY0, fX1, fY1, checkBounds, pixelInfo)do { jint X0 = (fX0) >> 10; jint Y0 = (fY0) >> 10 ; jint X1 = (fX1) >> 10; jint Y1 = (fY1) >> 10; jint res; if (checkBounds) { jfloat xMinf = hnd->dhnd->xMinf + 0.5f; jfloat yMinf = hnd->dhnd->yMinf + 0.5f; jfloat xMaxf = hnd->dhnd->xMaxf + 0.5f; jfloat yMaxf = hnd-> dhnd->yMaxf + 0.5f; do { jdouble t; res = CRES_NOT_CLIPPED ; if (Y0 < (yMinf) || Y0 > (yMaxf)) { if (Y0 < (yMinf )) { if (Y1 < (yMinf)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = (yMinf); } else { if (Y1 > (yMaxf )) { res = CRES_INVISIBLE; break; }; res = CRES_MAX_CLIPPED; t = (yMaxf); } X0 = (jint)(X0 + ((jdouble)(t - Y0)*(X1 - X0)) / (Y1 - Y0)); Y0 = (jint)t; } } while (0); if (res == CRES_INVISIBLE ) break; do { jdouble t; res = CRES_NOT_CLIPPED; if (Y1 < ( yMinf) || Y1 > (yMaxf)) { if (Y1 < (yMinf)) { if (Y0 < (yMinf)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED ; t = (yMinf); } else { if (Y0 > (yMaxf)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (yMaxf); } X1 = (jint )(X1 + ((jdouble)(t - Y1)*(X0 - X1)) / (Y0 - Y1)); Y1 = (jint )t; } } while (0); if (res == CRES_INVISIBLE) break; do { jdouble t; res = CRES_NOT_CLIPPED; if (X0 < (xMinf) || X0 > (xMaxf )) { if (X0 < (xMinf)) { if (X1 < (xMinf)) { res = CRES_INVISIBLE ; break; }; res = CRES_MIN_CLIPPED; t = (xMinf); } else { if ( X1 > (xMaxf)) { res = CRES_INVISIBLE; break; }; res = CRES_MAX_CLIPPED ; t = (xMaxf); } Y0 = (jint)(Y0 + ((jdouble)(t - X0)*(Y1 - Y0 )) / (X1 - X0)); X0 = (jint)t; } } while (0); if (res == CRES_INVISIBLE ) break; do { jdouble t; res = CRES_NOT_CLIPPED; if (X1 < ( xMinf) || X1 > (xMaxf)) { if (X1 < (xMinf)) { if (X0 < (xMinf)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED ; t = (xMinf); } else { if (X0 > (xMaxf)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (xMaxf); } Y1 = (jint )(Y1 + ((jdouble)(t - X1)*(Y0 - Y1)) / (X0 - X1)); X1 = (jint )t; } } while (0); if (res == CRES_INVISIBLE) break; } if ((( X0^X1) | (Y0^Y1)) == 0) { if (pixelInfo[0] == 0) { pixelInfo[ 0] = 1; pixelInfo[1] = X0; pixelInfo[2] = Y0; pixelInfo[3] = X0 ; pixelInfo[4] = Y0; hnd->dhnd->pDrawPixel(hnd->dhnd , X0, Y0); } else if ((X0 != pixelInfo[3] || Y0 != pixelInfo[ 4]) && (X0 != pixelInfo[1] || Y0 != pixelInfo[2])) { hnd ->dhnd->pDrawPixel(hnd->dhnd, X0, Y0); pixelInfo[3] = X0; pixelInfo[4] = Y0; } break; } if (pixelInfo[0] && ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) || (pixelInfo [3] == X0 && pixelInfo[4] == Y0))) { hnd->dhnd-> pDrawPixel(hnd->dhnd, X0, Y0); } hnd->dhnd->pDrawLine (hnd->dhnd, X0, Y0, X1, Y1); if (pixelInfo[0] == 0) { pixelInfo [0] = 1; pixelInfo[1] = X0; pixelInfo[2] = Y0; pixelInfo[3] = X0; pixelInfo[4] = Y0; } if ((pixelInfo[1] == X1 && pixelInfo [2] == Y1) || (pixelInfo[3] == X1 && pixelInfo[4] == Y1 )) { hnd->dhnd->pDrawPixel(hnd->dhnd, X1, Y1); } pixelInfo [3] = X1; pixelInfo[4] = Y1; } while(0) \ | |||
115 | do { \ | |||
116 | jint X0 = (fX0) >> MDP_PREC10; \ | |||
117 | jint Y0 = (fY0) >> MDP_PREC10; \ | |||
118 | jint X1 = (fX1) >> MDP_PREC10; \ | |||
119 | jint Y1 = (fY1) >> MDP_PREC10; \ | |||
120 | jint res; \ | |||
121 | \ | |||
122 | /* Checking bounds and clipping if necessary. \ | |||
123 | * REMIND: It's temporary solution to avoid OOB in rendering code. \ | |||
124 | * Current approach uses float equations which are unreliable for \ | |||
125 | * clipping and makes assumptions about the line biases of the \ | |||
126 | * rendering algorithm. Also, clipping code should be moved down \ | |||
127 | * into only those output renderers that need it. \ | |||
128 | */ \ | |||
129 | if (checkBounds) { \ | |||
130 | jfloat xMinf = hnd->dhnd->xMinf + 0.5f; \ | |||
131 | jfloat yMinf = hnd->dhnd->yMinf + 0.5f; \ | |||
132 | jfloat xMaxf = hnd->dhnd->xMaxf + 0.5f; \ | |||
133 | jfloat yMaxf = hnd->dhnd->yMaxf + 0.5f; \ | |||
134 | TESTANDCLIP(yMinf, yMaxf, Y0, X0, Y1, X1, jint, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (Y0 < (yMinf) || Y0 > (yMaxf)) { if (Y0 < (yMinf)) { if (Y1 < (yMinf )) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = (yMinf); } else { if (Y1 > (yMaxf)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (yMaxf); } X0 = (jint )(X0 + ((jdouble)(t - Y0)*(X1 - X0)) / (Y1 - Y0)); Y0 = (jint )t; } } while (0); \ | |||
135 | if (res == CRES_INVISIBLE) break; \ | |||
136 | TESTANDCLIP(yMinf, yMaxf, Y1, X1, Y0, X0, jint, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (Y1 < (yMinf) || Y1 > (yMaxf)) { if (Y1 < (yMinf)) { if (Y0 < (yMinf )) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = (yMinf); } else { if (Y0 > (yMaxf)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (yMaxf); } X1 = (jint )(X1 + ((jdouble)(t - Y1)*(X0 - X1)) / (Y0 - Y1)); Y1 = (jint )t; } } while (0); \ | |||
137 | if (res == CRES_INVISIBLE) break; \ | |||
138 | TESTANDCLIP(xMinf, xMaxf, X0, Y0, X1, Y1, jint, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (X0 < (xMinf) || X0 > (xMaxf)) { if (X0 < (xMinf)) { if (X1 < (xMinf )) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = (xMinf); } else { if (X1 > (xMaxf)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (xMaxf); } Y0 = (jint )(Y0 + ((jdouble)(t - X0)*(Y1 - Y0)) / (X1 - X0)); X0 = (jint )t; } } while (0); \ | |||
139 | if (res == CRES_INVISIBLE) break; \ | |||
140 | TESTANDCLIP(xMinf, xMaxf, X1, Y1, X0, Y0, jint, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (X1 < (xMinf) || X1 > (xMaxf)) { if (X1 < (xMinf)) { if (X0 < (xMinf )) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = (xMinf); } else { if (X0 > (xMaxf)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (xMaxf); } Y1 = (jint )(Y1 + ((jdouble)(t - X1)*(Y0 - Y1)) / (X0 - X1)); X1 = (jint )t; } } while (0); \ | |||
141 | if (res == CRES_INVISIBLE) break; \ | |||
142 | } \ | |||
143 | \ | |||
144 | /* Handling lines having just one pixel */ \ | |||
145 | if (((X0^X1) | (Y0^Y1)) == 0) { \ | |||
146 | if (pixelInfo[0] == 0) { \ | |||
147 | pixelInfo[0] = 1; \ | |||
148 | pixelInfo[1] = X0; \ | |||
149 | pixelInfo[2] = Y0; \ | |||
150 | pixelInfo[3] = X0; \ | |||
151 | pixelInfo[4] = Y0; \ | |||
152 | hnd->dhnd->pDrawPixel(hnd->dhnd, X0, Y0); \ | |||
153 | } else if ((X0 != pixelInfo[3] || Y0 != pixelInfo[4]) && \ | |||
154 | (X0 != pixelInfo[1] || Y0 != pixelInfo[2])) { \ | |||
155 | hnd->dhnd->pDrawPixel(hnd->dhnd, X0, Y0); \ | |||
156 | pixelInfo[3] = X0; \ | |||
157 | pixelInfo[4] = Y0; \ | |||
158 | } \ | |||
159 | break; \ | |||
160 | } \ | |||
161 | \ | |||
162 | if (pixelInfo[0] && \ | |||
163 | ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) || \ | |||
164 | (pixelInfo[3] == X0 && pixelInfo[4] == Y0))) \ | |||
165 | { \ | |||
166 | hnd->dhnd->pDrawPixel(hnd->dhnd, X0, Y0); \ | |||
167 | } \ | |||
168 | \ | |||
169 | hnd->dhnd->pDrawLine(hnd->dhnd, X0, Y0, X1, Y1); \ | |||
170 | \ | |||
171 | if (pixelInfo[0] == 0) { \ | |||
172 | pixelInfo[0] = 1; \ | |||
173 | pixelInfo[1] = X0; \ | |||
174 | pixelInfo[2] = Y0; \ | |||
175 | pixelInfo[3] = X0; \ | |||
176 | pixelInfo[4] = Y0; \ | |||
177 | } \ | |||
178 | \ | |||
179 | /* Switch on last pixel of the line if it was already \ | |||
180 | * drawn during rendering of the previous segments \ | |||
181 | */ \ | |||
182 | if ((pixelInfo[1] == X1 && pixelInfo[2] == Y1) || \ | |||
183 | (pixelInfo[3] == X1 && pixelInfo[4] == Y1)) \ | |||
184 | { \ | |||
185 | hnd->dhnd->pDrawPixel(hnd->dhnd, X1, Y1); \ | |||
186 | } \ | |||
187 | pixelInfo[3] = X1; \ | |||
188 | pixelInfo[4] = Y1; \ | |||
189 | } while(0) | |||
190 | ||||
191 | #define PROCESS_POINT(hnd, fX, fY, checkBounds, pixelInfo)do { jint X_ = (fX)>> 10; jint Y_ = (fY)>> 10; if (checkBounds && (hnd->dhnd->yMin > Y_ || hnd ->dhnd->yMax <= Y_ || hnd->dhnd->xMin > X_ || hnd->dhnd->xMax <= X_)) break; if (pixelInfo[0] == 0 ) { pixelInfo[0] = 1; pixelInfo[1] = X_; pixelInfo[2] = Y_; pixelInfo [3] = X_; pixelInfo[4] = Y_; hnd->dhnd->pDrawPixel(hnd-> dhnd, X_, Y_); } else if ((X_ != pixelInfo[3] || Y_ != pixelInfo [4]) && (X_ != pixelInfo[1] || Y_ != pixelInfo[2])) { hnd->dhnd->pDrawPixel(hnd->dhnd, X_, Y_); pixelInfo [3] = X_; pixelInfo[4] = Y_; } } while(0) \ | |||
192 | do { \ | |||
193 | jint X_ = (fX)>> MDP_PREC10; \ | |||
194 | jint Y_ = (fY)>> MDP_PREC10; \ | |||
195 | if (checkBounds && \ | |||
196 | (hnd->dhnd->yMin > Y_ || \ | |||
197 | hnd->dhnd->yMax <= Y_ || \ | |||
198 | hnd->dhnd->xMin > X_ || \ | |||
199 | hnd->dhnd->xMax <= X_)) break; \ | |||
200 | /* \ | |||
201 | * (X_,Y_) should be inside boundaries \ | |||
202 | * \ | |||
203 | * assert(hnd->dhnd->yMin <= Y_ && \ | |||
204 | * hnd->dhnd->yMax > Y_ && \ | |||
205 | * hnd->dhnd->xMin <= X_ && \ | |||
206 | * hnd->dhnd->xMax > X_); \ | |||
207 | * \ | |||
208 | */ \ | |||
209 | if (pixelInfo[0] == 0) { \ | |||
210 | pixelInfo[0] = 1; \ | |||
211 | pixelInfo[1] = X_; \ | |||
212 | pixelInfo[2] = Y_; \ | |||
213 | pixelInfo[3] = X_; \ | |||
214 | pixelInfo[4] = Y_; \ | |||
215 | hnd->dhnd->pDrawPixel(hnd->dhnd, X_, Y_); \ | |||
216 | } else if ((X_ != pixelInfo[3] || Y_ != pixelInfo[4]) && \ | |||
217 | (X_ != pixelInfo[1] || Y_ != pixelInfo[2])) { \ | |||
218 | hnd->dhnd->pDrawPixel(hnd->dhnd, X_, Y_); \ | |||
219 | pixelInfo[3] = X_; \ | |||
220 | pixelInfo[4] = Y_; \ | |||
221 | } \ | |||
222 | } while(0) | |||
223 | ||||
224 | ||||
225 | /* | |||
226 | * Constants for the forward differencing | |||
227 | * of the cubic and quad curves | |||
228 | */ | |||
229 | ||||
230 | /* Maximum size of the cubic curve (calculated as the size of the bounding box | |||
231 | * of the control points) which could be rendered without splitting | |||
232 | */ | |||
233 | #define MAX_CUB_SIZE256 256 | |||
234 | ||||
235 | /* Maximum size of the quad curve (calculated as the size of the bounding box | |||
236 | * of the control points) which could be rendered without splitting | |||
237 | */ | |||
238 | #define MAX_QUAD_SIZE1024 1024 | |||
239 | ||||
240 | /* Default power of 2 steps used in the forward differencing. Here DF prefix | |||
241 | * stands for DeFault. Constants below are used as initial values for the | |||
242 | * adaptive forward differencing algorithm. | |||
243 | */ | |||
244 | #define DF_CUB_STEPS3 3 | |||
245 | #define DF_QUAD_STEPS2 2 | |||
246 | ||||
247 | /* Shift of the current point of the curve for preparing to the midpoint | |||
248 | * rounding | |||
249 | */ | |||
250 | #define DF_CUB_SHIFT(7 + 3*3 - 10) (FWD_PREC7 + DF_CUB_STEPS3*3 - MDP_PREC10) | |||
251 | #define DF_QUAD_SHIFT(7 + 2*2 - 10) (FWD_PREC7 + DF_QUAD_STEPS2*2 - MDP_PREC10) | |||
252 | ||||
253 | /* Default amount of steps of the forward differencing */ | |||
254 | #define DF_CUB_COUNT(1<<3) (1<<DF_CUB_STEPS3) | |||
255 | #define DF_QUAD_COUNT(1<<2) (1<<DF_QUAD_STEPS2) | |||
256 | ||||
257 | /* Default boundary constants used to check the necessity of the restepping */ | |||
258 | #define DF_CUB_DEC_BND(1<<(3*3 + 7 + 2)) (1<<(DF_CUB_STEPS3*3 + FWD_PREC7 + 2)) | |||
259 | #define DF_CUB_INC_BND(1<<(3*3 + 7 - 1)) (1<<(DF_CUB_STEPS3*3 + FWD_PREC7 - 1)) | |||
260 | #define DF_QUAD_DEC_BND(1<<(2*2 + 7 + 2)) (1<<(DF_QUAD_STEPS2*2 + FWD_PREC7 + 2)) | |||
261 | ||||
262 | /* Multiplyers for the coefficients of the polynomial form of the cubic and | |||
263 | * quad curves representation | |||
264 | */ | |||
265 | #define CUB_A_SHIFT7 FWD_PREC7 | |||
266 | #define CUB_B_SHIFT(3 + 7 + 1) (DF_CUB_STEPS3 + FWD_PREC7 + 1) | |||
267 | #define CUB_C_SHIFT(3*2 + 7) (DF_CUB_STEPS3*2 + FWD_PREC7) | |||
268 | ||||
269 | #define CUB_A_MDP_MULT(1<<7) (1<<CUB_A_SHIFT7) | |||
270 | #define CUB_B_MDP_MULT(1<<(3 + 7 + 1)) (1<<CUB_B_SHIFT(3 + 7 + 1)) | |||
271 | #define CUB_C_MDP_MULT(1<<(3*2 + 7)) (1<<CUB_C_SHIFT(3*2 + 7)) | |||
272 | ||||
273 | #define QUAD_A_SHIFT7 FWD_PREC7 | |||
274 | #define QUAD_B_SHIFT(2 + 7) (DF_QUAD_STEPS2 + FWD_PREC7) | |||
275 | ||||
276 | #define QUAD_A_MDP_MULT(1<<7) (1<<QUAD_A_SHIFT7) | |||
277 | #define QUAD_B_MDP_MULT(1<<(2 + 7)) (1<<QUAD_B_SHIFT(2 + 7)) | |||
278 | ||||
279 | #define CALC_MAX(MAX, X)((MAX)=((X)>(MAX))?(X):(MAX)) ((MAX)=((X)>(MAX))?(X):(MAX)) | |||
280 | #define CALC_MIN(MIN, X)((MIN)=((X)<(MIN))?(X):(MIN)) ((MIN)=((X)<(MIN))?(X):(MIN)) | |||
281 | #define MAX(MAX, X)(((X)>(MAX))?(X):(MAX)) (((X)>(MAX))?(X):(MAX)) | |||
282 | #define MIN(MIN, X)(((X)<(MIN))?(X):(MIN)) (((X)<(MIN))?(X):(MIN)) | |||
283 | #define ABS32(X)(((X)^((X)>>31))-((X)>>31)) (((X)^((X)>>31))-((X)>>31)) | |||
284 | #define SIGN32(X)((X) >> 31) | ((juint)(-(X)) >> 31) ((X) >> 31) | ((juint)(-(X)) >> 31) | |||
285 | ||||
286 | /* Boundaries used for clipping large path segments (those are inside | |||
287 | * [UPPER/LOWER]_BND boundaries) | |||
288 | */ | |||
289 | #define UPPER_OUT_BND(1 << (30 - 10)) (1 << (30 - MDP_PREC10)) | |||
290 | #define LOWER_OUT_BND(-(1 << (30 - 10))) (-UPPER_OUT_BND(1 << (30 - 10))) | |||
291 | ||||
292 | #define ADJUST(X, LBND, UBND)do { if ((X) < (LBND)) { (X) = (LBND); } else if ((X) > UBND) { (X) = (UBND); } } while(0) \ | |||
293 | do { \ | |||
294 | if ((X) < (LBND)) { \ | |||
295 | (X) = (LBND); \ | |||
296 | } else if ((X) > UBND) { \ | |||
297 | (X) = (UBND); \ | |||
298 | } \ | |||
299 | } while(0) | |||
300 | ||||
301 | /* Following constants are used for providing open boundaries of the intervals | |||
302 | */ | |||
303 | #define EPSFX1 1 | |||
304 | #define EPSF(((jfloat)1)/(1<<10)) (((jfloat)EPSFX1)/MDP_MULT(1<<10)) | |||
305 | ||||
306 | /* Calculation boundary. It is used for switching to the more slow but allowing | |||
307 | * larger input values method of calculation of the initial values of the scan | |||
308 | * converted line segments inside the FillPolygon. | |||
309 | */ | |||
310 | #define CALC_BND(1 << (30 - 10)) (1 << (30 - MDP_PREC10)) | |||
311 | ||||
312 | /* Clipping macros for drawing and filling algorithms */ | |||
313 | ||||
314 | #define CLIP(a1, b1, a2, b2, t)(b1 + ((jdouble)(t - a1)*(b2 - b1)) / (a2 - a1)) \ | |||
315 | (b1 + ((jdouble)(t - a1)*(b2 - b1)) / (a2 - a1)) | |||
316 | ||||
317 | enum { | |||
318 | CRES_MIN_CLIPPED, | |||
319 | CRES_MAX_CLIPPED, | |||
320 | CRES_NOT_CLIPPED, | |||
321 | CRES_INVISIBLE | |||
322 | }; | |||
323 | ||||
324 | #define IS_CLIPPED(res)(res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED) (res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED) | |||
325 | ||||
326 | #define TESTANDCLIP(LINE_MIN, LINE_MAX, a1, b1, a2, b2, TYPE, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (a1 < (LINE_MIN ) || a1 > (LINE_MAX)) { if (a1 < (LINE_MIN)) { if (a2 < (LINE_MIN)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED ; t = (LINE_MIN); } else { if (a2 > (LINE_MAX)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (LINE_MAX); } b1 = (TYPE )(b1 + ((jdouble)(t - a1)*(b2 - b1)) / (a2 - a1)); a1 = (TYPE )t; } } while (0) \ | |||
327 | do { \ | |||
328 | jdouble t; \ | |||
329 | res = CRES_NOT_CLIPPED; \ | |||
330 | if (a1 < (LINE_MIN) || a1 > (LINE_MAX)) { \ | |||
331 | if (a1 < (LINE_MIN)) { \ | |||
332 | if (a2 < (LINE_MIN)) { \ | |||
333 | res = CRES_INVISIBLE; \ | |||
334 | break; \ | |||
335 | }; \ | |||
336 | res = CRES_MIN_CLIPPED; \ | |||
337 | t = (LINE_MIN); \ | |||
338 | } else { \ | |||
339 | if (a2 > (LINE_MAX)) { \ | |||
340 | res = CRES_INVISIBLE; \ | |||
341 | break; \ | |||
342 | }; \ | |||
343 | res = CRES_MAX_CLIPPED; \ | |||
344 | t = (LINE_MAX); \ | |||
345 | } \ | |||
346 | b1 = (TYPE)CLIP(a1, b1, a2, b2, t)(b1 + ((jdouble)(t - a1)*(b2 - b1)) / (a2 - a1)); \ | |||
347 | a1 = (TYPE)t; \ | |||
348 | } \ | |||
349 | } while (0) | |||
350 | ||||
351 | /* Following macro is used for clipping and clumping filled shapes. | |||
352 | * An example of this process is shown on the picture below: | |||
353 | * ----+ ----+ | |||
354 | * |/ | |/ | | |||
355 | * + | + | | |||
356 | * /| | I | | |||
357 | * / | | I | | |||
358 | * | | | ===> I | | |||
359 | * \ | | I | | |||
360 | * \| | I | | |||
361 | * + | + | | |||
362 | * |\ | |\ | | |||
363 | * | ----+ | ----+ | |||
364 | * boundary boundary | |||
365 | * | |||
366 | * We can only perform clipping in case of right side of the output area | |||
367 | * because all segments passed out the right boundary don't influence on the | |||
368 | * result of scan conversion algorithm (it correctly handles half open | |||
369 | * contours). | |||
370 | * | |||
371 | */ | |||
372 | #define CLIPCLAMP(LINE_MIN, LINE_MAX, a1, b1, a2, b2, a3, b3, TYPE, res)do { a3 = a1; b3 = b1; do { jdouble t; res = CRES_NOT_CLIPPED ; if (a1 < (LINE_MIN) || a1 > (LINE_MAX)) { if (a1 < (LINE_MIN)) { if (a2 < (LINE_MIN)) { res = CRES_INVISIBLE ; break; }; res = CRES_MIN_CLIPPED; t = (LINE_MIN); } else { if (a2 > (LINE_MAX)) { res = CRES_INVISIBLE; break; }; res = CRES_MAX_CLIPPED; t = (LINE_MAX); } b1 = (TYPE)(b1 + ((jdouble )(t - a1)*(b2 - b1)) / (a2 - a1)); a1 = (TYPE)t; } } while (0 ); if (res == CRES_MIN_CLIPPED) { a3 = a1; } else if (res == CRES_MAX_CLIPPED ) { a3 = a1; res = CRES_MAX_CLIPPED; } else if (res == CRES_INVISIBLE ) { if (a1 > LINE_MAX) { res = CRES_INVISIBLE; } else { a1 = (TYPE)LINE_MIN; a2 = (TYPE)LINE_MIN; res = CRES_NOT_CLIPPED ; } } } while (0) \ | |||
373 | do { \ | |||
374 | a3 = a1; \ | |||
375 | b3 = b1; \ | |||
376 | TESTANDCLIP(LINE_MIN, LINE_MAX, a1, b1, a2, b2, TYPE, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (a1 < (LINE_MIN ) || a1 > (LINE_MAX)) { if (a1 < (LINE_MIN)) { if (a2 < (LINE_MIN)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED ; t = (LINE_MIN); } else { if (a2 > (LINE_MAX)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (LINE_MAX); } b1 = (TYPE )(b1 + ((jdouble)(t - a1)*(b2 - b1)) / (a2 - a1)); a1 = (TYPE )t; } } while (0); \ | |||
377 | if (res == CRES_MIN_CLIPPED) { \ | |||
378 | a3 = a1; \ | |||
379 | } else if (res == CRES_MAX_CLIPPED) { \ | |||
380 | a3 = a1; \ | |||
381 | res = CRES_MAX_CLIPPED; \ | |||
382 | } else if (res == CRES_INVISIBLE) { \ | |||
383 | if (a1 > LINE_MAX) { \ | |||
384 | res = CRES_INVISIBLE; \ | |||
385 | } else { \ | |||
386 | a1 = (TYPE)LINE_MIN; \ | |||
387 | a2 = (TYPE)LINE_MIN; \ | |||
388 | res = CRES_NOT_CLIPPED; \ | |||
389 | } \ | |||
390 | } \ | |||
391 | } while (0) | |||
392 | ||||
393 | /* Following macro is used for solving quadratic equations: | |||
394 | * A*t^2 + B*t + C = 0 | |||
395 | * in (0,1) range. That means we put to the RES the only roots which | |||
396 | * belongs to the (0,1) range. Note: 0 and 1 are not included. | |||
397 | * See solveQuadratic method in | |||
398 | * src/share/classes/java/awt/geom/QuadCurve2D.java | |||
399 | * for more info about calculations | |||
400 | */ | |||
401 | #define SOLVEQUADINRANGE(A,B,C,RES,RCNT)do { double param; if ((A) != 0) { double d = (B)*(B) - 4*(A) *(C); double q; if (d < 0) { break; } d = sqrt(d); if ((B) < 0) { d = -d; } q = ((B) + d) / -2.0; param = q/(A); if ( param < 1.0 && param > 0.0) { (RES)[(RCNT)++] = param; } if (d == 0 || q == 0) { break; } param = (C)/q; if ( param < 1.0 && param > 0.0) { (RES)[(RCNT)++] = param; } } else { if ((B) == 0) { break; } param = -(C)/(B); if (param < 1.0 && param > 0.0) { (RES)[(RCNT) ++] = param; } } } while(0) \ | |||
402 | do { \ | |||
403 | double param; \ | |||
404 | if ((A) != 0) { \ | |||
405 | /* Calculating roots of the following equation \ | |||
406 | * A*t^2 + B*t + C = 0 \ | |||
407 | */ \ | |||
408 | double d = (B)*(B) - 4*(A)*(C); \ | |||
409 | double q; \ | |||
410 | if (d < 0) { \ | |||
411 | break; \ | |||
412 | } \ | |||
413 | d = sqrt(d); \ | |||
414 | /* For accuracy, calculate one root using: \ | |||
415 | * (-B +/- d) / 2*A \ | |||
416 | * and the other using: \ | |||
417 | * 2*C / (-B +/- d) \ | |||
418 | * Choose the sign of the +/- so that B+D gets larger \ | |||
419 | * in magnitude \ | |||
420 | */ \ | |||
421 | if ((B) < 0) { \ | |||
422 | d = -d; \ | |||
423 | } \ | |||
424 | q = ((B) + d) / -2.0; \ | |||
425 | param = q/(A); \ | |||
426 | if (param < 1.0 && param > 0.0) { \ | |||
427 | (RES)[(RCNT)++] = param; \ | |||
428 | } \ | |||
429 | if (d == 0 || q == 0) { \ | |||
430 | break; \ | |||
431 | } \ | |||
432 | param = (C)/q; \ | |||
433 | if (param < 1.0 && param > 0.0) { \ | |||
434 | (RES)[(RCNT)++] = param; \ | |||
435 | } \ | |||
436 | } else { \ | |||
437 | /* Calculating root of the following equation \ | |||
438 | * B*t + C = 0 \ | |||
439 | */ \ | |||
440 | if ((B) == 0) { \ | |||
441 | break; \ | |||
442 | } \ | |||
443 | param = -(C)/(B); \ | |||
444 | if (param < 1.0 && param > 0.0) { \ | |||
445 | (RES)[(RCNT)++] = param; \ | |||
446 | } \ | |||
447 | } \ | |||
448 | } while(0) | |||
449 | ||||
450 | /* Drawing line with subpixel endpoints | |||
451 | * | |||
452 | * (x1, y1), (x2, y2) - fixed point coordinates of the endpoints | |||
453 | * with MDP_PREC bits for the fractional part | |||
454 | * | |||
455 | * pixelInfo - structure which keeps drawing info for avoiding | |||
456 | * multiple drawing at the same position on the | |||
457 | * screen (required for the XOR mode of drawing) | |||
458 | * | |||
459 | * pixelInfo[0] - state of the drawing | |||
460 | * 0 - no pixel drawn between | |||
461 | * moveTo/close of the path | |||
462 | * 1 - there are drawn pixels | |||
463 | * | |||
464 | * pixelInfo[1,2] - first pixel of the path | |||
465 | * between moveTo/close of the | |||
466 | * path | |||
467 | * | |||
468 | * pixelInfo[3,4] - last drawn pixel between | |||
469 | * moveTo/close of the path | |||
470 | * | |||
471 | * checkBounds - flag showing necessity of checking the clip | |||
472 | * | |||
473 | */ | |||
474 | void ProcessFixedLine(ProcessHandler* hnd,jint x1,jint y1,jint x2,jint y2, | |||
475 | jint* pixelInfo,jboolean checkBounds, | |||
476 | jboolean endSubPath) | |||
477 | { | |||
478 | /* Checking if line is inside a (X,Y),(X+MDP_MULT,Y+MDP_MULT) box */ | |||
479 | jint c = ((x1 ^ x2) | (y1 ^ y2)); | |||
480 | jint rx1, ry1, rx2, ry2; | |||
481 | if ((c & MDP_W_MASK(-(1<<10))) == 0) { | |||
482 | /* Checking for the segments with integer coordinates having | |||
483 | * the same start and end points | |||
484 | */ | |||
485 | if (c == 0) { | |||
486 | PROCESS_POINT(hnd, x1 + MDP_HALF_MULT, y1 + MDP_HALF_MULT,do { jint X_ = (x1 + ((1<<10) >> 1))>> 10; jint Y_ = (y1 + ((1<<10) >> 1))>> 10; if (checkBounds && (hnd->dhnd->yMin > Y_ || hnd->dhnd-> yMax <= Y_ || hnd->dhnd->xMin > X_ || hnd->dhnd ->xMax <= X_)) break; if (pixelInfo[0] == 0) { pixelInfo [0] = 1; pixelInfo[1] = X_; pixelInfo[2] = Y_; pixelInfo[3] = X_; pixelInfo[4] = Y_; hnd->dhnd->pDrawPixel(hnd->dhnd , X_, Y_); } else if ((X_ != pixelInfo[3] || Y_ != pixelInfo[ 4]) && (X_ != pixelInfo[1] || Y_ != pixelInfo[2])) { hnd ->dhnd->pDrawPixel(hnd->dhnd, X_, Y_); pixelInfo[3] = X_; pixelInfo[4] = Y_; } } while(0) | |||
487 | checkBounds, pixelInfo)do { jint X_ = (x1 + ((1<<10) >> 1))>> 10; jint Y_ = (y1 + ((1<<10) >> 1))>> 10; if (checkBounds && (hnd->dhnd->yMin > Y_ || hnd->dhnd-> yMax <= Y_ || hnd->dhnd->xMin > X_ || hnd->dhnd ->xMax <= X_)) break; if (pixelInfo[0] == 0) { pixelInfo [0] = 1; pixelInfo[1] = X_; pixelInfo[2] = Y_; pixelInfo[3] = X_; pixelInfo[4] = Y_; hnd->dhnd->pDrawPixel(hnd->dhnd , X_, Y_); } else if ((X_ != pixelInfo[3] || Y_ != pixelInfo[ 4]) && (X_ != pixelInfo[1] || Y_ != pixelInfo[2])) { hnd ->dhnd->pDrawPixel(hnd->dhnd, X_, Y_); pixelInfo[3] = X_; pixelInfo[4] = Y_; } } while(0); | |||
488 | } | |||
489 | return; | |||
490 | } | |||
491 | ||||
492 | if (x1 == x2 || y1 == y2) { | |||
493 | rx1 = x1 + MDP_HALF_MULT((1<<10) >> 1); | |||
494 | rx2 = x2 + MDP_HALF_MULT((1<<10) >> 1); | |||
495 | ry1 = y1 + MDP_HALF_MULT((1<<10) >> 1); | |||
496 | ry2 = y2 + MDP_HALF_MULT((1<<10) >> 1); | |||
497 | } else { | |||
498 | /* Neither dx nor dy can be zero because of the check above */ | |||
499 | jint dx = x2 - x1; | |||
500 | jint dy = y2 - y1; | |||
501 | ||||
502 | /* Floor of x1, y1, x2, y2 */ | |||
503 | jint fx1 = x1 & MDP_W_MASK(-(1<<10)); | |||
504 | jint fy1 = y1 & MDP_W_MASK(-(1<<10)); | |||
505 | jint fx2 = x2 & MDP_W_MASK(-(1<<10)); | |||
506 | jint fy2 = y2 & MDP_W_MASK(-(1<<10)); | |||
507 | ||||
508 | /* Processing first endpoint */ | |||
509 | if (fx1 == x1 || fy1 == y1) { | |||
510 | /* Adding MDP_HALF_MULT to the [xy]1 if f[xy]1 == [xy]1 will not | |||
511 | * affect the result | |||
512 | */ | |||
513 | rx1 = x1 + MDP_HALF_MULT((1<<10) >> 1); | |||
514 | ry1 = y1 + MDP_HALF_MULT((1<<10) >> 1); | |||
515 | } else { | |||
516 | /* Boundary at the direction from (x1,y1) to (x2,y2) */ | |||
517 | jint bx1 = (x1 < x2) ? fx1 + MDP_MULT(1<<10) : fx1; | |||
518 | jint by1 = (y1 < y2) ? fy1 + MDP_MULT(1<<10) : fy1; | |||
519 | ||||
520 | /* intersection with column bx1 */ | |||
521 | jint cross = y1 + ((bx1 - x1)*dy)/dx; | |||
522 | if (cross >= fy1 && cross <= fy1 + MDP_MULT(1<<10)) { | |||
523 | rx1 = bx1; | |||
524 | ry1 = cross + MDP_HALF_MULT((1<<10) >> 1); | |||
525 | } else { | |||
526 | /* intersection with row by1 */ | |||
527 | cross = x1 + ((by1 - y1)*dx)/dy; | |||
528 | rx1 = cross + MDP_HALF_MULT((1<<10) >> 1); | |||
529 | ry1 = by1; | |||
530 | } | |||
531 | } | |||
532 | ||||
533 | /* Processing second endpoint */ | |||
534 | if (fx2 == x2 || fy2 == y2) { | |||
535 | /* Adding MDP_HALF_MULT to the [xy]2 if f[xy]2 == [xy]2 will not | |||
536 | * affect the result | |||
537 | */ | |||
538 | rx2 = x2 + MDP_HALF_MULT((1<<10) >> 1); | |||
539 | ry2 = y2 + MDP_HALF_MULT((1<<10) >> 1); | |||
540 | } else { | |||
541 | /* Boundary at the direction from (x2,y2) to (x1,y1) */ | |||
542 | jint bx2 = (x1 > x2) ? fx2 + MDP_MULT(1<<10) : fx2; | |||
543 | jint by2 = (y1 > y2) ? fy2 + MDP_MULT(1<<10) : fy2; | |||
544 | ||||
545 | /* intersection with column bx2 */ | |||
546 | jint cross = y2 + ((bx2 - x2)*dy)/dx; | |||
547 | if (cross >= fy2 && cross <= fy2 + MDP_MULT(1<<10)) { | |||
548 | rx2 = bx2; | |||
549 | ry2 = cross + MDP_HALF_MULT((1<<10) >> 1); | |||
550 | } else { | |||
551 | /* intersection with row by2 */ | |||
552 | cross = x2 + ((by2 - y2)*dx)/dy; | |||
553 | rx2 = cross + MDP_HALF_MULT((1<<10) >> 1); | |||
554 | ry2 = by2; | |||
555 | } | |||
556 | } | |||
557 | } | |||
558 | ||||
559 | PROCESS_LINE(hnd, rx1, ry1, rx2, ry2, checkBounds, pixelInfo)do { jint X0 = (rx1) >> 10; jint Y0 = (ry1) >> 10 ; jint X1 = (rx2) >> 10; jint Y1 = (ry2) >> 10; jint res; if (checkBounds) { jfloat xMinf = hnd->dhnd->xMinf + 0.5f; jfloat yMinf = hnd->dhnd->yMinf + 0.5f; jfloat xMaxf = hnd->dhnd->xMaxf + 0.5f; jfloat yMaxf = hnd-> dhnd->yMaxf + 0.5f; do { jdouble t; res = CRES_NOT_CLIPPED ; if (Y0 < (yMinf) || Y0 > (yMaxf)) { if (Y0 < (yMinf )) { if (Y1 < (yMinf)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = (yMinf); } else { if (Y1 > (yMaxf )) { res = CRES_INVISIBLE; break; }; res = CRES_MAX_CLIPPED; t = (yMaxf); } X0 = (jint)(X0 + ((jdouble)(t - Y0)*(X1 - X0)) / (Y1 - Y0)); Y0 = (jint)t; } } while (0); if (res == CRES_INVISIBLE ) break; do { jdouble t; res = CRES_NOT_CLIPPED; if (Y1 < ( yMinf) || Y1 > (yMaxf)) { if (Y1 < (yMinf)) { if (Y0 < (yMinf)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED ; t = (yMinf); } else { if (Y0 > (yMaxf)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (yMaxf); } X1 = (jint )(X1 + ((jdouble)(t - Y1)*(X0 - X1)) / (Y0 - Y1)); Y1 = (jint )t; } } while (0); if (res == CRES_INVISIBLE) break; do { jdouble t; res = CRES_NOT_CLIPPED; if (X0 < (xMinf) || X0 > (xMaxf )) { if (X0 < (xMinf)) { if (X1 < (xMinf)) { res = CRES_INVISIBLE ; break; }; res = CRES_MIN_CLIPPED; t = (xMinf); } else { if ( X1 > (xMaxf)) { res = CRES_INVISIBLE; break; }; res = CRES_MAX_CLIPPED ; t = (xMaxf); } Y0 = (jint)(Y0 + ((jdouble)(t - X0)*(Y1 - Y0 )) / (X1 - X0)); X0 = (jint)t; } } while (0); if (res == CRES_INVISIBLE ) break; do { jdouble t; res = CRES_NOT_CLIPPED; if (X1 < ( xMinf) || X1 > (xMaxf)) { if (X1 < (xMinf)) { if (X0 < (xMinf)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED ; t = (xMinf); } else { if (X0 > (xMaxf)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (xMaxf); } Y1 = (jint )(Y1 + ((jdouble)(t - X1)*(Y0 - Y1)) / (X0 - X1)); X1 = (jint )t; } } while (0); if (res == CRES_INVISIBLE) break; } if ((( X0^X1) | (Y0^Y1)) == 0) { if (pixelInfo[0] == 0) { pixelInfo[ 0] = 1; pixelInfo[1] = X0; pixelInfo[2] = Y0; pixelInfo[3] = X0 ; pixelInfo[4] = Y0; hnd->dhnd->pDrawPixel(hnd->dhnd , X0, Y0); } else if ((X0 != pixelInfo[3] || Y0 != pixelInfo[ 4]) && (X0 != pixelInfo[1] || Y0 != pixelInfo[2])) { hnd ->dhnd->pDrawPixel(hnd->dhnd, X0, Y0); pixelInfo[3] = X0; pixelInfo[4] = Y0; } break; } if (pixelInfo[0] && ((pixelInfo[1] == X0 && pixelInfo[2] == Y0) || (pixelInfo [3] == X0 && pixelInfo[4] == Y0))) { hnd->dhnd-> pDrawPixel(hnd->dhnd, X0, Y0); } hnd->dhnd->pDrawLine (hnd->dhnd, X0, Y0, X1, Y1); if (pixelInfo[0] == 0) { pixelInfo [0] = 1; pixelInfo[1] = X0; pixelInfo[2] = Y0; pixelInfo[3] = X0; pixelInfo[4] = Y0; } if ((pixelInfo[1] == X1 && pixelInfo [2] == Y1) || (pixelInfo[3] == X1 && pixelInfo[4] == Y1 )) { hnd->dhnd->pDrawPixel(hnd->dhnd, X1, Y1); } pixelInfo [3] = X1; pixelInfo[4] = Y1; } while(0); | |||
560 | } | |||
561 | ||||
562 | /* Performing drawing of the monotonic in X and Y quadratic curves with sizes | |||
563 | * less than MAX_QUAD_SIZE by using forward differencing method of calculation. | |||
564 | * See comments to the DrawMonotonicCubic. | |||
565 | */ | |||
566 | static void DrawMonotonicQuad(ProcessHandler* hnd, | |||
567 | jfloat *coords, | |||
568 | jboolean checkBounds, | |||
569 | jint* pixelInfo) | |||
570 | { | |||
571 | jint x0 = (jint)(coords[0]*MDP_MULT(1<<10)); | |||
572 | jint y0 = (jint)(coords[1]*MDP_MULT(1<<10)); | |||
573 | ||||
574 | jint xe = (jint)(coords[4]*MDP_MULT(1<<10)); | |||
575 | jint ye = (jint)(coords[5]*MDP_MULT(1<<10)); | |||
576 | ||||
577 | /* Extracting fractional part of coordinates of first control point */ | |||
578 | jint px = (x0 & (~MDP_W_MASK(-(1<<10)))) << DF_QUAD_SHIFT(7 + 2*2 - 10); | |||
579 | jint py = (y0 & (~MDP_W_MASK(-(1<<10)))) << DF_QUAD_SHIFT(7 + 2*2 - 10); | |||
580 | ||||
581 | /* Setting default amount of steps */ | |||
582 | jint count = DF_QUAD_COUNT(1<<2); | |||
583 | ||||
584 | /* Setting default shift for preparing to the midpoint rounding */ | |||
585 | jint shift = DF_QUAD_SHIFT(7 + 2*2 - 10); | |||
586 | ||||
587 | jint ax = (jint)((coords[0] - 2*coords[2] + | |||
588 | coords[4])*QUAD_A_MDP_MULT(1<<7)); | |||
589 | jint ay = (jint)((coords[1] - 2*coords[3] + | |||
590 | coords[5])*QUAD_A_MDP_MULT(1<<7)); | |||
591 | ||||
592 | jint bx = (jint)((-2*coords[0] + 2*coords[2])*QUAD_B_MDP_MULT(1<<(2 + 7))); | |||
593 | jint by = (jint)((-2*coords[1] + 2*coords[3])*QUAD_B_MDP_MULT(1<<(2 + 7))); | |||
594 | ||||
595 | jint ddpx = 2*ax; | |||
596 | jint ddpy = 2*ay; | |||
597 | ||||
598 | jint dpx = ax + bx; | |||
599 | jint dpy = ay + by; | |||
600 | ||||
601 | jint x1, y1; | |||
602 | ||||
603 | jint x2 = x0; | |||
604 | jint y2 = y0; | |||
605 | ||||
606 | jint maxDD = MAX(ABS32(ddpx),ABS32(ddpy))((((((ddpy)^((ddpy)>>31))-((ddpy)>>31)))>((((ddpx )^((ddpx)>>31))-((ddpx)>>31))))?((((ddpy)^((ddpy) >>31))-((ddpy)>>31))):((((ddpx)^((ddpx)>>31 ))-((ddpx)>>31)))); | |||
607 | jint x0w = x0 & MDP_W_MASK(-(1<<10)); | |||
608 | jint y0w = y0 & MDP_W_MASK(-(1<<10)); | |||
609 | ||||
610 | jint dx = xe - x0; | |||
611 | jint dy = ye - y0; | |||
612 | ||||
613 | /* Perform decreasing step in 2 times if slope of the second forward | |||
614 | * difference changes too quickly (more than a pixel per step in X or Y | |||
615 | * direction). We can perform adjusting of the step size before the | |||
616 | * rendering loop because the curvature of the quad curve remains the same | |||
617 | * along all the curve | |||
618 | */ | |||
619 | while (maxDD > DF_QUAD_DEC_BND(1<<(2*2 + 7 + 2))) { | |||
620 | dpx = (dpx<<1) - ax; | |||
621 | dpy = (dpy<<1) - ay; | |||
622 | count <<= 1; | |||
623 | maxDD >>= 2; | |||
624 | px <<=2; | |||
625 | py <<=2; | |||
626 | shift += 2; | |||
627 | } | |||
628 | ||||
629 | while(count-- > 1) { | |||
630 | ||||
631 | px += dpx; | |||
632 | py += dpy; | |||
633 | ||||
634 | dpx += ddpx; | |||
635 | dpy += ddpy; | |||
636 | ||||
637 | x1 = x2; | |||
638 | y1 = y2; | |||
639 | ||||
640 | x2 = x0w + (px >> shift); | |||
641 | y2 = y0w + (py >> shift); | |||
642 | ||||
643 | /* Checking that we are not running out of the endpoint and bounding | |||
644 | * violating coordinate. The check is pretty simple because the curve | |||
645 | * passed to the DrawMonotonicQuad already split into the monotonic | |||
646 | * in X and Y pieces | |||
647 | */ | |||
648 | ||||
649 | /* Bounding x2 by xe */ | |||
650 | if (((xe-x2)^dx) < 0) { | |||
651 | x2 = xe; | |||
652 | } | |||
653 | ||||
654 | /* Bounding y2 by ye */ | |||
655 | if (((ye-y2)^dy) < 0) { | |||
656 | y2 = ye; | |||
657 | } | |||
658 | ||||
659 | hnd->pProcessFixedLine(hnd, x1, y1, x2, y2, pixelInfo, checkBounds, | |||
660 | JNI_FALSE0); | |||
661 | } | |||
662 | ||||
663 | /* We are performing one step less than necessary and use actual (xe,ye) | |||
664 | * curve's endpoint instead of calculated. This prevent us from accumulated | |||
665 | * errors at the last point. | |||
666 | */ | |||
667 | ||||
668 | hnd->pProcessFixedLine(hnd, x2, y2, xe, ye, pixelInfo, checkBounds, | |||
669 | JNI_FALSE0); | |||
670 | } | |||
671 | ||||
672 | /* | |||
673 | * Checking size of the quad curves and split them if necessary. | |||
674 | * Calling DrawMonotonicQuad for the curves of the appropriate size. | |||
675 | * Note: coords array could be changed | |||
676 | */ | |||
677 | static void ProcessMonotonicQuad(ProcessHandler* hnd, | |||
678 | jfloat *coords, | |||
679 | jint* pixelInfo) { | |||
680 | ||||
681 | jfloat coords1[6]; | |||
682 | jfloat xMin, xMax; | |||
683 | jfloat yMin, yMax; | |||
684 | ||||
685 | xMin = xMax = coords[0]; | |||
686 | yMin = yMax = coords[1]; | |||
687 | ||||
688 | CALC_MIN(xMin, coords[2])((xMin)=((coords[2])<(xMin))?(coords[2]):(xMin)); | |||
689 | CALC_MAX(xMax, coords[2])((xMax)=((coords[2])>(xMax))?(coords[2]):(xMax)); | |||
690 | CALC_MIN(yMin, coords[3])((yMin)=((coords[3])<(yMin))?(coords[3]):(yMin)); | |||
691 | CALC_MAX(yMax, coords[3])((yMax)=((coords[3])>(yMax))?(coords[3]):(yMax)); | |||
692 | CALC_MIN(xMin, coords[4])((xMin)=((coords[4])<(xMin))?(coords[4]):(xMin)); | |||
693 | CALC_MAX(xMax, coords[4])((xMax)=((coords[4])>(xMax))?(coords[4]):(xMax)); | |||
694 | CALC_MIN(yMin, coords[5])((yMin)=((coords[5])<(yMin))?(coords[5]):(yMin)); | |||
695 | CALC_MAX(yMax, coords[5])((yMax)=((coords[5])>(yMax))?(coords[5]):(yMax)); | |||
696 | ||||
697 | ||||
698 | if (hnd->clipMode == PH_MODE_DRAW_CLIP) { | |||
699 | ||||
700 | /* In case of drawing we could just skip curves which are completely | |||
701 | * out of bounds | |||
702 | */ | |||
703 | if (hnd->dhnd->xMaxf < xMin || hnd->dhnd->xMinf > xMax || | |||
704 | hnd->dhnd->yMaxf < yMin || hnd->dhnd->yMinf > yMax) { | |||
705 | return; | |||
706 | } | |||
707 | } else { | |||
708 | ||||
709 | /* In case of filling we could skip curves which are above, | |||
710 | * below and behind the right boundary of the visible area | |||
711 | */ | |||
712 | ||||
713 | if (hnd->dhnd->yMaxf < yMin || hnd->dhnd->yMinf > yMax || | |||
714 | hnd->dhnd->xMaxf < xMin) | |||
715 | { | |||
716 | return; | |||
717 | } | |||
718 | ||||
719 | /* We could clamp x coordinates to the corresponding boundary | |||
720 | * if the curve is completely behind the left one | |||
721 | */ | |||
722 | ||||
723 | if (hnd->dhnd->xMinf > xMax) { | |||
724 | coords[0] = coords[2] = coords[4] = hnd->dhnd->xMinf; | |||
725 | } | |||
726 | } | |||
727 | ||||
728 | if (xMax - xMin > MAX_QUAD_SIZE1024 || yMax - yMin > MAX_QUAD_SIZE1024) { | |||
729 | coords1[4] = coords[4]; | |||
730 | coords1[5] = coords[5]; | |||
731 | coords1[2] = (coords[2] + coords[4])/2.0f; | |||
732 | coords1[3] = (coords[3] + coords[5])/2.0f; | |||
733 | coords[2] = (coords[0] + coords[2])/2.0f; | |||
734 | coords[3] = (coords[1] + coords[3])/2.0f; | |||
735 | coords[4] = coords1[0] = (coords[2] + coords1[2])/2.0f; | |||
736 | coords[5] = coords1[1] = (coords[3] + coords1[3])/2.0f; | |||
737 | ||||
738 | ProcessMonotonicQuad(hnd, coords, pixelInfo); | |||
739 | ||||
740 | ProcessMonotonicQuad(hnd, coords1, pixelInfo); | |||
741 | } else { | |||
742 | DrawMonotonicQuad(hnd, coords, | |||
743 | /* Set checkBounds parameter if curve intersects | |||
744 | * boundary of the visible area. We know that the | |||
745 | * curve is visible, so the check is pretty simple | |||
746 | */ | |||
747 | hnd->dhnd->xMinf >= xMin || hnd->dhnd->xMaxf <= xMax || | |||
748 | hnd->dhnd->yMinf >= yMin || hnd->dhnd->yMaxf <= yMax, | |||
749 | pixelInfo); | |||
750 | } | |||
751 | } | |||
752 | ||||
753 | /* | |||
754 | * Bite the piece of the quadratic curve from start point till the point | |||
755 | * corresponding to the specified parameter then call ProcessQuad for the | |||
756 | * bitten part. | |||
757 | * Note: coords array will be changed | |||
758 | */ | |||
759 | static void ProcessFirstMonotonicPartOfQuad(ProcessHandler* hnd, jfloat* coords, | |||
760 | jint* pixelInfo, jfloat t) | |||
761 | { | |||
762 | jfloat coords1[6]; | |||
763 | ||||
764 | coords1[0] = coords[0]; | |||
765 | coords1[1] = coords[1]; | |||
766 | coords1[2] = coords[0] + t*(coords[2] - coords[0]); | |||
767 | coords1[3] = coords[1] + t*(coords[3] - coords[1]); | |||
768 | coords[2] = coords[2] + t*(coords[4] - coords[2]); | |||
769 | coords[3] = coords[3] + t*(coords[5] - coords[3]); | |||
770 | coords[0] = coords1[4] = coords1[2] + t*(coords[2] - coords1[2]); | |||
771 | coords[1] = coords1[5] = coords1[3] + t*(coords[3] - coords1[3]); | |||
772 | ||||
773 | ProcessMonotonicQuad(hnd, coords1, pixelInfo); | |||
774 | } | |||
775 | ||||
776 | /* | |||
777 | * Split quadratic curve into monotonic in X and Y parts. Calling | |||
778 | * ProcessMonotonicQuad for each monotonic piece of the curve. | |||
779 | * Note: coords array could be changed | |||
780 | */ | |||
781 | static void ProcessQuad(ProcessHandler* hnd, jfloat* coords, jint* pixelInfo) { | |||
782 | ||||
783 | /* Temporary array for holding parameters corresponding to the extreme in X | |||
784 | * and Y points. The values are inside the (0,1) range (0 and 1 excluded) | |||
785 | * and in ascending order. | |||
786 | */ | |||
787 | double params[2]; | |||
788 | ||||
789 | jint cnt = 0; | |||
790 | double param; | |||
791 | ||||
792 | /* Simple check for monotonicity in X before searching for the extreme | |||
793 | * points of the X(t) function. We first check if the curve is monotonic | |||
794 | * in X by seeing if all of the X coordinates are strongly ordered. | |||
795 | */ | |||
796 | if ((coords[0] > coords[2] || coords[2] > coords[4]) && | |||
797 | (coords[0] < coords[2] || coords[2] < coords[4])) | |||
798 | { | |||
799 | /* Searching for extreme points of the X(t) function by solving | |||
800 | * dX(t) | |||
801 | * ---- = 0 equation | |||
802 | * dt | |||
803 | */ | |||
804 | double ax = coords[0] - 2*coords[2] + coords[4]; | |||
805 | if (ax != 0) { | |||
806 | /* Calculating root of the following equation | |||
807 | * ax*t + bx = 0 | |||
808 | */ | |||
809 | double bx = coords[0] - coords[2]; | |||
810 | ||||
811 | param = bx/ax; | |||
812 | if (param < 1.0 && param > 0.0) { | |||
813 | params[cnt++] = param; | |||
814 | } | |||
815 | } | |||
816 | } | |||
817 | ||||
818 | /* Simple check for monotonicity in Y before searching for the extreme | |||
819 | * points of the Y(t) function. We first check if the curve is monotonic | |||
820 | * in Y by seeing if all of the Y coordinates are strongly ordered. | |||
821 | */ | |||
822 | if ((coords[1] > coords[3] || coords[3] > coords[5]) && | |||
823 | (coords[1] < coords[3] || coords[3] < coords[5])) | |||
824 | { | |||
825 | /* Searching for extreme points of the Y(t) function by solving | |||
826 | * dY(t) | |||
827 | * ----- = 0 equation | |||
828 | * dt | |||
829 | */ | |||
830 | double ay = coords[1] - 2*coords[3] + coords[5]; | |||
831 | ||||
832 | if (ay != 0) { | |||
833 | /* Calculating root of the following equation | |||
834 | * ay*t + by = 0 | |||
835 | */ | |||
836 | double by = coords[1] - coords[3]; | |||
837 | ||||
838 | param = by/ay; | |||
839 | if (param < 1.0 && param > 0.0) { | |||
840 | if (cnt > 0) { | |||
841 | /* Inserting parameter only if it differs from | |||
842 | * already stored | |||
843 | */ | |||
844 | if (params[0] > param) { | |||
845 | params[cnt++] = params[0]; | |||
846 | params[0] = param; | |||
847 | } else if (params[0] < param) { | |||
848 | params[cnt++] = param; | |||
849 | } | |||
850 | } else { | |||
851 | params[cnt++] = param; | |||
852 | } | |||
853 | } | |||
854 | } | |||
855 | } | |||
856 | ||||
857 | /* Processing obtained monotonic parts */ | |||
858 | switch(cnt) { | |||
859 | case 0: | |||
860 | break; | |||
861 | case 1: | |||
862 | ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, | |||
863 | (jfloat)params[0]); | |||
864 | break; | |||
865 | case 2: | |||
866 | ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, | |||
867 | (jfloat)params[0]); | |||
868 | param = params[1] - params[0]; | |||
869 | if (param > 0) { | |||
870 | ProcessFirstMonotonicPartOfQuad(hnd, coords, pixelInfo, | |||
871 | /* Scale parameter to match with rest of the curve */ | |||
872 | (jfloat)(param/(1.0 - params[0]))); | |||
873 | } | |||
874 | break; | |||
875 | } | |||
876 | ||||
877 | ProcessMonotonicQuad(hnd,coords,pixelInfo); | |||
878 | } | |||
879 | ||||
880 | /* | |||
881 | * Performing drawing of the monotonic in X and Y cubic curves with sizes less | |||
882 | * than MAX_CUB_SIZE by using forward differencing method of calculation. | |||
883 | * | |||
884 | * Here is some math used in the code below. | |||
885 | * | |||
886 | * If we express the parametric equation for the coordinates as | |||
887 | * simple polynomial: | |||
888 | * | |||
889 | * V(t) = a * t^3 + b * t^2 + c * t + d | |||
890 | * | |||
891 | * The equations for how we derive these polynomial coefficients | |||
892 | * from the Bezier control points can be found in the method comments | |||
893 | * for the CubicCurve.fillEqn Java method. | |||
894 | * | |||
895 | * From this polynomial, we can derive the forward differences to | |||
896 | * allow us to calculate V(t+K) from V(t) as follows: | |||
897 | * | |||
898 | * 1) V1(0) | |||
899 | * = V(K)-V(0) | |||
900 | * = aK^3 + bK^2 + cK + d - d | |||
901 | * = aK^3 + bK^2 + cK | |||
902 | * | |||
903 | * 2) V1(K) | |||
904 | * = V(2K)-V(K) | |||
905 | * = 8aK^3 + 4bK^2 + 2cK + d - aK^3 - bK^2 - cK - d | |||
906 | * = 7aK^3 + 3bK^2 + cK | |||
907 | * | |||
908 | * 3) V1(2K) | |||
909 | * = V(3K)-V(2K) | |||
910 | * = 27aK^3 + 9bK^2 + 3cK + d - 8aK^3 - 4bK^2 - 2cK - d | |||
911 | * = 19aK^3 + 5bK^2 + cK | |||
912 | * | |||
913 | * 4) V2(0) | |||
914 | * = V1(K) - V1(0) | |||
915 | * = 7aK^3 + 3bK^2 + cK - aK^3 - bK^2 - cK | |||
916 | * = 6aK^3 + 2bK^2 | |||
917 | * | |||
918 | * 5) V2(K) | |||
919 | * = V1(2K) - V1(K) | |||
920 | * = 19aK^3 + 5bK^2 + cK - 7aK^3 - 3bK^2 - cK | |||
921 | * = 12aK^3 + 2bK^2 | |||
922 | * | |||
923 | * 6) V3(0) | |||
924 | * = V2(K) - V2(0) | |||
925 | * = 12aK^3 + 2bK^2 - 6aK^3 - 2bK^2 | |||
926 | * = 6aK^3 | |||
927 | * | |||
928 | * Note that if we continue on to calculate V1(3K), V2(2K) and | |||
929 | * V3(K) we will see that V3(K) == V3(0) so we need at most | |||
930 | * 3 cascading forward differences to step through the cubic | |||
931 | * curve. | |||
932 | * | |||
933 | * Note, b coefficient calculating in the DrawCubic is actually twice the b | |||
934 | * coefficient seen above. It's been done for the better accuracy. | |||
935 | * | |||
936 | * In our case, initialy K is chosen as 1/(2^DF_CUB_STEPS) this value is taken | |||
937 | * with FWD_PREC bits precision. This means that we should do 2^DF_CUB_STEPS | |||
938 | * steps to pass through all the curve. | |||
939 | * | |||
940 | * On each step we examine how far we are stepping by examining our first(V1) | |||
941 | * and second (V2) order derivatives and verifying that they are met following | |||
942 | * conditions: | |||
943 | * | |||
944 | * abs(V2) <= DF_CUB_DEC_BND | |||
945 | * abs(V1) > DF_CUB_INC_BND | |||
946 | * | |||
947 | * So, ensures that we step through the curve more slowly when its curvature is | |||
948 | * high and faster when its curvature is lower. If the step size needs | |||
949 | * adjustment we adjust it so that we step either twice as fast, or twice as | |||
950 | * slow until our step size is within range. This modifies our stepping | |||
951 | * variables as follows: | |||
952 | * | |||
953 | * Decreasing step size | |||
954 | * (See Graphics Gems/by A.Glassner,(Tutorial on forward differencing),601-602) | |||
955 | * | |||
956 | * V3 = oV3/8 | |||
957 | * V2 = oV2/4 - V3 | |||
958 | * V1 = (oV1 - V2)/2 | |||
959 | * | |||
960 | * Here V1-V3 stands for new values of the forward differencies and oV1 - oV3 | |||
961 | * for the old ones | |||
962 | * | |||
963 | * Using the equations above it's easy to calculating stepping variables for | |||
964 | * the increasing step size: | |||
965 | * | |||
966 | * V1 = 2*oV1 + oV2 | |||
967 | * V2 = 4*oV2 + 4*oV3 | |||
968 | * V3 = 8*oV3 | |||
969 | * | |||
970 | * And then for not to running out of 32 bit precision we are performing 3 bit | |||
971 | * shift of the forward differencing precision (keeping in shift variable) in | |||
972 | * left or right direction depending on what is happening (decreasing or | |||
973 | * increasing). So, all oV1 - oV3 variables should be thought as appropriately | |||
974 | * shifted in regard to the V1 - V3. | |||
975 | * | |||
976 | * Taking all of the above into account we will have following: | |||
977 | * | |||
978 | * Decreasing step size: | |||
979 | * | |||
980 | * shift = shift + 3 | |||
981 | * V3 keeps the same | |||
982 | * V2 = 2*oV2 - V3 | |||
983 | * V1 = 4*oV1 - V2/2 | |||
984 | * | |||
985 | * Increasing step size: | |||
986 | * | |||
987 | * shift = shift - 3 | |||
988 | * V1 = oV1/4 + oV2/8 | |||
989 | * V2 = oV2/2 + oV3/2 | |||
990 | * V3 keeps the same | |||
991 | * | |||
992 | */ | |||
993 | ||||
994 | static void DrawMonotonicCubic(ProcessHandler* hnd, | |||
995 | jfloat *coords, | |||
996 | jboolean checkBounds, | |||
997 | jint* pixelInfo) | |||
998 | { | |||
999 | jint x0 = (jint)(coords[0]*MDP_MULT(1<<10)); | |||
1000 | jint y0 = (jint)(coords[1]*MDP_MULT(1<<10)); | |||
1001 | ||||
1002 | jint xe = (jint)(coords[6]*MDP_MULT(1<<10)); | |||
1003 | jint ye = (jint)(coords[7]*MDP_MULT(1<<10)); | |||
1004 | ||||
1005 | /* Extracting fractional part of coordinates of first control point */ | |||
1006 | jint px = (x0 & (~MDP_W_MASK(-(1<<10)))) << DF_CUB_SHIFT(7 + 3*3 - 10); | |||
1007 | jint py = (y0 & (~MDP_W_MASK(-(1<<10)))) << DF_CUB_SHIFT(7 + 3*3 - 10); | |||
1008 | ||||
1009 | /* Setting default boundary values for checking first and second forward | |||
1010 | * difference for the necessity of the restepping. See comments to the | |||
1011 | * boundary values in ProcessQuad for more info. | |||
1012 | */ | |||
1013 | jint incStepBnd1 = DF_CUB_INC_BND(1<<(3*3 + 7 - 1)); | |||
1014 | jint incStepBnd2 = DF_CUB_INC_BND(1<<(3*3 + 7 - 1)) << 1; | |||
1015 | jint decStepBnd1 = DF_CUB_DEC_BND(1<<(3*3 + 7 + 2)); | |||
1016 | jint decStepBnd2 = DF_CUB_DEC_BND(1<<(3*3 + 7 + 2)) << 1; | |||
1017 | ||||
1018 | /* Setting default amount of steps */ | |||
1019 | jint count = DF_CUB_COUNT(1<<3); | |||
1020 | ||||
1021 | /* Setting default shift for preparing to the midpoint rounding */ | |||
1022 | jint shift = DF_CUB_SHIFT(7 + 3*3 - 10); | |||
1023 | ||||
1024 | jint ax = (jint)((-coords[0] + 3*coords[2] - 3*coords[4] + | |||
1025 | coords[6])*CUB_A_MDP_MULT(1<<7)); | |||
1026 | jint ay = (jint)((-coords[1] + 3*coords[3] - 3*coords[5] + | |||
1027 | coords[7])*CUB_A_MDP_MULT(1<<7)); | |||
1028 | ||||
1029 | jint bx = (jint)((3*coords[0] - 6*coords[2] + | |||
1030 | 3*coords[4])*CUB_B_MDP_MULT(1<<(3 + 7 + 1))); | |||
1031 | jint by = (jint)((3*coords[1] - 6*coords[3] + | |||
1032 | 3*coords[5])*CUB_B_MDP_MULT(1<<(3 + 7 + 1))); | |||
1033 | ||||
1034 | jint cx = (jint)((-3*coords[0] + 3*coords[2])*(CUB_C_MDP_MULT(1<<(3*2 + 7)))); | |||
1035 | jint cy = (jint)((-3*coords[1] + 3*coords[3])*(CUB_C_MDP_MULT(1<<(3*2 + 7)))); | |||
1036 | ||||
1037 | jint dddpx = 6*ax; | |||
1038 | jint dddpy = 6*ay; | |||
1039 | ||||
1040 | jint ddpx = dddpx + bx; | |||
1041 | jint ddpy = dddpy + by; | |||
1042 | ||||
1043 | jint dpx = ax + (bx>>1) + cx; | |||
1044 | jint dpy = ay + (by>>1) + cy; | |||
1045 | ||||
1046 | jint x1, y1; | |||
1047 | ||||
1048 | jint x2 = x0; | |||
1049 | jint y2 = y0; | |||
1050 | ||||
1051 | /* Calculating whole part of the first point of the curve */ | |||
1052 | jint x0w = x0 & MDP_W_MASK(-(1<<10)); | |||
1053 | jint y0w = y0 & MDP_W_MASK(-(1<<10)); | |||
1054 | ||||
1055 | jint dx = xe - x0; | |||
1056 | jint dy = ye - y0; | |||
1057 | ||||
1058 | while (count > 0) { | |||
1059 | /* Perform decreasing step in 2 times if necessary */ | |||
1060 | while ( | |||
1061 | /* The code below is an optimized version of the checks: | |||
1062 | * abs(ddpx) > decStepBnd1 || | |||
1063 | * abs(ddpy) > decStepBnd1 | |||
1064 | */ | |||
1065 | (juint)(ddpx + decStepBnd1) > (juint)decStepBnd2 || | |||
1066 | (juint)(ddpy + decStepBnd1) > (juint)decStepBnd2) | |||
1067 | { | |||
1068 | ddpx = (ddpx<<1) - dddpx; | |||
1069 | ddpy = (ddpy<<1) - dddpy; | |||
1070 | dpx = (dpx<<2) - (ddpx>>1); | |||
1071 | dpy = (dpy<<2) - (ddpy>>1); | |||
1072 | count <<=1; | |||
1073 | decStepBnd1 <<=3; | |||
1074 | decStepBnd2 <<=3; | |||
1075 | incStepBnd1 <<=3; | |||
1076 | incStepBnd2 <<=3; | |||
1077 | px <<=3; | |||
1078 | py <<=3; | |||
1079 | shift += 3; | |||
1080 | } | |||
1081 | ||||
1082 | /* Perform increasing step in 2 times if necessary. | |||
1083 | * Note: we could do it only in even steps | |||
1084 | */ | |||
1085 | ||||
1086 | while (((count & 1) ^ 1) && shift > DF_CUB_SHIFT(7 + 3*3 - 10) && | |||
1087 | /* The code below is an optimized version of the check: | |||
1088 | * abs(dpx) <= incStepBnd1 && | |||
1089 | * abs(dpy) <= incStepBnd1 | |||
1090 | */ | |||
1091 | (juint)(dpx + incStepBnd1) <= (juint)incStepBnd2 && | |||
1092 | (juint)(dpy + incStepBnd1) <= (juint)incStepBnd2) | |||
1093 | { | |||
1094 | dpx = (dpx>>2) + (ddpx>>3); | |||
1095 | dpy = (dpy>>2) + (ddpy>>3); | |||
1096 | ddpx = (ddpx + dddpx)>>1; | |||
1097 | ddpy = (ddpy + dddpy)>>1; | |||
1098 | count >>=1; | |||
1099 | decStepBnd1 >>=3; | |||
1100 | decStepBnd2 >>=3; | |||
1101 | incStepBnd1 >>=3; | |||
1102 | incStepBnd2 >>=3; | |||
1103 | px >>=3; | |||
1104 | py >>=3; | |||
1105 | shift -= 3; | |||
1106 | } | |||
1107 | ||||
1108 | count--; | |||
1109 | ||||
1110 | /* We are performing one step less than necessary and use actual | |||
1111 | * (xe,ye) endpoint of the curve instead of calculated. This prevent | |||
1112 | * us from accumulated errors at the last point. | |||
1113 | */ | |||
1114 | if (count) { | |||
1115 | ||||
1116 | px += dpx; | |||
1117 | py += dpy; | |||
1118 | ||||
1119 | dpx += ddpx; | |||
1120 | dpy += ddpy; | |||
1121 | ddpx += dddpx; | |||
1122 | ddpy += dddpy; | |||
1123 | ||||
1124 | x1 = x2; | |||
1125 | y1 = y2; | |||
1126 | ||||
1127 | x2 = x0w + (px >> shift); | |||
1128 | y2 = y0w + (py >> shift); | |||
1129 | ||||
1130 | /* Checking that we are not running out of the endpoint and | |||
1131 | * bounding violating coordinate. The check is pretty simple | |||
1132 | * because the curve passed to the DrawMonotonicCubic already | |||
1133 | * split into the monotonic in X and Y pieces | |||
1134 | */ | |||
1135 | ||||
1136 | /* Bounding x2 by xe */ | |||
1137 | if (((xe-x2)^dx) < 0) { | |||
1138 | x2 = xe; | |||
1139 | } | |||
1140 | ||||
1141 | /* Bounding y2 by ye */ | |||
1142 | if (((ye-y2)^dy) < 0) { | |||
1143 | y2 = ye; | |||
1144 | } | |||
1145 | ||||
1146 | hnd->pProcessFixedLine(hnd, x1, y1, x2, y2, pixelInfo, checkBounds, | |||
1147 | JNI_FALSE0); | |||
1148 | } else { | |||
1149 | hnd->pProcessFixedLine(hnd, x2, y2, xe, ye, pixelInfo, checkBounds, | |||
1150 | JNI_FALSE0); | |||
1151 | } | |||
1152 | } | |||
1153 | } | |||
1154 | ||||
1155 | /* | |||
1156 | * Checking size of the cubic curves and split them if necessary. | |||
1157 | * Calling DrawMonotonicCubic for the curves of the appropriate size. | |||
1158 | * Note: coords array could be changed | |||
1159 | */ | |||
1160 | static void ProcessMonotonicCubic(ProcessHandler* hnd, | |||
1161 | jfloat *coords, | |||
1162 | jint* pixelInfo) { | |||
1163 | ||||
1164 | jfloat coords1[8]; | |||
1165 | jfloat tx, ty; | |||
1166 | jfloat xMin, xMax; | |||
1167 | jfloat yMin, yMax; | |||
1168 | ||||
1169 | xMin = xMax = coords[0]; | |||
1170 | yMin = yMax = coords[1]; | |||
1171 | ||||
1172 | CALC_MIN(xMin, coords[2])((xMin)=((coords[2])<(xMin))?(coords[2]):(xMin)); | |||
1173 | CALC_MAX(xMax, coords[2])((xMax)=((coords[2])>(xMax))?(coords[2]):(xMax)); | |||
1174 | CALC_MIN(yMin, coords[3])((yMin)=((coords[3])<(yMin))?(coords[3]):(yMin)); | |||
1175 | CALC_MAX(yMax, coords[3])((yMax)=((coords[3])>(yMax))?(coords[3]):(yMax)); | |||
1176 | CALC_MIN(xMin, coords[4])((xMin)=((coords[4])<(xMin))?(coords[4]):(xMin)); | |||
1177 | CALC_MAX(xMax, coords[4])((xMax)=((coords[4])>(xMax))?(coords[4]):(xMax)); | |||
1178 | CALC_MIN(yMin, coords[5])((yMin)=((coords[5])<(yMin))?(coords[5]):(yMin)); | |||
1179 | CALC_MAX(yMax, coords[5])((yMax)=((coords[5])>(yMax))?(coords[5]):(yMax)); | |||
1180 | CALC_MIN(xMin, coords[6])((xMin)=((coords[6])<(xMin))?(coords[6]):(xMin)); | |||
1181 | CALC_MAX(xMax, coords[6])((xMax)=((coords[6])>(xMax))?(coords[6]):(xMax)); | |||
1182 | CALC_MIN(yMin, coords[7])((yMin)=((coords[7])<(yMin))?(coords[7]):(yMin)); | |||
1183 | CALC_MAX(yMax, coords[7])((yMax)=((coords[7])>(yMax))?(coords[7]):(yMax)); | |||
1184 | ||||
1185 | if (hnd->clipMode == PH_MODE_DRAW_CLIP) { | |||
1186 | ||||
1187 | /* In case of drawing we could just skip curves which are completely | |||
1188 | * out of bounds | |||
1189 | */ | |||
1190 | if (hnd->dhnd->xMaxf < xMin || hnd->dhnd->xMinf > xMax || | |||
1191 | hnd->dhnd->yMaxf < yMin || hnd->dhnd->yMinf > yMax) { | |||
1192 | return; | |||
1193 | } | |||
1194 | } else { | |||
1195 | ||||
1196 | /* In case of filling we could skip curves which are above, | |||
1197 | * below and behind the right boundary of the visible area | |||
1198 | */ | |||
1199 | ||||
1200 | if (hnd->dhnd->yMaxf < yMin || hnd->dhnd->yMinf > yMax || | |||
1201 | hnd->dhnd->xMaxf < xMin) | |||
1202 | { | |||
1203 | return; | |||
1204 | } | |||
1205 | ||||
1206 | /* We could clamp x coordinates to the corresponding boundary | |||
1207 | * if the curve is completely behind the left one | |||
1208 | */ | |||
1209 | ||||
1210 | if (hnd->dhnd->xMinf > xMax) { | |||
1211 | coords[0] = coords[2] = coords[4] = coords[6] = | |||
1212 | hnd->dhnd->xMinf; | |||
1213 | } | |||
1214 | } | |||
1215 | ||||
1216 | if (xMax - xMin > MAX_CUB_SIZE256 || yMax - yMin > MAX_CUB_SIZE256) { | |||
1217 | coords1[6] = coords[6]; | |||
1218 | coords1[7] = coords[7]; | |||
1219 | coords1[4] = (coords[4] + coords[6])/2.0f; | |||
1220 | coords1[5] = (coords[5] + coords[7])/2.0f; | |||
1221 | tx = (coords[2] + coords[4])/2.0f; | |||
1222 | ty = (coords[3] + coords[5])/2.0f; | |||
1223 | coords1[2] = (tx + coords1[4])/2.0f; | |||
1224 | coords1[3] = (ty + coords1[5])/2.0f; | |||
1225 | coords[2] = (coords[0] + coords[2])/2.0f; | |||
1226 | coords[3] = (coords[1] + coords[3])/2.0f; | |||
1227 | coords[4] = (coords[2] + tx)/2.0f; | |||
1228 | coords[5] = (coords[3] + ty)/2.0f; | |||
1229 | coords[6]=coords1[0]=(coords[4] + coords1[2])/2.0f; | |||
1230 | coords[7]=coords1[1]=(coords[5] + coords1[3])/2.0f; | |||
1231 | ||||
1232 | ProcessMonotonicCubic(hnd, coords, pixelInfo); | |||
1233 | ||||
1234 | ProcessMonotonicCubic(hnd, coords1, pixelInfo); | |||
1235 | ||||
1236 | } else { | |||
1237 | DrawMonotonicCubic(hnd, coords, | |||
1238 | /* Set checkBounds parameter if curve intersects | |||
1239 | * boundary of the visible area. We know that the | |||
1240 | * curve is visible, so the check is pretty simple | |||
1241 | */ | |||
1242 | hnd->dhnd->xMinf > xMin || hnd->dhnd->xMaxf < xMax || | |||
1243 | hnd->dhnd->yMinf > yMin || hnd->dhnd->yMaxf < yMax, | |||
1244 | pixelInfo); | |||
1245 | } | |||
1246 | } | |||
1247 | ||||
1248 | /* | |||
1249 | * Bite the piece of the cubic curve from start point till the point | |||
1250 | * corresponding to the specified parameter then call ProcessMonotonicCubic for | |||
1251 | * the bitten part. | |||
1252 | * Note: coords array will be changed | |||
1253 | */ | |||
1254 | static void ProcessFirstMonotonicPartOfCubic(ProcessHandler* hnd, | |||
1255 | jfloat* coords, jint* pixelInfo, | |||
1256 | jfloat t) | |||
1257 | { | |||
1258 | jfloat coords1[8]; | |||
1259 | jfloat tx, ty; | |||
1260 | ||||
1261 | coords1[0] = coords[0]; | |||
1262 | coords1[1] = coords[1]; | |||
1263 | tx = coords[2] + t*(coords[4] - coords[2]); | |||
1264 | ty = coords[3] + t*(coords[5] - coords[3]); | |||
1265 | coords1[2] = coords[0] + t*(coords[2] - coords[0]); | |||
1266 | coords1[3] = coords[1] + t*(coords[3] - coords[1]); | |||
1267 | coords1[4] = coords1[2] + t*(tx - coords1[2]); | |||
1268 | coords1[5] = coords1[3] + t*(ty - coords1[3]); | |||
1269 | coords[4] = coords[4] + t*(coords[6] - coords[4]); | |||
1270 | coords[5] = coords[5] + t*(coords[7] - coords[5]); | |||
1271 | coords[2] = tx + t*(coords[4] - tx); | |||
1272 | coords[3] = ty + t*(coords[5] - ty); | |||
1273 | coords[0]=coords1[6]=coords1[4] + t*(coords[2] - coords1[4]); | |||
1274 | coords[1]=coords1[7]=coords1[5] + t*(coords[3] - coords1[5]); | |||
1275 | ||||
1276 | ProcessMonotonicCubic(hnd, coords1, pixelInfo); | |||
1277 | } | |||
1278 | ||||
1279 | /* | |||
1280 | * Split cubic curve into monotonic in X and Y parts. Calling ProcessCubic for | |||
1281 | * each monotonic piece of the curve. | |||
1282 | * | |||
1283 | * Note: coords array could be changed | |||
1284 | */ | |||
1285 | static void ProcessCubic(ProcessHandler* hnd, jfloat* coords, jint* pixelInfo) | |||
1286 | { | |||
1287 | /* Temporary array for holding parameters corresponding to the extreme in X | |||
1288 | * and Y points. The values are inside the (0,1) range (0 and 1 excluded) | |||
1289 | * and in ascending order. | |||
1290 | */ | |||
1291 | double params[4]; | |||
1292 | jint cnt = 0, i; | |||
1293 | ||||
1294 | /* Simple check for monotonicity in X before searching for the extreme | |||
1295 | * points of the X(t) function. We first check if the curve is monotonic in | |||
1296 | * X by seeing if all of the X coordinates are strongly ordered. | |||
1297 | */ | |||
1298 | if ((coords[0] > coords[2] || coords[2] > coords[4] || | |||
| ||||
1299 | coords[4] > coords[6]) && | |||
1300 | (coords[0] < coords[2] || coords[2] < coords[4] || | |||
1301 | coords[4] < coords[6])) | |||
1302 | { | |||
1303 | /* Searching for extreme points of the X(t) function by solving | |||
1304 | * dX(t) | |||
1305 | * ---- = 0 equation | |||
1306 | * dt | |||
1307 | */ | |||
1308 | double ax = -coords[0] + 3*coords[2] - 3*coords[4] + coords[6]; | |||
1309 | double bx = 2*(coords[0] - 2*coords[2] + coords[4]); | |||
1310 | double cx = -coords[0] + coords[2]; | |||
1311 | ||||
1312 | SOLVEQUADINRANGE(ax,bx,cx,params,cnt)do { double param; if ((ax) != 0) { double d = (bx)*(bx) - 4* (ax)*(cx); double q; if (d < 0) { break; } d = sqrt(d); if ((bx) < 0) { d = -d; } q = ((bx) + d) / -2.0; param = q/( ax); if (param < 1.0 && param > 0.0) { (params) [(cnt)++] = param; } if (d == 0 || q == 0) { break; } param = (cx)/q; if (param < 1.0 && param > 0.0) { (params )[(cnt)++] = param; } } else { if ((bx) == 0) { break; } param = -(cx)/(bx); if (param < 1.0 && param > 0.0) { (params)[(cnt)++] = param; } } } while(0); | |||
1313 | } | |||
1314 | ||||
1315 | /* Simple check for monotonicity in Y before searching for the extreme | |||
1316 | * points of the Y(t) function. We first check if the curve is monotonic in | |||
1317 | * Y by seeing if all of the Y coordinates are strongly ordered. | |||
1318 | */ | |||
1319 | if ((coords[1] > coords[3] || coords[3] > coords[5] || | |||
1320 | coords[5] > coords[7]) && | |||
1321 | (coords[1] < coords[3] || coords[3] < coords[5] || | |||
1322 | coords[5] < coords[7])) | |||
1323 | { | |||
1324 | /* Searching for extreme points of the Y(t) function by solving | |||
1325 | * dY(t) | |||
1326 | * ----- = 0 equation | |||
1327 | * dt | |||
1328 | */ | |||
1329 | double ay = -coords[1] + 3*coords[3] - 3*coords[5] + coords[7]; | |||
1330 | double by = 2*(coords[1] - 2*coords[3] + coords[5]); | |||
1331 | double cy = -coords[1] + coords[3]; | |||
1332 | ||||
1333 | SOLVEQUADINRANGE(ay,by,cy,params,cnt)do { double param; if ((ay) != 0) { double d = (by)*(by) - 4* (ay)*(cy); double q; if (d < 0) { break; } d = sqrt(d); if ((by) < 0) { d = -d; } q = ((by) + d) / -2.0; param = q/( ay); if (param < 1.0 && param > 0.0) { (params) [(cnt)++] = param; } if (d == 0 || q == 0) { break; } param = (cy)/q; if (param < 1.0 && param > 0.0) { (params )[(cnt)++] = param; } } else { if ((by) == 0) { break; } param = -(cy)/(by); if (param < 1.0 && param > 0.0) { (params)[(cnt)++] = param; } } } while(0); | |||
1334 | } | |||
1335 | ||||
1336 | if (cnt > 0) { | |||
1337 | /* Sorting parameter values corresponding to the extremum points of | |||
1338 | * the curve. We are using insertion sort because of tiny size of the | |||
1339 | * array. | |||
1340 | */ | |||
1341 | jint j; | |||
1342 | ||||
1343 | for(i = 1; i < cnt; i++) { | |||
1344 | double value = params[i]; | |||
1345 | for (j = i - 1; j >= 0 && params[j] > value; j--) { | |||
1346 | params[j + 1] = params[j]; | |||
1347 | } | |||
1348 | params[j + 1] = value; | |||
1349 | } | |||
1350 | ||||
1351 | /* Processing obtained monotonic parts */ | |||
1352 | ProcessFirstMonotonicPartOfCubic(hnd, coords, pixelInfo, | |||
1353 | (jfloat)params[0]); | |||
1354 | for (i = 1; i < cnt; i++) { | |||
1355 | double param = params[i] - params[i-1]; | |||
1356 | if (param > 0) { | |||
1357 | ProcessFirstMonotonicPartOfCubic(hnd, coords, pixelInfo, | |||
1358 | /* Scale parameter to match with rest of the curve */ | |||
1359 | (float)(param/(1.0 - params[i - 1]))); | |||
1360 | } | |||
1361 | } | |||
1362 | } | |||
1363 | ||||
1364 | ProcessMonotonicCubic(hnd,coords,pixelInfo); | |||
1365 | } | |||
1366 | ||||
1367 | static void ProcessLine(ProcessHandler* hnd, | |||
1368 | jfloat *coord1, jfloat *coord2, jint* pixelInfo) { | |||
1369 | ||||
1370 | jfloat xMin, yMin, xMax, yMax; | |||
1371 | jint X1, Y1, X2, Y2, X3, Y3, res; | |||
1372 | jboolean clipped = JNI_FALSE0; | |||
1373 | jfloat x1 = coord1[0]; | |||
1374 | jfloat y1 = coord1[1]; | |||
1375 | jfloat x2 = coord2[0]; | |||
1376 | jfloat y2 = coord2[1]; | |||
1377 | jfloat x3,y3; | |||
1378 | ||||
1379 | jboolean lastClipped; | |||
1380 | ||||
1381 | xMin = hnd->dhnd->xMinf; | |||
1382 | yMin = hnd->dhnd->yMinf; | |||
1383 | xMax = hnd->dhnd->xMaxf; | |||
1384 | yMax = hnd->dhnd->yMaxf; | |||
1385 | ||||
1386 | TESTANDCLIP(yMin, yMax, y1, x1, y2, x2, jfloat, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (y1 < (yMin) || y1 > (yMax)) { if (y1 < (yMin)) { if (y2 < (yMin)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = ( yMin); } else { if (y2 > (yMax)) { res = CRES_INVISIBLE; break ; }; res = CRES_MAX_CLIPPED; t = (yMax); } x1 = (jfloat)(x1 + ((jdouble)(t - y1)*(x2 - x1)) / (y2 - y1)); y1 = (jfloat)t; } } while (0); | |||
1387 | if (res == CRES_INVISIBLE) return; | |||
1388 | clipped = IS_CLIPPED(res)(res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED); | |||
1389 | TESTANDCLIP(yMin, yMax, y2, x2, y1, x1, jfloat, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (y2 < (yMin) || y2 > (yMax)) { if (y2 < (yMin)) { if (y1 < (yMin)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = ( yMin); } else { if (y1 > (yMax)) { res = CRES_INVISIBLE; break ; }; res = CRES_MAX_CLIPPED; t = (yMax); } x2 = (jfloat)(x2 + ((jdouble)(t - y2)*(x1 - x2)) / (y1 - y2)); y2 = (jfloat)t; } } while (0); | |||
1390 | if (res == CRES_INVISIBLE) return; | |||
1391 | lastClipped = IS_CLIPPED(res)(res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED); | |||
1392 | clipped = clipped || lastClipped; | |||
1393 | ||||
1394 | if (hnd->clipMode == PH_MODE_DRAW_CLIP) { | |||
1395 | TESTANDCLIP(xMin, xMax,do { jdouble t; res = CRES_NOT_CLIPPED; if (x1 < (xMin) || x1 > (xMax)) { if (x1 < (xMin)) { if (x2 < (xMin)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = ( xMin); } else { if (x2 > (xMax)) { res = CRES_INVISIBLE; break ; }; res = CRES_MAX_CLIPPED; t = (xMax); } y1 = (jfloat)(y1 + ((jdouble)(t - x1)*(y2 - y1)) / (x2 - x1)); x1 = (jfloat)t; } } while (0) | |||
1396 | x1, y1, x2, y2, jfloat, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (x1 < (xMin) || x1 > (xMax)) { if (x1 < (xMin)) { if (x2 < (xMin)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = ( xMin); } else { if (x2 > (xMax)) { res = CRES_INVISIBLE; break ; }; res = CRES_MAX_CLIPPED; t = (xMax); } y1 = (jfloat)(y1 + ((jdouble)(t - x1)*(y2 - y1)) / (x2 - x1)); x1 = (jfloat)t; } } while (0); | |||
1397 | if (res == CRES_INVISIBLE) return; | |||
1398 | clipped = clipped || IS_CLIPPED(res)(res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED); | |||
1399 | TESTANDCLIP(xMin, xMax,do { jdouble t; res = CRES_NOT_CLIPPED; if (x2 < (xMin) || x2 > (xMax)) { if (x2 < (xMin)) { if (x1 < (xMin)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = ( xMin); } else { if (x1 > (xMax)) { res = CRES_INVISIBLE; break ; }; res = CRES_MAX_CLIPPED; t = (xMax); } y2 = (jfloat)(y2 + ((jdouble)(t - x2)*(y1 - y2)) / (x1 - x2)); x2 = (jfloat)t; } } while (0) | |||
1400 | x2, y2, x1, y1, jfloat, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (x2 < (xMin) || x2 > (xMax)) { if (x2 < (xMin)) { if (x1 < (xMin)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = ( xMin); } else { if (x1 > (xMax)) { res = CRES_INVISIBLE; break ; }; res = CRES_MAX_CLIPPED; t = (xMax); } y2 = (jfloat)(y2 + ((jdouble)(t - x2)*(y1 - y2)) / (x1 - x2)); x2 = (jfloat)t; } } while (0); | |||
1401 | if (res == CRES_INVISIBLE) return; | |||
1402 | lastClipped = lastClipped || IS_CLIPPED(res)(res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED); | |||
1403 | clipped = clipped || lastClipped; | |||
1404 | X1 = (jint)(x1*MDP_MULT(1<<10)); | |||
1405 | Y1 = (jint)(y1*MDP_MULT(1<<10)); | |||
1406 | X2 = (jint)(x2*MDP_MULT(1<<10)); | |||
1407 | Y2 = (jint)(y2*MDP_MULT(1<<10)); | |||
1408 | ||||
1409 | hnd->pProcessFixedLine(hnd, X1, Y1, X2, Y2, pixelInfo, | |||
1410 | clipped, /* enable boundary checking in case | |||
1411 | of clipping to avoid entering | |||
1412 | out of bounds which could | |||
1413 | happens during rounding | |||
1414 | */ | |||
1415 | lastClipped /* Notify pProcessFixedLine that | |||
1416 | this is the end of the | |||
1417 | subpath (because of exiting | |||
1418 | out of boundaries) | |||
1419 | */ | |||
1420 | ); | |||
1421 | } else { | |||
1422 | /* Clamping starting from first vertex of the processed segment | |||
1423 | */ | |||
1424 | CLIPCLAMP(xMin, xMax, x1, y1, x2, y2, x3, y3, jfloat, res)do { x3 = x1; y3 = y1; do { jdouble t; res = CRES_NOT_CLIPPED ; if (x1 < (xMin) || x1 > (xMax)) { if (x1 < (xMin)) { if (x2 < (xMin)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = (xMin); } else { if (x2 > (xMax)) { res = CRES_INVISIBLE; break; }; res = CRES_MAX_CLIPPED; t = ( xMax); } y1 = (jfloat)(y1 + ((jdouble)(t - x1)*(y2 - y1)) / ( x2 - x1)); x1 = (jfloat)t; } } while (0); if (res == CRES_MIN_CLIPPED ) { x3 = x1; } else if (res == CRES_MAX_CLIPPED) { x3 = x1; res = CRES_MAX_CLIPPED; } else if (res == CRES_INVISIBLE) { if ( x1 > xMax) { res = CRES_INVISIBLE; } else { x1 = (jfloat)xMin ; x2 = (jfloat)xMin; res = CRES_NOT_CLIPPED; } } } while (0); | |||
1425 | X1 = (jint)(x1*MDP_MULT(1<<10)); | |||
1426 | Y1 = (jint)(y1*MDP_MULT(1<<10)); | |||
1427 | ||||
1428 | /* Clamping only by left boundary */ | |||
1429 | if (res == CRES_MIN_CLIPPED) { | |||
1430 | X3 = (jint)(x3*MDP_MULT(1<<10)); | |||
1431 | Y3 = (jint)(y3*MDP_MULT(1<<10)); | |||
1432 | hnd->pProcessFixedLine(hnd, X3, Y3, X1, Y1, pixelInfo, | |||
1433 | JNI_FALSE0, lastClipped); | |||
1434 | ||||
1435 | } else if (res == CRES_INVISIBLE) { | |||
1436 | return; | |||
1437 | } | |||
1438 | ||||
1439 | /* Clamping starting from last vertex of the processed segment | |||
1440 | */ | |||
1441 | CLIPCLAMP(xMin, xMax, x2, y2, x1, y1, x3, y3, jfloat, res)do { x3 = x2; y3 = y2; do { jdouble t; res = CRES_NOT_CLIPPED ; if (x2 < (xMin) || x2 > (xMax)) { if (x2 < (xMin)) { if (x1 < (xMin)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED; t = (xMin); } else { if (x1 > (xMax)) { res = CRES_INVISIBLE; break; }; res = CRES_MAX_CLIPPED; t = ( xMax); } y2 = (jfloat)(y2 + ((jdouble)(t - x2)*(y1 - y2)) / ( x1 - x2)); x2 = (jfloat)t; } } while (0); if (res == CRES_MIN_CLIPPED ) { x3 = x2; } else if (res == CRES_MAX_CLIPPED) { x3 = x2; res = CRES_MAX_CLIPPED; } else if (res == CRES_INVISIBLE) { if ( x2 > xMax) { res = CRES_INVISIBLE; } else { x2 = (jfloat)xMin ; x1 = (jfloat)xMin; res = CRES_NOT_CLIPPED; } } } while (0); | |||
1442 | ||||
1443 | /* Checking if there was a clip by right boundary */ | |||
1444 | lastClipped = lastClipped || (res == CRES_MAX_CLIPPED); | |||
1445 | ||||
1446 | X2 = (jint)(x2*MDP_MULT(1<<10)); | |||
1447 | Y2 = (jint)(y2*MDP_MULT(1<<10)); | |||
1448 | hnd->pProcessFixedLine(hnd, X1, Y1, X2, Y2, pixelInfo, | |||
1449 | JNI_FALSE0, lastClipped); | |||
1450 | ||||
1451 | /* Clamping only by left boundary */ | |||
1452 | if (res == CRES_MIN_CLIPPED) { | |||
1453 | X3 = (jint)(x3*MDP_MULT(1<<10)); | |||
1454 | Y3 = (jint)(y3*MDP_MULT(1<<10)); | |||
1455 | hnd->pProcessFixedLine(hnd, X2, Y2, X3, Y3, pixelInfo, | |||
1456 | JNI_FALSE0, lastClipped); | |||
1457 | } | |||
1458 | } | |||
1459 | } | |||
1460 | ||||
1461 | jboolean ProcessPath(ProcessHandler* hnd, | |||
1462 | jfloat transXf, jfloat transYf, | |||
1463 | jfloat* coords, jint maxCoords, | |||
1464 | jbyte* types, jint numTypes) | |||
1465 | { | |||
1466 | jfloat tCoords[8]; | |||
1467 | jfloat closeCoord[2]; | |||
1468 | jint pixelInfo[5]; | |||
1469 | jboolean skip = JNI_FALSE0; | |||
1470 | jboolean subpathStarted = JNI_FALSE0; | |||
1471 | jfloat lastX, lastY; | |||
1472 | int i, index = 0; | |||
1473 | ||||
1474 | pixelInfo[0] = 0; | |||
1475 | ||||
1476 | /* Adding support of the KEY_STROKE_CONTROL rendering hint. | |||
1477 | * Now we are supporting two modes: "pixels at centers" and | |||
1478 | * "pixels at corners". | |||
1479 | * First one is disabled by default but could be enabled by setting | |||
1480 | * VALUE_STROKE_PURE to the rendering hint. It means that pixel at the | |||
1481 | * screen (x,y) has (x + 0.5, y + 0.5) float coordinates. | |||
1482 | * | |||
1483 | * Second one is enabled by default and means straightforward mapping | |||
1484 | * (x,y) --> (x,y) | |||
1485 | * | |||
1486 | */ | |||
1487 | if (hnd->stroke == PH_STROKE_PURE) { | |||
| ||||
1488 | closeCoord[0] = -0.5f; | |||
1489 | closeCoord[1] = -0.5f; | |||
1490 | transXf -= 0.5; | |||
1491 | transYf -= 0.5; | |||
1492 | } else { | |||
1493 | closeCoord[0] = 0.0f; | |||
1494 | closeCoord[1] = 0.0f; | |||
1495 | } | |||
1496 | ||||
1497 | /* Adjusting boundaries to the capabilities of the ProcessPath code */ | |||
1498 | ADJUST(hnd->dhnd->xMin, LOWER_OUT_BND, UPPER_OUT_BND)do { if ((hnd->dhnd->xMin) < ((-(1 << (30 - 10 ))))) { (hnd->dhnd->xMin) = ((-(1 << (30 - 10)))) ; } else if ((hnd->dhnd->xMin) > (1 << (30 - 10 ))) { (hnd->dhnd->xMin) = ((1 << (30 - 10))); } } while(0); | |||
1499 | ADJUST(hnd->dhnd->yMin, LOWER_OUT_BND, UPPER_OUT_BND)do { if ((hnd->dhnd->yMin) < ((-(1 << (30 - 10 ))))) { (hnd->dhnd->yMin) = ((-(1 << (30 - 10)))) ; } else if ((hnd->dhnd->yMin) > (1 << (30 - 10 ))) { (hnd->dhnd->yMin) = ((1 << (30 - 10))); } } while(0); | |||
1500 | ADJUST(hnd->dhnd->xMax, LOWER_OUT_BND, UPPER_OUT_BND)do { if ((hnd->dhnd->xMax) < ((-(1 << (30 - 10 ))))) { (hnd->dhnd->xMax) = ((-(1 << (30 - 10)))) ; } else if ((hnd->dhnd->xMax) > (1 << (30 - 10 ))) { (hnd->dhnd->xMax) = ((1 << (30 - 10))); } } while(0); | |||
1501 | ADJUST(hnd->dhnd->yMax, LOWER_OUT_BND, UPPER_OUT_BND)do { if ((hnd->dhnd->yMax) < ((-(1 << (30 - 10 ))))) { (hnd->dhnd->yMax) = ((-(1 << (30 - 10)))) ; } else if ((hnd->dhnd->yMax) > (1 << (30 - 10 ))) { (hnd->dhnd->yMax) = ((1 << (30 - 10))); } } while(0); | |||
1502 | ||||
1503 | ||||
1504 | /* Setting up fractional clipping box | |||
1505 | * | |||
1506 | * We are using following float -> int mapping: | |||
1507 | * | |||
1508 | * xi = floor(xf + 0.5) | |||
1509 | * | |||
1510 | * So, fractional values that hit the [xmin, xmax) integer interval will be | |||
1511 | * situated inside the [xmin-0.5, xmax - 0.5) fractional interval. We are | |||
1512 | * using EPSF constant to provide that upper boundary is not included. | |||
1513 | */ | |||
1514 | hnd->dhnd->xMinf = hnd->dhnd->xMin - 0.5f; | |||
1515 | hnd->dhnd->yMinf = hnd->dhnd->yMin - 0.5f; | |||
1516 | hnd->dhnd->xMaxf = hnd->dhnd->xMax - 0.5f - EPSF(((jfloat)1)/(1<<10)); | |||
1517 | hnd->dhnd->yMaxf = hnd->dhnd->yMax - 0.5f - EPSF(((jfloat)1)/(1<<10)); | |||
1518 | ||||
1519 | ||||
1520 | for (i = 0; i < numTypes; i++) { | |||
1521 | switch (types[i]) { | |||
1522 | case java_awt_geom_PathIterator_SEG_MOVETO0L: | |||
1523 | if (index + 2 <= maxCoords) { | |||
1524 | /* Performing closing of the unclosed segments */ | |||
1525 | if (subpathStarted & !skip) { | |||
1526 | if (hnd->clipMode == PH_MODE_FILL_CLIP) { | |||
1527 | if (tCoords[0] != closeCoord[0] || | |||
1528 | tCoords[1] != closeCoord[1]) | |||
1529 | { | |||
1530 | ProcessLine(hnd, tCoords, closeCoord, | |||
1531 | pixelInfo); | |||
1532 | } | |||
1533 | } | |||
1534 | hnd->pProcessEndSubPath(hnd); | |||
1535 | } | |||
1536 | ||||
1537 | tCoords[0] = coords[index++] + transXf; | |||
1538 | tCoords[1] = coords[index++] + transYf; | |||
1539 | ||||
1540 | /* Checking SEG_MOVETO coordinates if they are out of the | |||
1541 | * [LOWER_BND, UPPER_BND] range. This check also handles | |||
1542 | * NaN and Infinity values. Skipping next path segment in | |||
1543 | * case of invalid data. | |||
1544 | */ | |||
1545 | ||||
1546 | if (tCoords[0] < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1547 | tCoords[0] > LOWER_BND(-(3.40282347e+38F/4.0f)) && | |||
1548 | tCoords[1] < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1549 | tCoords[1] > LOWER_BND(-(3.40282347e+38F/4.0f))) | |||
1550 | { | |||
1551 | subpathStarted = JNI_TRUE1; | |||
1552 | skip = JNI_FALSE0; | |||
1553 | closeCoord[0] = tCoords[0]; | |||
1554 | closeCoord[1] = tCoords[1]; | |||
1555 | } else { | |||
1556 | skip = JNI_TRUE1; | |||
1557 | } | |||
1558 | } else { | |||
1559 | return JNI_FALSE0; | |||
1560 | } | |||
1561 | break; | |||
1562 | case java_awt_geom_PathIterator_SEG_LINETO1L: | |||
1563 | if (index + 2 <= maxCoords) { | |||
1564 | lastX = tCoords[2] = coords[index++] + transXf; | |||
1565 | lastY = tCoords[3] = coords[index++] + transYf; | |||
1566 | ||||
1567 | /* Checking SEG_LINETO coordinates if they are out of the | |||
1568 | * [LOWER_BND, UPPER_BND] range. This check also handles | |||
1569 | * NaN and Infinity values. Ignoring current path segment | |||
1570 | * in case of invalid data. If segment is skipped its | |||
1571 | * endpoint (if valid) is used to begin new subpath. | |||
1572 | */ | |||
1573 | ||||
1574 | if (lastX < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1575 | lastX > LOWER_BND(-(3.40282347e+38F/4.0f)) && | |||
1576 | lastY < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1577 | lastY > LOWER_BND(-(3.40282347e+38F/4.0f))) | |||
1578 | { | |||
1579 | if (skip) { | |||
1580 | tCoords[0] = closeCoord[0] = lastX; | |||
1581 | tCoords[1] = closeCoord[1] = lastY; | |||
1582 | subpathStarted = JNI_TRUE1; | |||
1583 | skip = JNI_FALSE0; | |||
1584 | } else { | |||
1585 | ProcessLine(hnd, tCoords, tCoords + 2, | |||
1586 | pixelInfo); | |||
1587 | tCoords[0] = lastX; | |||
1588 | tCoords[1] = lastY; | |||
1589 | } | |||
1590 | } | |||
1591 | } else { | |||
1592 | return JNI_FALSE0; | |||
1593 | } | |||
1594 | break; | |||
1595 | case java_awt_geom_PathIterator_SEG_QUADTO2L: | |||
1596 | if (index + 4 <= maxCoords) { | |||
1597 | tCoords[2] = coords[index++] + transXf; | |||
1598 | tCoords[3] = coords[index++] + transYf; | |||
1599 | lastX = tCoords[4] = coords[index++] + transXf; | |||
1600 | lastY = tCoords[5] = coords[index++] + transYf; | |||
1601 | ||||
1602 | /* Checking SEG_QUADTO coordinates if they are out of the | |||
1603 | * [LOWER_BND, UPPER_BND] range. This check also handles | |||
1604 | * NaN and Infinity values. Ignoring current path segment | |||
1605 | * in case of invalid endpoints's data. Equivalent to | |||
1606 | * the SEG_LINETO if endpoint coordinates are valid but | |||
1607 | * there are invalid data among other coordinates | |||
1608 | */ | |||
1609 | ||||
1610 | if (lastX < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1611 | lastX > LOWER_BND(-(3.40282347e+38F/4.0f)) && | |||
1612 | lastY < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1613 | lastY > LOWER_BND(-(3.40282347e+38F/4.0f))) | |||
1614 | { | |||
1615 | if (skip) { | |||
1616 | tCoords[0] = closeCoord[0] = lastX; | |||
1617 | tCoords[1] = closeCoord[1] = lastY; | |||
1618 | subpathStarted = JNI_TRUE1; | |||
1619 | skip = JNI_FALSE0; | |||
1620 | } else { | |||
1621 | if (tCoords[2] < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1622 | tCoords[2] > LOWER_BND(-(3.40282347e+38F/4.0f)) && | |||
1623 | tCoords[3] < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1624 | tCoords[3] > LOWER_BND(-(3.40282347e+38F/4.0f))) | |||
1625 | { | |||
1626 | ProcessQuad(hnd, tCoords, pixelInfo); | |||
1627 | } else { | |||
1628 | ProcessLine(hnd, tCoords, | |||
1629 | tCoords + 4, pixelInfo); | |||
1630 | } | |||
1631 | tCoords[0] = lastX; | |||
1632 | tCoords[1] = lastY; | |||
1633 | } | |||
1634 | } | |||
1635 | } else { | |||
1636 | return JNI_FALSE0; | |||
1637 | } | |||
1638 | break; | |||
1639 | case java_awt_geom_PathIterator_SEG_CUBICTO3L: | |||
1640 | if (index + 6 <= maxCoords) { | |||
1641 | tCoords[2] = coords[index++] + transXf; | |||
1642 | tCoords[3] = coords[index++] + transYf; | |||
1643 | tCoords[4] = coords[index++] + transXf; | |||
1644 | tCoords[5] = coords[index++] + transYf; | |||
1645 | lastX = tCoords[6] = coords[index++] + transXf; | |||
1646 | lastY = tCoords[7] = coords[index++] + transYf; | |||
1647 | ||||
1648 | /* Checking SEG_CUBICTO coordinates if they are out of the | |||
1649 | * [LOWER_BND, UPPER_BND] range. This check also handles | |||
1650 | * NaN and Infinity values. Ignoring current path segment | |||
1651 | * in case of invalid endpoints's data. Equivalent to | |||
1652 | * the SEG_LINETO if endpoint coordinates are valid but | |||
1653 | * there are invalid data among other coordinates | |||
1654 | */ | |||
1655 | ||||
1656 | if (lastX < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1657 | lastX > LOWER_BND(-(3.40282347e+38F/4.0f)) && | |||
1658 | lastY < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1659 | lastY > LOWER_BND(-(3.40282347e+38F/4.0f))) | |||
1660 | { | |||
1661 | if (skip
| |||
1662 | tCoords[0] = closeCoord[0] = tCoords[6]; | |||
1663 | tCoords[1] = closeCoord[1] = tCoords[7]; | |||
1664 | subpathStarted = JNI_TRUE1; | |||
1665 | skip = JNI_FALSE0; | |||
1666 | } else { | |||
1667 | if (tCoords[2] < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1668 | tCoords[2] > LOWER_BND(-(3.40282347e+38F/4.0f)) && | |||
1669 | tCoords[3] < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1670 | tCoords[3] > LOWER_BND(-(3.40282347e+38F/4.0f)) && | |||
1671 | tCoords[4] < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1672 | tCoords[4] > LOWER_BND(-(3.40282347e+38F/4.0f)) && | |||
1673 | tCoords[5] < UPPER_BND(3.40282347e+38F/4.0f) && | |||
1674 | tCoords[5] > LOWER_BND(-(3.40282347e+38F/4.0f))) | |||
1675 | { | |||
1676 | ProcessCubic(hnd, tCoords, pixelInfo); | |||
1677 | } else { | |||
1678 | ProcessLine(hnd, tCoords, tCoords + 6, | |||
1679 | pixelInfo); | |||
1680 | } | |||
1681 | tCoords[0] = lastX; | |||
1682 | tCoords[1] = lastY; | |||
1683 | } | |||
1684 | } | |||
1685 | } else { | |||
1686 | return JNI_FALSE0; | |||
1687 | } | |||
1688 | break; | |||
1689 | case java_awt_geom_PathIterator_SEG_CLOSE4L: | |||
1690 | if (subpathStarted && !skip) { | |||
1691 | skip = JNI_FALSE0; | |||
1692 | if (tCoords[0] != closeCoord[0] || | |||
1693 | tCoords[1] != closeCoord[1]) | |||
1694 | { | |||
1695 | ProcessLine(hnd, tCoords, closeCoord, pixelInfo); | |||
1696 | /* Storing last path's point for using in | |||
1697 | * following segments without initial moveTo | |||
1698 | */ | |||
1699 | tCoords[0] = closeCoord[0]; | |||
1700 | tCoords[1] = closeCoord[1]; | |||
1701 | } | |||
1702 | ||||
1703 | hnd->pProcessEndSubPath(hnd); | |||
1704 | } | |||
1705 | ||||
1706 | break; | |||
1707 | } | |||
1708 | } | |||
1709 | ||||
1710 | /* Performing closing of the unclosed segments */ | |||
1711 | if (subpathStarted & !skip) { | |||
1712 | if (hnd->clipMode == PH_MODE_FILL_CLIP) { | |||
1713 | if (tCoords[0] != closeCoord[0] || | |||
1714 | tCoords[1] != closeCoord[1]) | |||
1715 | { | |||
1716 | ProcessLine(hnd, tCoords, closeCoord, | |||
1717 | pixelInfo); | |||
1718 | } | |||
1719 | } | |||
1720 | hnd->pProcessEndSubPath(hnd); | |||
1721 | } | |||
1722 | ||||
1723 | return JNI_TRUE1; | |||
1724 | } | |||
1725 | ||||
1726 | /* TODO Add checking of the result of the malloc/realloc functions to handle | |||
1727 | * out of memory error and don't leak earlier allocated data | |||
1728 | */ | |||
1729 | ||||
1730 | ||||
1731 | #define ALLOC(ptr, type, n)ptr = (type *)malloc((n)*sizeof(type)) \ | |||
1732 | ptr = (type *)malloc((n)*sizeof(type)) | |||
1733 | #define REALLOC(ptr, type, n)ptr = (type *)realloc(ptr, (n)*sizeof(type)) \ | |||
1734 | ptr = (type *)realloc(ptr, (n)*sizeof(type)) | |||
1735 | ||||
1736 | ||||
1737 | struct _Edge; | |||
1738 | ||||
1739 | typedef struct _Point { | |||
1740 | jint x; | |||
1741 | jint y; | |||
1742 | jboolean lastPoint; | |||
1743 | struct _Point* prev; | |||
1744 | struct _Point* next; | |||
1745 | struct _Point* nextByY; | |||
1746 | jboolean endSL; | |||
1747 | struct _Edge* edge; | |||
1748 | } Point; | |||
1749 | ||||
1750 | ||||
1751 | typedef struct _Edge { | |||
1752 | jint x; | |||
1753 | jint dx; | |||
1754 | Point* p; | |||
1755 | jint dir; | |||
1756 | struct _Edge* prev; | |||
1757 | struct _Edge* next; | |||
1758 | } Edge; | |||
1759 | ||||
1760 | /* Size of the default buffer in the FillData structure. This buffer is | |||
1761 | * replaced with heap allocated in case of large paths. | |||
1762 | */ | |||
1763 | #define DF_MAX_POINT256 256 | |||
1764 | ||||
1765 | /* Following structure accumulates points of the non-continuous flattened | |||
1766 | * path during iteration through the origin path's segments . The end | |||
1767 | * of the each subpath is marked as lastPoint flag set at the last point | |||
1768 | */ | |||
1769 | ||||
1770 | typedef struct { | |||
1771 | Point *plgPnts; | |||
1772 | Point dfPlgPnts[DF_MAX_POINT256]; | |||
1773 | jint plgSize; | |||
1774 | jint plgMax; | |||
1775 | jint plgYMin; | |||
1776 | jint plgYMax; | |||
1777 | } FillData; | |||
1778 | ||||
1779 | #define FD_INIT(PTR)do { (PTR)->plgPnts = (PTR)->dfPlgPnts; (PTR)->plgSize = 0; (PTR)->plgMax = 256; } while(0) \ | |||
1780 | do { \ | |||
1781 | (PTR)->plgPnts = (PTR)->dfPlgPnts; \ | |||
1782 | (PTR)->plgSize = 0; \ | |||
1783 | (PTR)->plgMax = DF_MAX_POINT256; \ | |||
1784 | } while(0) | |||
1785 | ||||
1786 | #define FD_ADD_POINT(PTR, X, Y, LASTPT)do { Point* _pnts = (PTR)->plgPnts; jint _size = (PTR)-> plgSize; if (_size >= (PTR)->plgMax) { jint newMax = (PTR )->plgMax*2; if ((PTR)->plgPnts == (PTR)->dfPlgPnts) { (PTR)->plgPnts = (Point*)malloc(newMax*sizeof(Point)); memcpy ((PTR)->plgPnts, _pnts, _size*sizeof(Point)); } else { (PTR )->plgPnts = (Point*)realloc( _pnts, newMax*sizeof(Point)) ; } _pnts = (PTR)->plgPnts; (PTR)->plgMax = newMax; } _pnts += _size; _pnts->x = X; _pnts->y = Y; _pnts->lastPoint = LASTPT; if (_size) { if ((PTR)->plgYMin > Y) (PTR)-> plgYMin = Y; if ((PTR)->plgYMax < Y) (PTR)->plgYMax = Y; } else { (PTR)->plgYMin = Y; (PTR)->plgYMax = Y; } ( PTR)->plgSize = _size + 1; } while(0) \ | |||
1787 | do { \ | |||
1788 | Point* _pnts = (PTR)->plgPnts; \ | |||
1789 | jint _size = (PTR)->plgSize; \ | |||
1790 | if (_size >= (PTR)->plgMax) { \ | |||
1791 | jint newMax = (PTR)->plgMax*2; \ | |||
1792 | if ((PTR)->plgPnts == (PTR)->dfPlgPnts) { \ | |||
1793 | (PTR)->plgPnts = (Point*)malloc(newMax*sizeof(Point)); \ | |||
1794 | memcpy((PTR)->plgPnts, _pnts, _size*sizeof(Point)); \ | |||
1795 | } else { \ | |||
1796 | (PTR)->plgPnts = (Point*)realloc( \ | |||
1797 | _pnts, newMax*sizeof(Point)); \ | |||
1798 | } \ | |||
1799 | _pnts = (PTR)->plgPnts; \ | |||
1800 | (PTR)->plgMax = newMax; \ | |||
1801 | } \ | |||
1802 | _pnts += _size; \ | |||
1803 | _pnts->x = X; \ | |||
1804 | _pnts->y = Y; \ | |||
1805 | _pnts->lastPoint = LASTPT; \ | |||
1806 | if (_size) { \ | |||
1807 | if ((PTR)->plgYMin > Y) (PTR)->plgYMin = Y; \ | |||
1808 | if ((PTR)->plgYMax < Y) (PTR)->plgYMax = Y; \ | |||
1809 | } else { \ | |||
1810 | (PTR)->plgYMin = Y; \ | |||
1811 | (PTR)->plgYMax = Y; \ | |||
1812 | } \ | |||
1813 | (PTR)->plgSize = _size + 1; \ | |||
1814 | } while(0) | |||
1815 | ||||
1816 | ||||
1817 | #define FD_FREE_POINTS(PTR)do { if ((PTR)->plgPnts != (PTR)->dfPlgPnts) { free((PTR )->plgPnts); } } while(0) \ | |||
1818 | do { \ | |||
1819 | if ((PTR)->plgPnts != (PTR)->dfPlgPnts) { \ | |||
1820 | free((PTR)->plgPnts); \ | |||
1821 | } \ | |||
1822 | } while(0) | |||
1823 | ||||
1824 | #define FD_IS_EMPTY(PTR)(!((PTR)->plgSize)) (!((PTR)->plgSize)) | |||
1825 | ||||
1826 | #define FD_IS_ENDED(PTR)((PTR)->plgPnts[(PTR)->plgSize - 1].lastPoint) ((PTR)->plgPnts[(PTR)->plgSize - 1].lastPoint) | |||
1827 | ||||
1828 | #define FD_SET_ENDED(PTR)do { (PTR)->plgPnts[(PTR)->plgSize - 1].lastPoint = 1; } while(0) \ | |||
1829 | do { \ | |||
1830 | (PTR)->plgPnts[(PTR)->plgSize - 1].lastPoint = JNI_TRUE1; \ | |||
1831 | } while(0) | |||
1832 | ||||
1833 | #define PFD(HND)((FillData*)(HND)->pData) ((FillData*)(HND)->pData) | |||
1834 | ||||
1835 | /* Bubble sorting in the ascending order of the linked list. This | |||
1836 | * implementation stops processing the list if there were no changes during the | |||
1837 | * previous pass. | |||
1838 | * | |||
1839 | * LIST - ptr to the ptr to the first element of the list | |||
1840 | * ETYPE - type of the element in the list | |||
1841 | * NEXT - accessor to the next field in the list element | |||
1842 | * GET_LKEY - accessor to the key of the list element | |||
1843 | */ | |||
1844 | #define LBUBBLE_SORT(LIST, ETYPE, NEXT, GET_LKEY)do { ETYPE *p, *q, *r, *s = ((void*)0), *temp ; jint wasSwap = 1; while ( s != NEXT(*LIST) && wasSwap) { r = p = *LIST ; q = NEXT(p); wasSwap = 0; while ( p != s ) { if (GET_LKEY(p ) >= GET_LKEY(q)) { wasSwap = 1; if ( p == *LIST ) { temp = NEXT(q); NEXT(q) = p ; NEXT(p) = temp ; *LIST = q ; r = q ; } else { temp = NEXT(q); NEXT(q) = p ; NEXT(p) = temp ; NEXT(r ) = q ; r = q ; } } else { r = p ; p = NEXT(p); } q = NEXT(p) ; if ( q == s ) s = p ; } } } while(0); \ | |||
1845 | do { \ | |||
1846 | ETYPE *p, *q, *r, *s = NULL((void*)0), *temp ; \ | |||
1847 | jint wasSwap = 1; \ | |||
1848 | /* r precedes p and s points to the node up to which comparisons \ | |||
1849 | * are to be made */ \ | |||
1850 | while ( s != NEXT(*LIST) && wasSwap) { \ | |||
1851 | r = p = *LIST; \ | |||
1852 | q = NEXT(p); \ | |||
1853 | wasSwap = 0; \ | |||
1854 | while ( p != s ) { \ | |||
1855 | if (GET_LKEY(p) >= GET_LKEY(q)) { \ | |||
1856 | wasSwap = 1; \ | |||
1857 | if ( p == *LIST ) { \ | |||
1858 | temp = NEXT(q); \ | |||
1859 | NEXT(q) = p ; \ | |||
1860 | NEXT(p) = temp ; \ | |||
1861 | *LIST = q ; \ | |||
1862 | r = q ; \ | |||
1863 | } else { \ | |||
1864 | temp = NEXT(q); \ | |||
1865 | NEXT(q) = p ; \ | |||
1866 | NEXT(p) = temp ; \ | |||
1867 | NEXT(r) = q ; \ | |||
1868 | r = q ; \ | |||
1869 | } \ | |||
1870 | } else { \ | |||
1871 | r = p ; \ | |||
1872 | p = NEXT(p); \ | |||
1873 | } \ | |||
1874 | q = NEXT(p); \ | |||
1875 | if ( q == s ) s = p ; \ | |||
1876 | } \ | |||
1877 | } \ | |||
1878 | } while(0); | |||
1879 | ||||
1880 | /* Accessors for the Edge structure to work with LBUBBLE_SORT */ | |||
1881 | #define GET_ACTIVE_KEY(a)(a->x) (a->x) | |||
1882 | #define GET_ACTIVE_NEXT(a)((a)->next) ((a)->next) | |||
1883 | ||||
1884 | /* TODO: Implement stack/heap allocation technique for active edges | |||
1885 | */ | |||
1886 | #define DELETE_ACTIVE(head,pnt)do { Edge *prevp = pnt->prev; Edge *nextp = pnt->next; if (prevp) { prevp->next = nextp; } else { head = nextp; } if (nextp) { nextp->prev = prevp; } } while(0); \ | |||
1887 | do { \ | |||
1888 | Edge *prevp = pnt->prev; \ | |||
1889 | Edge *nextp = pnt->next; \ | |||
1890 | if (prevp) { \ | |||
1891 | prevp->next = nextp; \ | |||
1892 | } else { \ | |||
1893 | head = nextp; \ | |||
1894 | } \ | |||
1895 | if (nextp) { \ | |||
1896 | nextp->prev = prevp; \ | |||
1897 | } \ | |||
1898 | } while(0); | |||
1899 | ||||
1900 | #define INSERT_ACTIVE(head,pnt,cy)do { Point *np = pnt->next; Edge *ne = active + nact; if ( pnt->y == np->y) { break; } else { jint dX = np->x - pnt->x; jint dY = np->y - pnt->y; jint dy; if (pnt-> y < np->y) { ne->dir = -1; ne->p = pnt; ne->x = pnt->x; dy = cy - pnt->y; } else { ne->dir = 1; ne-> p = np; ne->x = np->x; dy = cy - np->y; } if ((((dX) ^((dX)>>31))-((dX)>>31)) > (1 << (30 - 10 ))) { ne->dx = (jint)((((jdouble)dX)*(1<<10))/dY); ne ->x += (jint)((((jdouble)dX)*dy)/dY); } else { ne->dx = ((dX)<<10)/dY; ne->x += (dX*dy)/dY; } } ne->next = head; ne->prev = ((void*)0); if (head) { head->prev = ne; } head = active + nact; pnt->edge = head; nact++; } while (0); \ | |||
1901 | do { \ | |||
1902 | Point *np = pnt->next; \ | |||
1903 | Edge *ne = active + nact; \ | |||
1904 | if (pnt->y == np->y) { \ | |||
1905 | /* Skipping horizontal segments */ \ | |||
1906 | break; \ | |||
1907 | } else { \ | |||
1908 | jint dX = np->x - pnt->x; \ | |||
1909 | jint dY = np->y - pnt->y; \ | |||
1910 | jint dy; \ | |||
1911 | if (pnt->y < np->y) { \ | |||
1912 | ne->dir = -1; \ | |||
1913 | ne->p = pnt; \ | |||
1914 | ne->x = pnt->x; \ | |||
1915 | dy = cy - pnt->y; \ | |||
1916 | } else { /* pnt->y > np->y */ \ | |||
1917 | ne->dir = 1; \ | |||
1918 | ne->p = np; \ | |||
1919 | ne->x = np->x; \ | |||
1920 | dy = cy - np->y; \ | |||
1921 | } \ | |||
1922 | \ | |||
1923 | /* We need to worry only about dX because dY is in */\ | |||
1924 | /* denominator and abs(dy) < MDP_MULT (cy is a first */\ | |||
1925 | /* scanline of the scan converted segment and we subtract */\ | |||
1926 | /* y coordinate of the nearest segment's end from it to */\ | |||
1927 | /* obtain dy) */\ | |||
1928 | if (ABS32(dX)(((dX)^((dX)>>31))-((dX)>>31)) > CALC_BND(1 << (30 - 10))) { \ | |||
1929 | ne->dx = (jint)((((jdouble)dX)*MDP_MULT(1<<10))/dY); \ | |||
1930 | ne->x += (jint)((((jdouble)dX)*dy)/dY); \ | |||
1931 | } else { \ | |||
1932 | ne->dx = ((dX)<<MDP_PREC10)/dY; \ | |||
1933 | ne->x += (dX*dy)/dY; \ | |||
1934 | } \ | |||
1935 | } \ | |||
1936 | ne->next = head; \ | |||
1937 | ne->prev = NULL((void*)0); \ | |||
1938 | if (head) { \ | |||
1939 | head->prev = ne; \ | |||
1940 | } \ | |||
1941 | head = active + nact; \ | |||
1942 | pnt->edge = head; \ | |||
1943 | nact++; \ | |||
1944 | } while(0); | |||
1945 | ||||
1946 | void FillPolygon(ProcessHandler* hnd, | |||
1947 | jint fillRule) { | |||
1948 | jint k, y, xl, xr; | |||
1949 | jint drawing; | |||
1950 | Edge* activeList, *active; | |||
1951 | Edge* curEdge, *prevEdge; | |||
1952 | jint nact; | |||
1953 | jint n; | |||
1954 | Point* pt, *curpt, *ept; | |||
1955 | Point** yHash; | |||
1956 | Point** curHash; | |||
1957 | jint rightBnd = hnd->dhnd->xMax - 1; | |||
1958 | FillData* pfd = (FillData*)(hnd->pData); | |||
1959 | jint yMin = pfd->plgYMin; | |||
1960 | jint yMax = pfd->plgYMax; | |||
1961 | jint hashSize = ((yMax - yMin)>>MDP_PREC10) + 4; | |||
1962 | ||||
1963 | /* Because of support of the KEY_STROKE_CONTROL hint we are performing | |||
1964 | * shift of the coordinates at the higher level | |||
1965 | */ | |||
1966 | jint hashOffset = ((yMin - 1) & MDP_W_MASK(-(1<<10))); | |||
1967 | ||||
1968 | // TODO creating lists using fake first element to avoid special casing of | |||
1969 | // the first element in the list (which otherwise should be performed in each | |||
1970 | // list operation) | |||
1971 | ||||
1972 | /* Winding counter */ | |||
1973 | jint counter; | |||
1974 | ||||
1975 | /* Calculating mask to be applied to the winding counter */ | |||
1976 | jint counterMask = | |||
1977 | (fillRule == java_awt_geom_PathIterator_WIND_NON_ZERO1L)? -1:1; | |||
1978 | pt = pfd->plgPnts; | |||
1979 | n = pfd->plgSize; | |||
1980 | ||||
1981 | if (n <=1) return; | |||
1982 | ||||
1983 | ALLOC(yHash, Point*, hashSize)yHash = (Point* *)malloc((hashSize)*sizeof(Point*)); | |||
1984 | for (k = 0; k < hashSize; k++) { | |||
1985 | yHash[k] = NULL((void*)0); | |||
1986 | } | |||
1987 | ||||
1988 | ALLOC(active, Edge, n)active = (Edge *)malloc((n)*sizeof(Edge)); | |||
1989 | ||||
1990 | /* Creating double linked list (prev, next links) describing path order and | |||
1991 | * hash table with points which fall between scanlines. nextByY link is | |||
1992 | * used for the points which are between same scanlines. Scanlines are | |||
1993 | * passed through the centers of the pixels. | |||
1994 | */ | |||
1995 | curpt = pt; | |||
1996 | curpt->prev = NULL((void*)0); | |||
1997 | ept = pt + n - 1; | |||
1998 | for (curpt = pt; curpt != ept; curpt++) { | |||
1999 | Point* nextpt = curpt + 1; | |||
2000 | curHash = yHash + ((curpt->y - hashOffset - 1) >> MDP_PREC10); | |||
2001 | curpt->nextByY = *curHash; | |||
2002 | *curHash = curpt; | |||
2003 | curpt->next = nextpt; | |||
2004 | nextpt->prev = curpt; | |||
2005 | curpt->edge = NULL((void*)0); | |||
2006 | } | |||
2007 | ||||
2008 | curHash = yHash + ((ept->y - hashOffset - 1) >> MDP_PREC10); | |||
2009 | ept->nextByY = *curHash; | |||
2010 | *curHash = ept; | |||
2011 | ept->next = NULL((void*)0); | |||
2012 | ept->edge = NULL((void*)0); | |||
2013 | nact = 0; | |||
2014 | ||||
2015 | activeList = NULL((void*)0); | |||
2016 | for (y=hashOffset + MDP_MULT(1<<10),k = 0; | |||
2017 | y<=yMax && k < hashSize; y += MDP_MULT(1<<10), k++) | |||
2018 | { | |||
2019 | for(pt = yHash[k];pt; pt=pt->nextByY) { | |||
2020 | /* pt->y should be inside hashed interval | |||
2021 | * assert(y-MDP_MULT <= pt->y && pt->y < y); | |||
2022 | */ | |||
2023 | if (pt->prev && !pt->prev->lastPoint) { | |||
2024 | if (pt->prev->edge && pt->prev->y <= y) { | |||
2025 | DELETE_ACTIVE(activeList, pt->prev->edge)do { Edge *prevp = pt->prev->edge->prev; Edge *nextp = pt->prev->edge->next; if (prevp) { prevp->next = nextp; } else { activeList = nextp; } if (nextp) { nextp-> prev = prevp; } } while(0);; | |||
2026 | pt->prev->edge = NULL((void*)0); | |||
2027 | } else if (pt->prev->y > y) { | |||
2028 | INSERT_ACTIVE(activeList, pt->prev, y)do { Point *np = pt->prev->next; Edge *ne = active + nact ; if (pt->prev->y == np->y) { break; } else { jint dX = np->x - pt->prev->x; jint dY = np->y - pt-> prev->y; jint dy; if (pt->prev->y < np->y) { ne ->dir = -1; ne->p = pt->prev; ne->x = pt->prev ->x; dy = y - pt->prev->y; } else { ne->dir = 1; ne ->p = np; ne->x = np->x; dy = y - np->y; } if ((( (dX)^((dX)>>31))-((dX)>>31)) > (1 << (30 - 10))) { ne->dx = (jint)((((jdouble)dX)*(1<<10))/dY ); ne->x += (jint)((((jdouble)dX)*dy)/dY); } else { ne-> dx = ((dX)<<10)/dY; ne->x += (dX*dy)/dY; } } ne-> next = activeList; ne->prev = ((void*)0); if (activeList) { activeList->prev = ne; } activeList = active + nact; pt-> prev->edge = activeList; nact++; } while(0);; | |||
2029 | } | |||
2030 | } | |||
2031 | ||||
2032 | if (!pt->lastPoint && pt->next) { | |||
2033 | if (pt->edge && pt->next->y <= y) { | |||
2034 | DELETE_ACTIVE(activeList, pt->edge)do { Edge *prevp = pt->edge->prev; Edge *nextp = pt-> edge->next; if (prevp) { prevp->next = nextp; } else { activeList = nextp; } if (nextp) { nextp->prev = prevp; } } while(0) ;; | |||
2035 | pt->edge = NULL((void*)0); | |||
2036 | } else if (pt->next->y > y) { | |||
2037 | INSERT_ACTIVE(activeList, pt, y)do { Point *np = pt->next; Edge *ne = active + nact; if (pt ->y == np->y) { break; } else { jint dX = np->x - pt ->x; jint dY = np->y - pt->y; jint dy; if (pt->y < np->y) { ne->dir = -1; ne->p = pt; ne->x = pt-> x; dy = y - pt->y; } else { ne->dir = 1; ne->p = np; ne->x = np->x; dy = y - np->y; } if ((((dX)^((dX)>> 31))-((dX)>>31)) > (1 << (30 - 10))) { ne-> dx = (jint)((((jdouble)dX)*(1<<10))/dY); ne->x += (jint )((((jdouble)dX)*dy)/dY); } else { ne->dx = ((dX)<<10 )/dY; ne->x += (dX*dy)/dY; } } ne->next = activeList; ne ->prev = ((void*)0); if (activeList) { activeList->prev = ne; } activeList = active + nact; pt->edge = activeList ; nact++; } while(0);; | |||
2038 | } | |||
2039 | } | |||
2040 | } | |||
2041 | ||||
2042 | if (!activeList) continue; | |||
2043 | ||||
2044 | /* We could not use O(N) Radix sort here because in most cases list of | |||
2045 | * edges almost sorted. So, bubble sort (O(N^2))is working much | |||
2046 | * better. Note, in case of array of edges Shell sort is more | |||
2047 | * efficient. | |||
2048 | */ | |||
2049 | LBUBBLE_SORT((&activeList), Edge, GET_ACTIVE_NEXT, GET_ACTIVE_KEY)do { Edge *p, *q, *r, *s = ((void*)0), *temp ; jint wasSwap = 1; while ( s != ((*(&activeList))->next) && wasSwap ) { r = p = *(&activeList); q = ((p)->next); wasSwap = 0; while ( p != s ) { if ((p->x) >= (q->x)) { wasSwap = 1; if ( p == *(&activeList) ) { temp = ((q)->next); ((q)->next) = p ; ((p)->next) = temp ; *(&activeList ) = q ; r = q ; } else { temp = ((q)->next); ((q)->next ) = p ; ((p)->next) = temp ; ((r)->next) = q ; r = q ; } } else { r = p ; p = ((p)->next); } q = ((p)->next); if ( q == s ) s = p ; } } } while(0);; | |||
2050 | ||||
2051 | /* Correction of the back links in the double linked edge list */ | |||
2052 | curEdge=activeList; | |||
2053 | prevEdge = NULL((void*)0); | |||
2054 | while (curEdge) { | |||
2055 | curEdge->prev = prevEdge; | |||
2056 | prevEdge = curEdge; | |||
2057 | curEdge = curEdge->next; | |||
2058 | } | |||
2059 | ||||
2060 | xl = xr = hnd->dhnd->xMin; | |||
2061 | curEdge = activeList; | |||
2062 | counter = 0; | |||
2063 | drawing = 0; | |||
2064 | for(;curEdge; curEdge = curEdge->next) { | |||
2065 | counter += curEdge->dir; | |||
2066 | if ((counter & counterMask) && !drawing) { | |||
2067 | xl = (curEdge->x + MDP_MULT(1<<10) - 1)>>MDP_PREC10; | |||
2068 | drawing = 1; | |||
2069 | } | |||
2070 | ||||
2071 | if (!(counter & counterMask) && drawing) { | |||
2072 | xr = (curEdge->x - 1)>>MDP_PREC10; | |||
2073 | if (xl <= xr) { | |||
2074 | hnd->dhnd->pDrawScanline(hnd->dhnd, xl, xr, y >> MDP_PREC10); | |||
2075 | } | |||
2076 | drawing = 0; | |||
2077 | } | |||
2078 | ||||
2079 | curEdge->x += curEdge->dx; | |||
2080 | } | |||
2081 | ||||
2082 | /* Performing drawing till the right boundary (for correct rendering | |||
2083 | * shapes clipped at the right side) | |||
2084 | */ | |||
2085 | if (drawing && xl <= rightBnd) { | |||
2086 | hnd->dhnd->pDrawScanline(hnd->dhnd, xl, rightBnd, y >> MDP_PREC10); | |||
2087 | } | |||
2088 | } | |||
2089 | free(active); | |||
2090 | free(yHash); | |||
2091 | } | |||
2092 | ||||
2093 | ||||
2094 | ||||
2095 | void StoreFixedLine(ProcessHandler* hnd,jint x1,jint y1,jint x2,jint y2, | |||
2096 | jint* pixelInfo,jboolean checkBounds, | |||
2097 | jboolean endSubPath) { | |||
2098 | FillData* pfd; | |||
2099 | jint outXMin, outXMax, outYMin, outYMax; | |||
2100 | jint x3, y3, res; | |||
2101 | ||||
2102 | /* There is no need to round line coordinates to the forward differencing | |||
2103 | * precision anymore. Such a rounding was used for preventing the curve go | |||
2104 | * out the endpoint (this sometimes does not help). The problem was fixed | |||
2105 | * in the forward differencing loops. | |||
2106 | */ | |||
2107 | ||||
2108 | if (checkBounds) { | |||
2109 | jboolean lastClipped = JNI_FALSE0; | |||
2110 | ||||
2111 | /* This function is used only for filling shapes, so there is no | |||
2112 | * check for the type of clipping | |||
2113 | */ | |||
2114 | outXMin = (jint)(hnd->dhnd->xMinf * MDP_MULT(1<<10)); | |||
2115 | outXMax = (jint)(hnd->dhnd->xMaxf * MDP_MULT(1<<10)); | |||
2116 | outYMin = (jint)(hnd->dhnd->yMinf * MDP_MULT(1<<10)); | |||
2117 | outYMax = (jint)(hnd->dhnd->yMaxf * MDP_MULT(1<<10)); | |||
2118 | ||||
2119 | TESTANDCLIP(outYMin, outYMax, y1, x1, y2, x2, jint, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (y1 < (outYMin) || y1 > (outYMax)) { if (y1 < (outYMin)) { if (y2 < (outYMin)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED ; t = (outYMin); } else { if (y2 > (outYMax)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (outYMax); } x1 = (jint )(x1 + ((jdouble)(t - y1)*(x2 - x1)) / (y2 - y1)); y1 = (jint )t; } } while (0); | |||
2120 | if (res == CRES_INVISIBLE) return; | |||
2121 | TESTANDCLIP(outYMin, outYMax, y2, x2, y1, x1, jint, res)do { jdouble t; res = CRES_NOT_CLIPPED; if (y2 < (outYMin) || y2 > (outYMax)) { if (y2 < (outYMin)) { if (y1 < (outYMin)) { res = CRES_INVISIBLE; break; }; res = CRES_MIN_CLIPPED ; t = (outYMin); } else { if (y1 > (outYMax)) { res = CRES_INVISIBLE ; break; }; res = CRES_MAX_CLIPPED; t = (outYMax); } x2 = (jint )(x2 + ((jdouble)(t - y2)*(x1 - x2)) / (y1 - y2)); y2 = (jint )t; } } while (0); | |||
2122 | if (res == CRES_INVISIBLE) return; | |||
2123 | lastClipped = IS_CLIPPED(res)(res == CRES_MIN_CLIPPED || res == CRES_MAX_CLIPPED); | |||
2124 | ||||
2125 | /* Clamping starting from first vertex of the processed segment */ | |||
2126 | CLIPCLAMP(outXMin, outXMax, x1, y1, x2, y2, x3, y3, jint, res)do { x3 = x1; y3 = y1; do { jdouble t; res = CRES_NOT_CLIPPED ; if (x1 < (outXMin) || x1 > (outXMax)) { if (x1 < ( outXMin)) { if (x2 < (outXMin)) { res = CRES_INVISIBLE; break ; }; res = CRES_MIN_CLIPPED; t = (outXMin); } else { if (x2 > (outXMax)) { res = CRES_INVISIBLE; break; }; res = CRES_MAX_CLIPPED ; t = (outXMax); } y1 = (jint)(y1 + ((jdouble)(t - x1)*(y2 - y1 )) / (x2 - x1)); x1 = (jint)t; } } while (0); if (res == CRES_MIN_CLIPPED ) { x3 = x1; } else if (res == CRES_MAX_CLIPPED) { x3 = x1; res = CRES_MAX_CLIPPED; } else if (res == CRES_INVISIBLE) { if ( x1 > outXMax) { res = CRES_INVISIBLE; } else { x1 = (jint) outXMin; x2 = (jint)outXMin; res = CRES_NOT_CLIPPED; } } } while (0); | |||
2127 | ||||
2128 | /* Clamping only by left boundary */ | |||
2129 | if (res == CRES_MIN_CLIPPED) { | |||
2130 | StoreFixedLine(hnd, x3, y3, x1, y1, pixelInfo, | |||
2131 | JNI_FALSE0, lastClipped); | |||
2132 | ||||
2133 | } else if (res == CRES_INVISIBLE) { | |||
2134 | return; | |||
2135 | } | |||
2136 | ||||
2137 | /* Clamping starting from last vertex of the processed segment */ | |||
2138 | CLIPCLAMP(outXMin, outXMax, x2, y2, x1, y1, x3, y3, jint, res)do { x3 = x2; y3 = y2; do { jdouble t; res = CRES_NOT_CLIPPED ; if (x2 < (outXMin) || x2 > (outXMax)) { if (x2 < ( outXMin)) { if (x1 < (outXMin)) { res = CRES_INVISIBLE; break ; }; res = CRES_MIN_CLIPPED; t = (outXMin); } else { if (x1 > (outXMax)) { res = CRES_INVISIBLE; break; }; res = CRES_MAX_CLIPPED ; t = (outXMax); } y2 = (jint)(y2 + ((jdouble)(t - x2)*(y1 - y2 )) / (x1 - x2)); x2 = (jint)t; } } while (0); if (res == CRES_MIN_CLIPPED ) { x3 = x2; } else if (res == CRES_MAX_CLIPPED) { x3 = x2; res = CRES_MAX_CLIPPED; } else if (res == CRES_INVISIBLE) { if ( x2 > outXMax) { res = CRES_INVISIBLE; } else { x2 = (jint) outXMin; x1 = (jint)outXMin; res = CRES_NOT_CLIPPED; } } } while (0); | |||
2139 | ||||
2140 | /* Checking if there was a clip by right boundary */ | |||
2141 | lastClipped = lastClipped || (res == CRES_MAX_CLIPPED); | |||
2142 | ||||
2143 | StoreFixedLine(hnd, x1, y1, x2, y2, pixelInfo, | |||
2144 | JNI_FALSE0, lastClipped); | |||
2145 | ||||
2146 | /* Clamping only by left boundary */ | |||
2147 | if (res == CRES_MIN_CLIPPED) { | |||
2148 | StoreFixedLine(hnd, x2, y2, x3, y3, pixelInfo, | |||
2149 | JNI_FALSE0, lastClipped); | |||
2150 | } | |||
2151 | ||||
2152 | return; | |||
2153 | } | |||
2154 | pfd = (FillData*)(hnd->pData); | |||
2155 | ||||
2156 | /* Adding first point of the line only in case of empty or just finished | |||
2157 | * path | |||
2158 | */ | |||
2159 | if (FD_IS_EMPTY(pfd)(!((pfd)->plgSize)) || FD_IS_ENDED(pfd)((pfd)->plgPnts[(pfd)->plgSize - 1].lastPoint)) { | |||
2160 | FD_ADD_POINT(pfd, x1, y1, JNI_FALSE)do { Point* _pnts = (pfd)->plgPnts; jint _size = (pfd)-> plgSize; if (_size >= (pfd)->plgMax) { jint newMax = (pfd )->plgMax*2; if ((pfd)->plgPnts == (pfd)->dfPlgPnts) { (pfd)->plgPnts = (Point*)malloc(newMax*sizeof(Point)); memcpy ((pfd)->plgPnts, _pnts, _size*sizeof(Point)); } else { (pfd )->plgPnts = (Point*)realloc( _pnts, newMax*sizeof(Point)) ; } _pnts = (pfd)->plgPnts; (pfd)->plgMax = newMax; } _pnts += _size; _pnts->x = x1; _pnts->y = y1; _pnts->lastPoint = 0; if (_size) { if ((pfd)->plgYMin > y1) (pfd)->plgYMin = y1; if ((pfd)->plgYMax < y1) (pfd)->plgYMax = y1; } else { (pfd)->plgYMin = y1; (pfd)->plgYMax = y1; } ( pfd)->plgSize = _size + 1; } while(0); | |||
2161 | } | |||
2162 | ||||
2163 | FD_ADD_POINT(pfd, x2, y2, JNI_FALSE)do { Point* _pnts = (pfd)->plgPnts; jint _size = (pfd)-> plgSize; if (_size >= (pfd)->plgMax) { jint newMax = (pfd )->plgMax*2; if ((pfd)->plgPnts == (pfd)->dfPlgPnts) { (pfd)->plgPnts = (Point*)malloc(newMax*sizeof(Point)); memcpy ((pfd)->plgPnts, _pnts, _size*sizeof(Point)); } else { (pfd )->plgPnts = (Point*)realloc( _pnts, newMax*sizeof(Point)) ; } _pnts = (pfd)->plgPnts; (pfd)->plgMax = newMax; } _pnts += _size; _pnts->x = x2; _pnts->y = y2; _pnts->lastPoint = 0; if (_size) { if ((pfd)->plgYMin > y2) (pfd)->plgYMin = y2; if ((pfd)->plgYMax < y2) (pfd)->plgYMax = y2; } else { (pfd)->plgYMin = y2; (pfd)->plgYMax = y2; } ( pfd)->plgSize = _size + 1; } while(0); | |||
2164 | ||||
2165 | if (endSubPath) { | |||
2166 | FD_SET_ENDED(pfd)do { (pfd)->plgPnts[(pfd)->plgSize - 1].lastPoint = 1; } while(0); | |||
2167 | } | |||
2168 | } | |||
2169 | ||||
2170 | ||||
2171 | static void endSubPath(ProcessHandler* hnd) { | |||
2172 | FillData* pfd = (FillData*)(hnd->pData); | |||
2173 | if (!FD_IS_EMPTY(pfd)(!((pfd)->plgSize))) { | |||
2174 | FD_SET_ENDED(pfd)do { (pfd)->plgPnts[(pfd)->plgSize - 1].lastPoint = 1; } while(0); | |||
2175 | } | |||
2176 | } | |||
2177 | ||||
2178 | static void stubEndSubPath(ProcessHandler* hnd) { | |||
2179 | } | |||
2180 | ||||
2181 | JNIEXPORT__attribute__((visibility("default"))) jboolean JNICALL | |||
2182 | doFillPath(DrawHandler* dhnd, | |||
2183 | jint transX, jint transY, | |||
2184 | jfloat* coords, jint maxCoords, | |||
2185 | jbyte* types, jint numTypes, | |||
2186 | PHStroke stroke, jint fillRule) | |||
2187 | { | |||
2188 | jint res; | |||
2189 | ||||
2190 | FillData fillData; | |||
2191 | ||||
2192 | ProcessHandler hnd = | |||
2193 | { | |||
2194 | &StoreFixedLine, | |||
2195 | &endSubPath, | |||
2196 | NULL((void*)0), | |||
2197 | PH_STROKE_DEFAULT, | |||
2198 | PH_MODE_FILL_CLIP, | |||
2199 | NULL((void*)0) | |||
2200 | }; | |||
2201 | ||||
2202 | /* Initialization of the following fields in the declaration of the hnd | |||
2203 | * above causes warnings on sun studio compiler with -xc99=%none option | |||
2204 | * applied (this option means compliance with C90 standard instead of C99) | |||
2205 | */ | |||
2206 | hnd.dhnd = dhnd; | |||
2207 | hnd.pData = &fillData; | |||
2208 | hnd.stroke = stroke; | |||
2209 | ||||
2210 | FD_INIT(&fillData)do { (&fillData)->plgPnts = (&fillData)->dfPlgPnts ; (&fillData)->plgSize = 0; (&fillData)->plgMax = 256; } while(0); | |||
2211 | res = ProcessPath(&hnd, (jfloat)transX, (jfloat)transY, | |||
2212 | coords, maxCoords, types, numTypes); | |||
2213 | if (!res) { | |||
2214 | FD_FREE_POINTS(&fillData)do { if ((&fillData)->plgPnts != (&fillData)->dfPlgPnts ) { free((&fillData)->plgPnts); } } while(0); | |||
2215 | return JNI_FALSE0; | |||
2216 | } | |||
2217 | FillPolygon(&hnd, fillRule); | |||
2218 | FD_FREE_POINTS(&fillData)do { if ((&fillData)->plgPnts != (&fillData)->dfPlgPnts ) { free((&fillData)->plgPnts); } } while(0); | |||
2219 | return JNI_TRUE1; | |||
2220 | } | |||
2221 | ||||
2222 | JNIEXPORT__attribute__((visibility("default"))) jboolean JNICALL | |||
2223 | doDrawPath(DrawHandler* dhnd, | |||
2224 | void (*pProcessEndSubPath)(ProcessHandler*), | |||
2225 | jint transX, jint transY, | |||
2226 | jfloat* coords, jint maxCoords, | |||
2227 | jbyte* types, jint numTypes, PHStroke stroke) | |||
2228 | { | |||
2229 | ProcessHandler hnd = | |||
2230 | { | |||
2231 | &ProcessFixedLine, | |||
2232 | NULL((void*)0), | |||
2233 | NULL((void*)0), | |||
2234 | PH_STROKE_DEFAULT, | |||
2235 | PH_MODE_DRAW_CLIP, | |||
2236 | NULL((void*)0) | |||
2237 | }; | |||
2238 | ||||
2239 | /* Initialization of the following fields in the declaration of the hnd | |||
2240 | * above causes warnings on sun studio compiler with -xc99=%none option | |||
2241 | * applied (this option means compliance with C90 standard instead of C99) | |||
2242 | */ | |||
2243 | hnd.dhnd = dhnd; | |||
2244 | hnd.stroke = stroke; | |||
2245 | ||||
2246 | hnd.pProcessEndSubPath = (pProcessEndSubPath == NULL((void*)0))? | |||
2247 | stubEndSubPath : pProcessEndSubPath; | |||
2248 | return ProcessPath(&hnd, (jfloat)transX, (jfloat)transY, coords, maxCoords, | |||
2249 | types, numTypes); | |||
2250 | } |