1 /*
2 * Copyright 2014 Adobe Systems Incorporated (http://www.adobe.com/).
3 * All Rights Reserved.
4 *
5 * This software is licensed as OpenSource, under the Apache License, Version
6 * 2.0.
7 * This license is available at: http://opensource.org/licenses/Apache-2.0.
8 */
9
10 #include "ac.h"
11
12 PathElt*
GetDest(PathElt * cldest)13 GetDest(PathElt* cldest)
14 {
15 if (cldest == NULL)
16 return NULL;
17 while (true) {
18 cldest = cldest->prev;
19 if (cldest == NULL)
20 return gPathStart;
21 if (cldest->type == MOVETO)
22 return cldest;
23 }
24 }
25
26 PathElt*
GetClosedBy(PathElt * clsdby)27 GetClosedBy(PathElt* clsdby)
28 {
29 if (clsdby == NULL)
30 return NULL;
31 if (clsdby->type == CLOSEPATH)
32 return clsdby;
33 while (true) {
34 clsdby = clsdby->next;
35 if (clsdby == NULL)
36 return NULL;
37 if (clsdby->type == MOVETO)
38 return NULL;
39 if (clsdby->type == CLOSEPATH)
40 return clsdby;
41 }
42 }
43
44 void
GetEndPoint(PathElt * e,Fixed * x1p,Fixed * y1p)45 GetEndPoint(PathElt* e, Fixed* x1p, Fixed* y1p)
46 {
47 retry:
48 if (e == NULL) {
49 *x1p = 0;
50 *y1p = 0;
51 return;
52 }
53 switch (e->type) {
54 case MOVETO:
55 case LINETO:
56 *x1p = e->x;
57 *y1p = e->y;
58 break;
59 case CURVETO:
60 *x1p = e->x3;
61 *y1p = e->y3;
62 break;
63 case CLOSEPATH:
64 e = GetDest(e);
65 if (e == NULL || e->type == CLOSEPATH) {
66 LogMsg(LOGERROR, NONFATALERROR, "Bad description.");
67 }
68 goto retry;
69 default: {
70 LogMsg(LOGERROR, NONFATALERROR, "Illegal operator.");
71 }
72 }
73 }
74
75 void
GetEndPoints(PathElt * p,Fixed * px0,Fixed * py0,Fixed * px1,Fixed * py1)76 GetEndPoints(PathElt* p, Fixed* px0, Fixed* py0, Fixed* px1, Fixed* py1)
77 {
78 GetEndPoint(p, px1, py1);
79 GetEndPoint(p->prev, px0, py0);
80 }
81
82 #define Interpolate(q, v0, q0, v1, q1) (v0 + (q - q0) * ((v1 - v0) / (q1 - q0)))
83 static Fixed
HVness(float * pq)84 HVness(float* pq)
85 {
86 float q;
87 float result;
88 /* approximately == 2 q neg exp */
89 /* as q -> 0, result goes to 1.0 */
90 /* as q -> inf, result goes to 0.0 */
91 q = *pq;
92 if (q < .25f)
93 result = (float)Interpolate(q, 1.0f, 0.0f, .841f, .25f);
94 else if (q < .5f)
95 result = (float)Interpolate(q, .841f, .25f, .707f, .5f);
96 else if (q < 1)
97 result = (float)Interpolate(q, .707f, .5f, .5f, 1.0f);
98 else if (q < 2)
99 result = (float)Interpolate(q, .5f, 1.0f, .25f, 2.0f);
100 else if (q < 4)
101 result = (float)Interpolate(q, .25f, 2.0f, 0.0f, 4.0f);
102 else
103 result = 0.0;
104 return acpflttofix(&result);
105 }
106
107 Fixed
VertQuo(Fixed xk,Fixed yk,Fixed xl,Fixed yl)108 VertQuo(Fixed xk, Fixed yk, Fixed xl, Fixed yl)
109 {
110 /* FixOne means exactly vertical. 0 means not vertical */
111 /* intermediate values mean almost vertical */
112 Fixed xabs, yabs;
113 float rx, ry, q;
114 xabs = xk - xl;
115 if (xabs < 0)
116 xabs = -xabs;
117 if (xabs == 0)
118 return FixOne;
119 yabs = yk - yl;
120 if (yabs < 0)
121 yabs = -yabs;
122 if (yabs == 0)
123 return 0;
124 acfixtopflt(xabs, &rx);
125 acfixtopflt(yabs, &ry);
126 q = (float)(rx * rx) / (gTheta * ry); /* DEBUG 8 BIT. Used to by
127 2*(rx*rx)/(theta*ry). Don't need
128 thsi with the 8 bits of Fixed
129 fraction. */
130 return HVness(&q);
131 }
132
133 Fixed
HorzQuo(Fixed xk,Fixed yk,Fixed xl,Fixed yl)134 HorzQuo(Fixed xk, Fixed yk, Fixed xl, Fixed yl)
135 {
136 Fixed xabs, yabs;
137 float rx, ry, q;
138 yabs = yk - yl;
139 if (yabs < 0)
140 yabs = -yabs;
141 if (yabs == 0)
142 return FixOne;
143 xabs = xk - xl;
144 if (xabs < 0)
145 xabs = -xabs;
146 if (xabs == 0)
147 return 0;
148 acfixtopflt(xabs, &rx);
149 acfixtopflt(yabs, &ry);
150 q = (float)(ry * ry) / (gTheta * rx); /* DEBUG 8 BIT. Used to by
151 2*(ry*ry)/(theta*ry). Don't need
152 thsi with the 8 bits of Fixed
153 fraction. */
154 return HVness(&q);
155 }
156
157 bool
IsTiny(PathElt * e)158 IsTiny(PathElt* e)
159 {
160 Fixed x0 = 0, y0 = 0, x1 = 0, y1 = 0;
161 GetEndPoints(e, &x0, &y0, &x1, &y1);
162 return ((abs(x0 - x1) < FixTwo) && (abs(y0 - y1) < FixTwo)) ? true : false;
163 }
164
165 bool
IsShort(PathElt * e)166 IsShort(PathElt* e)
167 {
168 Fixed x0 = 0, y0 = 0, x1 = 0, y1 = 0, dx = 0, dy = 0, mn = 0, mx = 0;
169 GetEndPoints(e, &x0, &y0, &x1, &y1);
170 dx = abs(x0 - x1);
171 dy = abs(y0 - y1);
172 if (dx > dy) {
173 mn = dy;
174 mx = dx;
175 } else {
176 mn = dx;
177 mx = dy;
178 }
179 return ((mx + (mn * 42) / 125) < FixInt(6))
180 ? true
181 : false; /* DEBUG 8 BIT. Increased threshold from 3 to 6, for
182 change in coordinare system. */
183 }
184
185 PathElt*
NxtForBend(PathElt * p,Fixed * px2,Fixed * py2,Fixed * px3,Fixed * py3)186 NxtForBend(PathElt* p, Fixed* px2, Fixed* py2, Fixed* px3, Fixed* py3)
187 {
188 PathElt *nxt, *nxtMT = NULL;
189 Fixed x = 0, y = 0;
190 nxt = p;
191 GetEndPoint(p, &x, &y);
192 while (true) {
193 if (nxt->type == CLOSEPATH) {
194 nxt = GetDest(nxt);
195 /* The following test was added to prevent an infinite loop. */
196 if (nxtMT != NULL && nxtMT == nxt) {
197 ReportPossibleLoop(p);
198 nxt = NULL;
199 } else {
200 nxtMT = nxt;
201 nxt = nxt->next;
202 }
203 } else
204 nxt = nxt->next;
205 if (nxt == NULL) { /* forget it */
206 *px2 = *py2 = *px3 = *py3 = -FixInt(9999);
207 return nxt;
208 }
209 if (!IsTiny(nxt))
210 break;
211 }
212 if (nxt->type == CURVETO) {
213 Fixed x2 = nxt->x1;
214 Fixed y2 = nxt->y1;
215 if (x2 == x && y2 == y) {
216 x2 = nxt->x2;
217 y2 = nxt->y2;
218 }
219 *px2 = x2;
220 *py2 = y2;
221 } else
222 GetEndPoint(nxt, px2, py2);
223 GetEndPoint(nxt, px3, py3);
224 return nxt;
225 }
226
227 PathElt*
PrvForBend(PathElt * p,Fixed * px2,Fixed * py2)228 PrvForBend(PathElt* p, Fixed* px2, Fixed* py2)
229 {
230 PathElt *prv, *prvCP = NULL;
231 Fixed x2, y2;
232 prv = p;
233 while (true) {
234 prv = prv->prev;
235 if (prv == NULL)
236 goto Bogus;
237 if (prv->type == MOVETO) {
238 prv = GetClosedBy(prv);
239 /* The following test was added to prevent an infinite loop. */
240 if (prv == NULL || (prvCP != NULL && prvCP == prv))
241 goto Bogus;
242 prvCP = prv;
243 }
244 if (!IsTiny(prv))
245 break;
246 }
247 if (prv->type == CURVETO) {
248 x2 = prv->x2;
249 y2 = prv->y2;
250 if (x2 == prv->x3 && y2 == prv->y3) {
251 x2 = prv->x1;
252 y2 = prv->y1;
253 }
254 *px2 = x2;
255 *py2 = y2;
256 } else {
257 p = prv->prev;
258 if (p == NULL)
259 goto Bogus;
260 GetEndPoint(p, px2, py2);
261 }
262 return prv;
263 Bogus:
264 *px2 = *py2 = -FixInt(9999);
265 return prv;
266 }
267
268 static bool
CheckHeight(bool upperFlag,PathElt * p)269 CheckHeight(bool upperFlag, PathElt* p)
270 {
271 PathElt* ee;
272 Fixed y, yy;
273 ee = gPathStart;
274 y = -p->y;
275 while (ee != NULL) {
276 if (ee->type == MOVETO && ee != p) {
277 yy = -ee->y;
278 if ((upperFlag && yy > y) || (!upperFlag && yy < y))
279 return false;
280 }
281 ee = ee->next;
282 }
283 return true;
284 }
285
286 bool
IsLower(PathElt * p)287 IsLower(PathElt* p)
288 {
289 return CheckHeight(false, p);
290 }
291
292 bool
IsUpper(PathElt * p)293 IsUpper(PathElt* p)
294 {
295 return CheckHeight(true, p);
296 }
297