Bug Summary

File:jdk/src/java.desktop/share/native/libawt/java2d/loops/ProcessPath.c
Warning:line 2060, column 14
Although the value stored to 'xr' is used in the enclosing expression, the value is never actually read from 'xr'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ProcessPath.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -fno-delete-null-pointer-checks -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/modules_include/java.base/linux -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava -I /home/daniel/Projects/java/jdk/src/hotspot/share/include -I /home/daniel/Projects/java/jdk/src/hotspot/os/posix/include -D LIBC=gnu -D _GNU_SOURCE -D _REENTRANT -D _LARGEFILE64_SOURCE -D LINUX -D DEBUG -D _LITTLE_ENDIAN -D ARCH="amd64" -D amd64 -D _LP64=1 -D __MEDIALIB_OLD_NAMES -D __USE_J2D_NAMES -D MLIB_NO_LIBSUNMATH -I /home/daniel/Projects/java/jdk/src/java.desktop/unix/native/libawt -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libawt -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/debug -I /home/daniel/Projects/java/jdk/src/java.desktop/unix/native/common/awt -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/headers/java.desktop -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libawt/awt/image -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libawt/awt/image/cvutils -I /home/daniel/Projects/java/jdk/src/java.desktop/unix/native/libawt/java2d -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libawt/java2d -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libawt/java2d/loops -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libawt/java2d/pipe -I /home/daniel/Projects/java/jdk/build/linux-x86_64-server-fastdebug/support/headers/java.base -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libawt/awt/medialib -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/common/awt/medialib -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libmlib_image -I /home/daniel/Projects/java/jdk/src/java.desktop/unix/native/include -I /home/daniel/Projects/java/jdk/src/java.desktop/share/native/include -I /home/daniel/Projects/java/jdk/src/java.base/linux/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/share/native/libjava -I /home/daniel/Projects/java/jdk/src/java.base/unix/native/include -I /home/daniel/Projects/java/jdk/src/java.base/share/native/include -D _FORTIFY_SOURCE=2 -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-unused -Wno-sign-compare -Wno-unused-result -Wno-maybe-uninitialized -Wno-format-nonliteral -Wno-parentheses -Wno-unused-value -Wno-unused-function -std=c99 -fdebug-compilation-dir /home/daniel/Projects/java/jdk/make -ferror-limit 19 -fmessage-length 0 -fvisibility default -stack-protector 1 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/daniel/Projects/java/scan/2021-12-21-193737-8510-1 -x c /home/daniel/Projects/java/jdk/src/java.desktop/share/native/libawt/java2d/loops/ProcessPath.c
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
317enum {
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 */
474void 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 */
566static 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 */
677static 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 */
759static 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 */
781static 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
994static 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 */
1160static 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 */
1254static 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 */
1285static 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
1367static 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
1461jboolean 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
1737struct _Edge;
1738
1739typedef 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
1751typedef 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
1770typedef 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);
\
1887do { \
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);
\
1901do { \
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
1946void 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;
Although the value stored to 'xr' is used in the enclosing expression, the value is never actually read from 'xr'
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
2095void 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
2171static 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
2178static void stubEndSubPath(ProcessHandler* hnd) {
2179}
2180
2181JNIEXPORT__attribute__((visibility("default"))) jboolean JNICALL
2182doFillPath(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
2222JNIEXPORT__attribute__((visibility("default"))) jboolean JNICALL
2223doDrawPath(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}