|
|
1.1 root 1: /*
2: * UserPath.m by Bruce Blumberg, NeXT Computer, Inc.
3: *
4: * You may freely copy,distribute and re-use the code in this example. NeXT
5: * disclaims any warranty of any kind, expressed or implied, as to its fitness
6: * for any particular purpose
7: *
8: */
9:
10: #import "UserPath.h"
11: #import <mach/mach_init.h>
12: #import <appkit/graphics.h>
13: #import <appkit/errors.h>
14: #import <math.h>
15: #import <libc.h>
16:
17: static NXZone *upZone = NULL;
18:
19: NXZone *userPathZone()
20: /* Creates a unique zone for use by all user paths */
21: {
22: if (!upZone) {
23: upZone = NXCreateZone(vm_page_size, vm_page_size, 1);
24: }
25:
26: return upZone;
27: }
28:
29: UserPath *newUserPath()
30: /* Creates a new User Path in the zone returned by userPathZone */
31: {
32: UserPath *up;
33:
34: up = (UserPath *)NXZoneMalloc(userPathZone(), sizeof(UserPath));
35: up->max = 32;
36: up->points = (float *)NXZoneMalloc(userPathZone(),
37: sizeof(float) * up->max);
38: up->ops = (char *)NXZoneMalloc(userPathZone(),
39: (2 + (up->max / 2)) * sizeof(char));
40: up->ping = NO;
41:
42: return up;
43: }
44:
45: void freeUserPath(UserPath *up)
46: /* Frees User Path and its associated buffers */
47: {
48: free(up->points);
49: free(up->ops);
50: free(up);
51:
52: return;
53: }
54:
55: void growUserPath(UserPath *up)
56: /*
57: * grows the associated buffers as necessary. buffer size doubles on each
58: * call. You never need to call grow directly as it is called as needed by the
59: * methods and functions which add elements into the buffer
60: */
61: {
62: /* double the size of the internal buffers */
63: up->max *= 2;
64: up->points = (float *)NXZoneRealloc(userPathZone(), up->points,
65: sizeof(float) * up->max);
66: up->ops = (char *)NXZoneRealloc(userPathZone(), up->ops,
67: (2 + (up->max / 2)) * sizeof(char));
68:
69: return;
70: }
71:
72: void beginUserPath(UserPath *up, BOOL cache)
73: /*
74: * Call this to start generating a user path. The cache argument specifies if
75: * you want the user path cached at the server (i.e. dps_ucache). In either
76: * case, the UserPath object will automatically calculate the bounding box for
77: * the path and add the dps_setbbox operator.
78: */
79: {
80: up->numberOfPoints = up->numberOfOps = 0;
81: up->cp.x = up->cp.y = 0;
82: up->bbox[0] = up->bbox[1] = 1.0e6;
83: up->bbox[2] = up->bbox[3] = -1.0e6;
84: if (cache) {
85: up->ops[up->numberOfOps++] = dps_ucache;
86: }
87: up->ops[up->numberOfOps++] = dps_setbbox;
88: up->opForUserPath = 0;
89:
90: return;
91: }
92:
93: void endUserPath(UserPath *up, int op)
94: /*
95: * Call this to stop filling the path. Note this does not send the userpath to
96: * the server -- use sendUserPath. The op argument should be one of the
97: * following:
98: * dps_uappend, dps_ufill ,dps_ueofill, dps_ustroke, dps_ustrokepath,
99: * dps_inufill, dps_inueofill, dps_inustroke, dps_def, dps_put.
100: * These are defined in <dpsclient/dpsNext.h.
101: */
102: {
103: up->opForUserPath = op;
104:
105: return;
106: }
107:
108:
109: void UPdebug(UserPath *up, BOOL shouldPing)
110: /*
111: * Sets ping to YES so that after each time a user path is sent down to the
112: * window server, an NXPing() is sent after. The purpose is to catch PostScript
113: * errors that may be generated by the user path. sendUserPath brackets the
114: * download and the NXPing() in an NX_DURING... NX_HANDLER construct. Normally
115: * ping is NO.
116: */
117: {
118: up->ping = shouldPing;
119:
120: return;
121: }
122:
123: int sendUserPath(UserPath *up)
124: /*
125: * Call this to send the path down to the server. If ping==YES (set via
126: * debug:), the function will send an NXPing() after the Path. In any event,
127: * code is bracketed by a NX_DURING ... NX_HANDLER construct which will try to
128: * catch postscript errors. If ping==NO (the default) it is unlikely to catch
129: * errors, with ping==YES it will. Whether you can recover or not is another
130: * matter. sendUserPath returns 0 on success and -1 on failure. If no previous
131: * endUserPath: has been sent, will return -2 and will not send the path to the
132: * server.
133: */
134: {
135: NXHandler exception;
136:
137: exception.code = 0;
138: if (up->opForUserPath != 0) {
139: NX_DURING
140: DPSDoUserPath(up->points, up->numberOfPoints, dps_float, up->ops,
141: up->numberOfOps, up->bbox, up->opForUserPath);
142: if (up->ping) {
143: NXPing();
144: }
145:
146: NX_HANDLER
147: exception = NXLocalHandler;
148: NX_ENDHANDLER
149: if (exception.code) {
150: NXReportError(&exception);
151: if (exception.code == dps_err_ps) {
152: return -1;
153: }
154: } else {
155: return 0;
156: }
157: }
158:
159: return -1;
160: }
161:
162: void checkBoundingBox(UserPath *up, float x, float y)
163: /* Checks if bounding box needs to be enlarged based on x and y */
164: {
165: if (x < up->bbox[0]) {
166: up->bbox[0] = x;
167: }
168: if (y < up->bbox[1]) {
169: up->bbox[1] = y;
170: }
171: if (x > up->bbox[2]) {
172: up->bbox[2] = x;
173: }
174: if (y > up->bbox[3]) {
175: up->bbox[3] = y;
176: }
177:
178: return;
179: }
180:
181: void addPts(UserPath *up, float x, float y)
182: /* adds x and y to user path. Updates bounding box as necessary */
183: {
184: if (!((up->numberOfPoints + 2) < up->max)) {
185: growUserPath(up);
186: }
187:
188: up->points[up->numberOfPoints++] = x;
189: up->points[up->numberOfPoints++] = y;
190: checkBoundingBox(up, x, y);
191:
192: return;
193: }
194:
195: void addOp(UserPath *up, int op)
196: /*
197: * adds operator to user path. Operator should be one of the following:
198: * dps_moveto, dps_rmoveto, dps_lineto, dps_rlineto, dps_curveto,
199: * dps_rcurveto, dps_arc, dps_arcn, dps_arct, dps_closepath.
200: */
201: {
202: up->ops[up->numberOfOps++] = op;
203:
204: return;
205: }
206:
207: void add(UserPath *up, int op, float x, float y)
208: /*
209: * adds operator and x and y to user path. Operator should be one of the
210: * operators above
211: */
212: {
213: if (!((up->numberOfPoints + 2) < up->max)) {
214: growUserPath(up);
215: }
216:
217: up->ops[up->numberOfOps++] = op;
218: up->points[up->numberOfPoints++] = x;
219: up->points[up->numberOfPoints++] = y;
220: checkBoundingBox(up, x, y);
221:
222: return;
223: }
224:
225: void UPmoveto(UserPath *up, float x, float y)
226: /* adds <x y moveto> to user path and updates bounding box */
227: {
228: add(up, dps_moveto, x, y);
229: up->cp.x = x;
230: up->cp.y = y;
231:
232: return;
233: }
234:
235: void UPrmoveto(UserPath *up, float x, float y)
236: /* adds <x y rmoveto> to user path and updates bounding box */
237: {
238: if (!((up->numberOfPoints + 2) < up->max)) {
239: growUserPath(up);
240: }
241: up->ops[up->numberOfOps++] = dps_rmoveto;
242: up->points[up->numberOfPoints++] = x;
243: up->points[up->numberOfPoints++] = y;
244: up->cp.x += x;
245: up->cp.y += y;
246: checkBoundingBox(up, up->cp.x, up->cp.y);
247:
248: return;
249: }
250:
251: void UPlineto(UserPath *up, float x, float y)
252: /* adds <x y lineto> to user path and updates bounding box */
253: {
254: add(up, dps_lineto, x, y);
255: up->cp.x = x;
256: up->cp.y = y;
257:
258: return;
259: }
260:
261: void UPrlineto(UserPath *up, float x, float y)
262: /* adds <x y rlineto> to user path and updates bounding box */
263: {
264: if (!((up->numberOfPoints + 2) < up->max)) {
265: growUserPath(up);
266: }
267: up->ops[up->numberOfOps++] = dps_rlineto;
268: up->points[up->numberOfPoints++] = x;
269: up->points[up->numberOfPoints++] = y;
270: up->cp.x += x;
271: up->cp.y += y;
272: checkBoundingBox(up, up->cp.x, up->cp.y);
273:
274: return;
275: }
276:
277: void UPcurveto(UserPath *up, float x1, float y1, float x2, float y2, float x3,
278: float y3)
279: /* adds <x1 y1 x2 y2 curveto> to user path and updates bounding box */
280: {
281: addPts(up, x1, y1);
282: addPts(up, x2, y2);
283: add(up, dps_curveto, x3, y3);
284: up->cp.x = x3;
285: up->cp.y = y3;
286:
287: return;
288: }
289:
290: void UPrcurveto(UserPath *up, float dx1, float dy1, float dx2, float dy2,
291: float dx3, float dy3)
292: /* adds <x1 y1 x2 y2 rcurveto> to user path and updates bounding box */
293: {
294: if (!((up->numberOfPoints + 6) < up->max)) {
295: growUserPath(up);
296: }
297: up->ops[up->numberOfOps++] = dps_rcurveto;
298: up->points[up->numberOfPoints++] = dx1;
299: up->points[up->numberOfPoints++] = dy1;
300: up->points[up->numberOfPoints++] = dx2;
301: up->points[up->numberOfPoints++] = dy2;
302: up->points[up->numberOfPoints++] = dx3;
303: up->points[up->numberOfPoints++] = dy3;
304: checkBoundingBox(up, up->cp.x + dx1, up->cp.y + dy1);
305: checkBoundingBox(up, up->cp.x + dx2, up->cp.y + dy2);
306: checkBoundingBox(up, up->cp.x + dx3, up->cp.y + dy3);
307: up->cp.x = dx3;
308: up->cp.y = dy3;
309:
310: return;
311: }
312:
313: void UParc(UserPath *up, float x, float y, float r, float ang1, float ang2)
314: /* adds <x y r ang1 ang2 arc> to user path and updates bounding box */
315: {
316: if (!((up->numberOfPoints + 5) < up->max)) {
317: growUserPath(up);
318: }
319: up->ops[up->numberOfOps++] = dps_arc;
320: up->points[up->numberOfPoints++] = x;
321: up->points[up->numberOfPoints++] = y;
322: up->points[up->numberOfPoints++] = r;
323: up->points[up->numberOfPoints++] = ang1;
324: up->points[up->numberOfPoints++] = ang2;
325: checkBoundingBox(up, x + r, y + r);
326: checkBoundingBox(up, x - r, y - r);
327: up->cp.x = x + cos(ang2 / 57.3) * r;
328: up->cp.y = y + sin(ang2 / 57.3) * r;
329:
330: return;
331: }
332:
333: void UParcn(UserPath *up, float x, float y, float r, float ang1, float ang2)
334: /* adds <x y r ang1 ang2 arcn> to user path and updates bounding box */
335: {
336: if (!((up->numberOfPoints + 5) < up->max)) {
337: growUserPath(up);
338: }
339: up->ops[up->numberOfOps++] = dps_arcn;
340: up->points[up->numberOfPoints++] = x;
341: up->points[up->numberOfPoints++] = y;
342: up->points[up->numberOfPoints++] = r;
343: up->points[up->numberOfPoints++] = ang1;
344: up->points[up->numberOfPoints++] = ang2;
345: checkBoundingBox(up, x + r, y + r);
346: checkBoundingBox(up, x - r, y - r);
347: up->cp.x = x + cos(ang2 / 57.3) * r;
348: up->cp.y = y + sin(ang2 / 57.3) * r;
349:
350: return;
351: }
352:
353: void UParct(UserPath *up, float x1, float y1, float x2, float y2, float r)
354: /* adds <x1 y1 x2 y2 r arct> to user path and updates bounding box */
355: {
356: if (!((up->numberOfPoints + 5) < up->max)) {
357: growUserPath(up);
358: }
359: up->ops[up->numberOfOps++] = dps_arcn;
360: up->points[up->numberOfPoints++] = x1;
361: up->points[up->numberOfPoints++] = y1;
362: up->points[up->numberOfPoints++] = x2;
363: up->points[up->numberOfPoints++] = y2;
364: up->points[up->numberOfPoints++] = r;
365: checkBoundingBox(up, x1, y1);
366: checkBoundingBox(up, x2, y2);
367: up->cp.x = x2;
368: up->cp.y = y2;
369:
370: return;
371: }
372:
373: void closePath(UserPath *up)
374: /* adds <closepath> to user path and updates bounding box */
375: {
376: up->ops[up->numberOfOps++] = dps_closepath;
377:
378: return;
379: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.