1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 /* 41 * 42 * Drawing routines used by dpost. Almost no real work is done here. Instead 43 * the required calculations are done in special Postscript procedures that 44 * include: 45 * 46 * 47 * Dl 48 * 49 * x1 y1 x y Dl - 50 * 51 * Starts a new path and then draws a line from the current point 52 * (x, y) to (x1, y1). 53 * 54 * De 55 * 56 * x y a b De - 57 * 58 * Starts a new path and then draws an ellipse that has its left side 59 * at the current point (x, y) and horizontal and vertical axes lengths 60 * given by a and b respectively. 61 * 62 * Da 63 * 64 * x y dx1 dy1 dx2 dy2 Da - 65 * 66 * Starts a new segment and then draws a circular arc from the current 67 * point (x, y) to (x + dx1 + dx2, y + dy1 + dy2). The center of the 68 * circle is at (x + dx1, y + dy1). Arcs always go counter-clockwise 69 * from the starting point to the end point. 70 * 71 * DA 72 * 73 * x y dx1 dy1 dx2 dy2 DA - 74 * 75 * Draws a clockwise arc from (x, y) to (x + dx1 + dx2, y + dy1 + dy2) 76 * with center at (x + dx1, y + dy1). Only needed when we're building 77 * large paths that use arcs and want to control the current point. The 78 * arguments passed to drawarc() will be whatever they would have been 79 * for a counter-clockwise arc, so we need to map them into appropriate 80 * arguments for PostScript's arcn operator. The mapping is, 81 * 82 * x = hpos + dx1' + dx2' 83 * y = vpos + dy1' + dy2' 84 * dx1 = -dx2' 85 * dy1 = -dy2' 86 * dx2 = -dx1' 87 * dy2 = -dy1' 88 * 89 * where primed values represent the drawarc() arguments and (hpos, vpos) 90 * is our current position. 91 * 92 * Ds 93 * 94 * x0 y0 x1 y1 x2 y2 Ds - 95 * 96 * Starts a new segment and then draws a quadratic spline connecting 97 * point ((x0 + x1)/2, (y0 + y1)/2) to ((x1 + x2)/2, (y1 + y2)/2). 98 * The points used in Postscript's curveto procedure are given by, 99 * 100 * x0' = (x0 + 5 * x1) / 6 101 * x1' = (x2 + 5 * x1) / 6 102 * x2' = (x1 + x2) / 2 103 * 104 * with similar equations for the y coordinates. 105 * 106 * By default all the PostScript drawing procedures begin with a newpath (just to 107 * be safe) and end with a stroke, which essentially isolates the path elements 108 * built by the drawing procedures. In order to accommodate big paths built from 109 * smaller pieces each of the PostScript drawing procedures can forced to retain 110 * the path that's being built. That's what happens in beginpath() when an "x X 111 * BeginPath" command is read. beginpath() sets the PostScript variable inpath to 112 * true, and that essentially eliminates the newpath/stroke pair that bracket the 113 * individual pieces. In that case the path is terminated and drawn when dpost 114 * reads an "x X DrawPath" command. 115 * 116 * Early versions of dpost included the PostScript drawing procedures as part of 117 * the prologue, and as a result they were included with every job, even if they 118 * were never used. This version has separated the drawing procedures from the 119 * default prologue (they're now in *drawfile) and only includes them if they're 120 * really needed, which is yet another convenient violation of page independence. 121 * Routine getdraw() is responsible for adding *drawfile to the output file, and 122 * if it can't read *drawfile it continues on as if nothing happened. That means 123 * everything should still work if you append *drawfile to *prologue and then 124 * delete *drawfile. 125 * 126 */ 127 128 129 #include <stdio.h> 130 #include <math.h> 131 132 #include "gen.h" /* general purpose definitions */ 133 #include "ext.h" /* external variable definitions */ 134 135 136 int gotdraw = FALSE; /* TRUE when *drawfile has been added */ 137 int gotbaseline = FALSE; /* TRUE after *baselinefile is added */ 138 int inpath = FALSE; /* TRUE if we're putting pieces together */ 139 140 141 /* 142 * 143 * All these should be defined in file dpost.c. 144 * 145 */ 146 147 148 extern int hpos; 149 extern int vpos; 150 extern int encoding; 151 extern int maxencoding; 152 extern int realencoding; 153 154 extern char *drawfile; 155 extern char *baselinefile; 156 extern FILE *tf; 157 158 void drawcirc(int); 159 void drawellip(int, int); 160 static void parsebuf(char *); 161 162 /*****************************************************************************/ 163 164 165 void 166 getdraw(void) 167 { 168 169 170 /* 171 * 172 * Responsible for making sure the PostScript drawing procedures are downloaded 173 * from *drawfile. Stuff is done at most once per job, and only if the job needs 174 * them. For now I've decided not to quit if we can't read the drawing file. That 175 * pretty much assumes an old version of prologue is being used that includes all 176 * the drawing procedures. 177 * 178 */ 179 180 181 if ( gotdraw == FALSE && access(drawfile, 04) == 0 ) 182 doglobal(drawfile); 183 184 if ( tf == stdout ) 185 gotdraw = TRUE; 186 187 } /* End of getdraw */ 188 189 190 /*****************************************************************************/ 191 192 193 void 194 drawline(int dx, int dy) 195 /* endpoint is (hpos+dx, vpos+dy) */ 196 { 197 198 /* 199 * 200 * Draws a line from (hpos, vpos) to (hpos+dx, vpos+dy), and leaves the current 201 * position at the endpoint. 202 * 203 */ 204 205 206 if ( dx == 0 && dy == 0 ) 207 drawcirc(1); 208 else fprintf(tf, "%d %d %d %d Dl\n", hpos + dx, vpos + dy, hpos, vpos); 209 210 hgoto(hpos+dx); /* where troff expects to be */ 211 vgoto(vpos+dy); 212 213 resetpos(); /* not sure where the printer is */ 214 215 } /* End of drawline */ 216 217 218 /*****************************************************************************/ 219 220 221 void 222 drawcirc(int d) 223 /* diameter of the circle */ 224 { 225 226 /* 227 * 228 * Draws a circle of diameter d with the left 'side' of the circle at the 229 * current point. After we're finished drawing we move the current position 230 * to the right side. 231 * 232 */ 233 234 drawellip(d, d); 235 236 } /* End of drawcirc */ 237 238 239 /*****************************************************************************/ 240 241 242 void 243 drawellip(int a, int b) 244 /* axes lengths for the ellipse */ 245 { 246 247 /* 248 * 249 * Draws an ellipse having axes lengths horizontally and vertically of a and 250 * b. The left side of the ellipse is at the current point. After we're done 251 * drawing the path we move the current position to the right side. 252 * 253 */ 254 255 256 if ( a == 0 && b == 0 ) 257 return; 258 259 fprintf(tf, "%d %d %d %d De\n", hpos, vpos, a, b); 260 261 hgoto(hpos + a); /* where troff expects to be */ 262 vgoto(vpos); 263 264 resetpos(); /* not sure where the printer is */ 265 266 } /* End of drawellip */ 267 268 269 /*****************************************************************************/ 270 271 272 void 273 drawarc(int dx1, int dy1, int dx2, int dy2, int c) 274 /* dx1, dy1 - vector from current pos to center */ 275 /* dx2, dy2 - from center to end of the arc */ 276 /* c - clockwise if c is A */ 277 { 278 279 /* 280 * 281 * If c isn't set to 'A' a counter-clockwise arc is drawn from the current point 282 * (hpos, vpos) to (hpos+dx1+dx2, vpos+dy1+dy2). The center of the circle is the 283 * point (hpos+dx1, vpos+dy1). If c is 'A' the arc goes clockwise from the point 284 * (hpos+dx1+dx2, vpos+dy1+dy2) to (hpos, vpos). Clockwise arcs are only needed 285 * if we're building a larger path out of pieces that include arcs, and want to 286 * have PostScript manage the path for us. Arguments (for a clockwise arc) are 287 * what would have been supplied if the arc was drawn in a counter-clockwise 288 * direction, and are converted to values suitable for use with PostScript's arcn 289 * operator. 290 * 291 */ 292 293 294 if ( (dx1 != 0 || dy1 != 0) && (dx2 != 0 || dy2 != 0) ) 295 if ( c != 'A' ) 296 fprintf(tf, "%d %d %d %d %d %d Da\n", hpos, vpos, dx1, dy1, dx2, dy2); 297 else fprintf(tf, "%d %d %d %d %d %d DA\n", hpos+dx1+dx2, vpos+dy1+dy2, 298 -dx2, -dy2, -dx1, -dy1); 299 300 hgoto(hpos + dx1 + dx2); /* where troff expects to be */ 301 vgoto(vpos + dy1 + dy2); 302 303 resetpos(); /* not sure where the printer is */ 304 305 } /* End of drawarc */ 306 307 308 /*****************************************************************************/ 309 310 311 void 312 drawspline(FILE *fp, int flag) 313 /* fp - input for point list */ 314 /* flag - flag!=1 connect end points */ 315 { 316 317 318 int x[100], y[100]; 319 int i, N; 320 321 322 /* 323 * 324 * Spline drawing routine for Postscript printers. The complicated stuff is 325 * handled by procedure Ds, which should be defined in the library file. I've 326 * seen wrong implementations of troff's spline drawing, so fo the record I'll 327 * write down the parametric equations and the necessary conversions to Bezier 328 * cubic splines (as used in Postscript). 329 * 330 * 331 * Parametric equation (x coordinate only): 332 * 333 * 334 * (x2 - 2 * x1 + x0) 2 (x0 + x1) 335 * x = ------------------ * t + (x1 - x0) * t + --------- 336 * 2 2 337 * 338 * 339 * The coefficients in the Bezier cubic are, 340 * 341 * 342 * A = 0 343 * B = (x2 - 2 * x1 + x0) / 2 344 * C = x1 - x0 345 * 346 * 347 * while the current point is, 348 * 349 * current-point = (x0 + x1) / 2 350 * 351 * Using the relationships given in the Postscript manual (page 121) it's easy to 352 * see that the control points are given by, 353 * 354 * 355 * x0' = (x0 + 5 * x1) / 6 356 * x1' = (x2 + 5 * x1) / 6 357 * x2' = (x1 + x2) / 2 358 * 359 * 360 * where the primed variables are the ones used by curveto. The calculations 361 * shown above are done in procedure Ds using the coordinates set up in both 362 * the x[] and y[] arrays. 363 * 364 * A simple test of whether your spline drawing is correct would be to use cip 365 * to draw a spline and some tangent lines at appropriate points and then print 366 * the file. 367 * 368 */ 369 370 371 for ( N = 2; N < sizeof(x)/sizeof(x[0]); N++ ) 372 if (fscanf(fp, "%d %d", &x[N], &y[N]) != 2) 373 break; 374 375 x[0] = x[1] = hpos; 376 y[0] = y[1] = vpos; 377 378 for (i = 1; i < N; i++) { 379 x[i+1] += x[i]; 380 y[i+1] += y[i]; 381 } /* End for */ 382 383 x[N] = x[N-1]; 384 y[N] = y[N-1]; 385 386 for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++) 387 fprintf(tf, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]); 388 389 hgoto(x[N]); /* where troff expects to be */ 390 vgoto(y[N]); 391 392 resetpos(); /* not sure where the printer is */ 393 394 } /* End of drawspline */ 395 396 397 /*****************************************************************************/ 398 399 400 void 401 beginpath(char *buf, int copy) 402 /* buf - whatever followed "x X BeginPath" */ 403 /* copy - ignore *buf if FALSE */ 404 { 405 406 /* 407 * 408 * Called from devcntrl() whenever an "x X BeginPath" command is read. It's used 409 * to mark the start of a sequence of drawing commands that should be grouped 410 * together and treated as a single path. By default the drawing procedures in 411 * *drawfile treat each drawing command as a separate object, and usually start 412 * with a newpath (just as a precaution) and end with a stroke. The newpath and 413 * stroke isolate individual drawing commands and make it impossible to deal with 414 * composite objects. "x X BeginPath" can be used to mark the start of drawing 415 * commands that should be grouped together and treated as a single object, and 416 * part of what's done here ensures that the PostScript drawing commands defined 417 * in *drawfile skip the newpath and stroke, until after the next "x X DrawPath" 418 * command. At that point the path that's been built up can be manipulated in 419 * various ways (eg. filled and/or stroked with a different line width). 420 * 421 * String *buf is unnecessary and is only included for compatibility with an early 422 * verion of that's still in use. In that version "x X BeginObject" marked the 423 * start of a graphical object, and whatever followed it was passed along in *buf 424 * and copied to the output file. Color selection is one of the options that's 425 * available in parsebuf(), so if we get here we add *colorfile to the output 426 * file before doing anything important. 427 * 428 */ 429 430 431 432 if ( inpath == FALSE ) { 433 endtext(); 434 getdraw(); 435 getcolor(); 436 fprintf(tf, "gsave\n"); 437 fprintf(tf, "newpath\n"); 438 fprintf(tf, "%d %d m\n", hpos, vpos); 439 fprintf(tf, "/inpath true def\n"); 440 if ( copy == TRUE ) 441 fprintf(tf, "%s", buf); 442 inpath = TRUE; 443 } /* End if */ 444 445 } /* End of beginpath */ 446 447 448 /*****************************************************************************/ 449 450 451 void 452 drawpath(char *buf, int copy) 453 { 454 455 /* 456 * 457 * Called from devcntrl() whenever an "x X DrawPath" command is read. It marks the 458 * end of the path started by the last "x X BeginPath" command and uses whatever 459 * has been passed along in *buf to manipulate the path (eg. fill and/or stroke 460 * the path). Once that's been done the drawing procedures are restored to their 461 * default behavior in which each drawing command is treated as an isolated path. 462 * The new version (called after "x X DrawPath") has copy set to FALSE, and calls 463 * parsebuf() to figure out what goes in the output file. It's a feeble attempt 464 * to free users and preprocessors (like pic) from having to know PostScript. The 465 * comments in parsebuf() describe what's handled. 466 * 467 * In the early version a path was started with "x X BeginObject" and ended with 468 * "x X EndObject". In both cases *buf was just copied to the output file, and 469 * was expected to be legitimate PostScript that manipulated the current path. 470 * The old escape sequence will be supported for a while (for Ravi), and always 471 * call this routine with copy set to TRUE. 472 * 473 * 474 */ 475 476 477 if ( inpath == TRUE ) { 478 if ( copy == TRUE ) 479 fprintf(tf, "%s", buf); 480 else parsebuf(buf); 481 fprintf(tf, "grestore\n"); 482 fprintf(tf, "/inpath false def\n"); 483 reset(); 484 inpath = FALSE; 485 } /* End if */ 486 487 } /* End of drawpath */ 488 489 490 /*****************************************************************************/ 491 492 493 static void 494 parsebuf(char *buf) 495 /* whatever followed "x X DrawPath" */ 496 { 497 char *p; /* usually the next token */ 498 char *p1; /* for grabbing arguments */ 499 char *pend; /* end of the original string (ie. *buf) */ 500 int gsavelevel = 0; /* non-zero if we've done a gsave */ 501 502 /* 503 * 504 * Simple minded attempt at parsing the string that followed an "x X DrawPath" 505 * command. Everything not recognized here is simply ignored - there's absolutely 506 * no error checking and what was originally in buf is clobbered by strtok(). 507 * A typical *buf might look like, 508 * 509 * gray .9 fill stroke 510 * 511 * to fill the current path with a gray level of .9 and follow that by stroking the 512 * outline of the path. Since unrecognized tokens are ignored the last example 513 * could also be written as, 514 * 515 * with gray .9 fill then stroke 516 * 517 * The "with" and "then" strings aren't recognized tokens and are simply discarded. 518 * The "stroke", "fill", and "wfill" force out appropriate PostScript code and are 519 * followed by a grestore. In otherwords changes to the grahics state (eg. a gray 520 * level or color) are reset to default values immediately after the stroke, fill, 521 * or wfill tokens. For now "fill" gets invokes PostScript's eofill operator and 522 * "wfill" calls fill (ie. the operator that uses the non-zero winding rule). 523 * 524 * The tokens that cause temporary changes to the graphics state are "gray" (for 525 * setting the gray level), "color" (for selecting a known color from the colordict 526 * dictionary defined in *colorfile), and "line" (for setting the line width). All 527 * three tokens can be extended since strncmp() makes the comparison. For example 528 * the strings "line" and "linewidth" accomplish the same thing. Colors are named 529 * (eg. "red"), but must be appropriately defined in *colorfile. For now all three 530 * tokens must be followed immediately by their single argument. The gray level 531 * (ie. the argument that follows "gray") should be a number between 0 and 1, with 532 * 0 for black and 1 for white. 533 * 534 * To pass straight PostScript through enclose the appropriate commands in double 535 * quotes. Straight PostScript is only bracketed by the outermost gsave/grestore 536 * pair (ie. the one from the initial "x X BeginPath") although that's probably 537 * a mistake. Suspect I may have to change the double quote delimiters. 538 * 539 */ 540 541 542 pend = buf + strlen(buf); 543 p = strtok(buf, " \n"); 544 545 while ( p != NULL ) { 546 if ( gsavelevel == 0 ) { 547 fprintf(tf, "gsave\n"); 548 gsavelevel++; 549 } /* End if */ 550 if ( strcmp(p, "stroke") == 0 ) { 551 fprintf(tf, "closepath stroke\ngrestore\n"); 552 gsavelevel--; 553 } else if ( strcmp(p, "openstroke") == 0 ) { 554 fprintf(tf, "stroke\ngrestore\n"); 555 gsavelevel--; 556 } else if ( strcmp(p, "fill") == 0 ) { 557 fprintf(tf, "eofill\ngrestore\n"); 558 gsavelevel--; 559 } else if ( strcmp(p, "wfill") == 0 ) { 560 fprintf(tf, "fill\ngrestore\n"); 561 gsavelevel--; 562 } else if ( strcmp(p, "sfill") == 0 ) { 563 fprintf(tf, "eofill\ngrestore\ngsave\nstroke\ngrestore\n"); 564 gsavelevel--; 565 } else if ( strncmp(p, "gray", strlen("gray")) == 0 ) { 566 p1 = strtok(NULL, " \n"); 567 fprintf(tf, "%s setgray\n", p1); 568 } else if ( strncmp(p, "color", strlen("color")) == 0 ) { 569 p1 = strtok(NULL, " \n"); 570 fprintf(tf, "/%s setcolor\n", p1); 571 } else if ( strncmp(p, "line", strlen("line")) == 0 ) { 572 p1 = strtok(NULL, " \n"); 573 fprintf(tf, "%s resolution mul 2 div setlinewidth\n", p1); 574 } else if ( strncmp(p, "reverse", strlen("reverse")) == 0 ) 575 fprintf(tf, "reversepath\n"); 576 else if ( *p == '"' ) { 577 for ( ; gsavelevel > 0; gsavelevel-- ) 578 fprintf(tf, "grestore\n"); 579 if ( (p1 = p + strlen(p)) < pend ) 580 *p1 = ' '; 581 p = strtok(p, "\"\n"); 582 fprintf(tf, "%s\n", p); 583 } /* End else */ 584 p = strtok(NULL, " \n"); 585 } /* End while */ 586 587 for ( ; gsavelevel > 0; gsavelevel-- ) 588 fprintf(tf, "grestore\n"); 589 590 } /* End of parsebuf */ 591 592 593 /*****************************************************************************/ 594 595 static void 596 getbaseline(void) 597 { 598 599 /* 600 * 601 * Responsible for making sure the PostScript procedures needed for printing text 602 * along an arbitrary baseline are downloaded from *baselinefile. Done at most 603 * once per job, and only if the the stuff is really used. 604 * 605 */ 606 607 608 if ( gotbaseline == FALSE && access(baselinefile, 04) == 0 ) 609 doglobal(baselinefile); 610 611 if ( tf == stdout ) 612 gotbaseline = TRUE; 613 614 } /* End of getbaseline */ 615 616 617 /*****************************************************************************/ 618 619 620 void 621 newbaseline(char *buf) 622 /* whatever followed "x X NewBaseline" */ 623 { 624 char *p; /* for eliminating white space etc. */ 625 626 627 /* 628 * 629 * Called from devcntrl() whenever an "x X NewBaseline" command is recognized. We 630 * assume whatever is in *buf is a set of parametric equations that describe the 631 * new baseline. Equations for x(t), y(t), dx/dt, and dy/dt must be written in 632 * PostScript, bracketed by { and } characters, and supplied in exactly that order. 633 * In particular the equation for x must come first in *buf and it ends up as the 634 * last one on the stack, while the equation for dy/dt comes last (in *buf) and 635 * ends up on the top of the PostScript stack. For example if *buf is given by, 636 * 637 * {} {180 mul 3.1416 div cos} {pop 1} {180 mul 3.1416 div sin neg} 638 * 639 * text will be printed along the curve y = cos(x). 640 * 641 * Angles given in radians must be converted to degrees for the PostScript trig 642 * functions, and things are scaled so that 1 unit maps into 1 inch. In the last 643 * example the cosine curve that describes the baseline has an amplitude of 1 inch. 644 * As another example of this rather confusing syntax if *buf is, 645 * 646 * {} {} {pop 1} {pop 1} 647 * 648 * the baseline will be the 45 degree line y = x. 649 * 650 * When any of the four functions is used they're called with a single number on 651 * the stack that's equal to the current value of the parameter t. The coordinate 652 * system axes run parallel to the PostScript coordinate system that's currently 653 * being used. 654 * 655 */ 656 657 658 for ( p = buf; *p; p++ ) /* eliminate trailing '\n' */ 659 if ( *p == '\n' ) { 660 *p = '\0'; 661 break; 662 } /* End if */ 663 664 for ( p = buf; *p && (*p == ' ' || *p == ':'); p++ ) ; 665 666 if ( *p != '\0' ) { /* something's there */ 667 endtext(); 668 getbaseline(); 669 fprintf(tf, "mark resolution %s newbaseline\n", p); 670 t_sf(); 671 resetpos(); 672 } /* End if */ 673 674 } /* End of newbaseline */ 675 676 677 /*****************************************************************************/ 678 679 void 680 drawtext(char *buf) 681 /* whatever followed "x X DrawText */ 682 { 683 char *p; /* for eliminating white space etc. */ 684 685 686 /* 687 * 688 * Called from devcntrl() whenever an "x X DrawText command is recognized. *buf 689 * should contain three arguments in the following order. First comes the text we 690 * want to print along the current baseline. Right now the string should be given 691 * as a PostScript string using characters '(' and ')' as the delimiters. Next in 692 * *buf comes a justification mode that can be the words left, right, or center. 693 * Last comes a number that represents the starting value of the parameter t that's 694 * given as the argument to the parametric equations that describe the current 695 * baseline. For example if *buf is given by, 696 * 697 * (hello world) left .5 698 * 699 * hello world will be printed along the path described by the current baseline 700 * and left justified at whatever (x(.5), y(.5)) happens to be. Usually will be 701 * preceeded by an "x X NewBaseline" call that defines the current baseline. The 702 * origin of the coordinate system used by the parametric equations will be the 703 * current point. 704 * 705 */ 706 707 708 for ( p = buf; *p; p++ ) /* eliminate trailing '\n' */ 709 if ( *p == '\n' ) { 710 *p = '\0'; 711 break; 712 } /* End if */ 713 714 for ( p = buf; *p && (*p == ' ' || *p == ':'); p++ ) ; 715 716 if ( *p != '\0' ) { /* something's there */ 717 endtext(); 718 getbaseline(); 719 xymove(hpos, vpos); 720 fprintf(tf, "mark %s drawfunnytext\n", p); 721 resetpos(); 722 } /* End if */ 723 724 } /* End of drawtext */ 725 726 727 /*****************************************************************************/ 728 729 void 730 settext(char *buf) 731 { 732 char *p; 733 734 735 /* 736 * 737 * Does whatever is needed to ensure any text that follows will be set along the 738 * curve described by the PostScript procedures listed in *buf. If *buf doesn't 739 * contain anything useful (eg. just a newline) things are restored to whatever 740 * they originally were. Doesn't work well if we try to start in the middle of a 741 * line of text. 742 * 743 * The parametric equations needed are, 744 * 745 * x = f(t) 746 * y = g(t) 747 * dx/dt = f'(t) 748 * dy/dt = g'(t) 749 * 750 * and must be given as proper PostScript procedures. The equation for x must come 751 * first (ie. it ends up on the bottom of the stack) and the equation for dy/dt 752 * must be given last (ie. it ends up on top of the stack). For example if *buf 753 * is given by, 754 * 755 * {} {180 mul 3.1416 div cos} {pop 1} {180 mul 3.1416 div sin neg} 756 * 757 * text will be set along the curve y=cos(x). 758 * 759 */ 760 761 762 endtext(); 763 getbaseline(); 764 765 for ( p = buf; *p && *p == ' '; p++ ) ; 766 767 if ( *p && *p != '\n' ) { 768 encoding = maxencoding + 2; 769 fprintf(tf, "mark resolution %s newbaseline\n", buf); 770 } else encoding = realencoding; 771 772 fprintf(tf, "%d setdecoding\n", encoding); 773 resetpos(); 774 775 } /* End of settext */ 776