|
|
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.