w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

paths.c
Go to the documentation of this file.
1 /* $XConsortium: paths.c,v 1.4 91/10/10 11:18:40 rws Exp $ */
2 /* Copyright International Business Machines, Corp. 1991
3  * All Rights Reserved
4  * Copyright Lexmark International, Inc. 1991
5  * All Rights Reserved
6  *
7  * License to use, copy, modify, and distribute this software and its
8  * documentation for any purpose and without fee is hereby granted,
9  * provided that the above copyright notice appear in all copies and that
10  * both that copyright notice and this permission notice appear in
11  * supporting documentation, and that the name of IBM or Lexmark not be
12  * used in advertising or publicity pertaining to distribution of the
13  * software without specific, written prior permission.
14  *
15  * IBM AND LEXMARK PROVIDE THIS SOFTWARE "AS IS", WITHOUT ANY WARRANTIES OF
16  * ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO ANY
17  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
18  * AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE ENTIRE RISK AS TO THE
19  * QUALITY AND PERFORMANCE OF THE SOFTWARE, INCLUDING ANY DUTY TO SUPPORT
20  * OR MAINTAIN, BELONGS TO THE LICENSEE. SHOULD ANY PORTION OF THE
21  * SOFTWARE PROVE DEFECTIVE, THE LICENSEE (NOT IBM OR LEXMARK) ASSUMES THE
22  * ENTIRE COST OF ALL SERVICING, REPAIR AND CORRECTION. IN NO EVENT SHALL
23  * IBM OR LEXMARK BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
24  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
25  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
26  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
27  * THIS SOFTWARE.
28  */
29  /* PATHS CWEB V0021 ******** */
30 /*
31 :h1 id=paths.PATHS Module - Path Operator Handler
32 
33 This is the module that is responsible for building and transforming
34 path lists.
35 
36 &author. Jeffrey B. Lotspiech (lotspiech@almaden.ibm.com)
37 
38 
39 :h3.Include Files
40 
41 The included files are:
42 */
43 
44  /* after the system includes (dsr) */
45 #include "types.h"
46 #include "objects.h"
47 #include "spaces.h"
48 #include "paths.h"
49 #include "regions.h" /* understands about Union */
50 #include "fonts.h" /* understands about TEXTTYPEs */
51 #include "pictures.h" /* understands about handles */
52 #include "strokes.h" /* understands how to coerce stroke paths */
53 
54 static void UnClose(struct segment *);
55 
56 /*
57 :h3.Routines Available to the TYPE1IMAGER User
58 
59 The PATHS routines that are made available to the outside user are:
60 */
61 
62 /*SHARED LINE(S) ORIGINATED HERE*/
63 /*
64 :h3.Functions Provided to Other Modules
65 
66 The path routines that are made available to other TYPE1IMAGER modules
67 are defined here:
68 */
69 
70 /*SHARED LINE(S) ORIGINATED HERE*/
71 /*
72 NOTE: because of the casts put in the macros for Loc, ArcCA, Conic,
73 RoundConic, PathSegment, and JoinSegment, we cannot use the macro names
74 when the functions are actually defined. We have to use the unique
75 names with their unique first two characters. Thus, if anyone in the
76 future ever decided to change the first two characters, it would not be
77 enough just to change the macro (as it would for most other functions).
78 He would have to also change the function definition.
79 */
80 /*
81 :h3.Macros Provided to Other Modules
82 
83 The CONCAT macro is defined here and used in the STROKES module. See
84 :hdref refid=pathmac..
85 */
86 
87 /*SHARED LINE(S) ORIGINATED HERE*/
88 
89 /*
90 :h2.Path Segment Structures
91 
92 A path is represented as a linked list of the following structure:
93 */
94 
95 /*SHARED LINE(S) ORIGINATED HERE*/
96 /*
97 When 'link' is NULL, we are at the last segment in the path (surprise!).
98 
99 'last' is only non-NULL on the first segment of a path,
100 for all the other segments 'last' == NULL. We test for a non-NULL
101 'last' (ISPATHANCHOR predicate) when we are given an alleged path
102 to make sure the user is not trying to pull a fast one on us.
103 
104 A path may be a collection of disjoint paths. Every break in the
105 disjoint path is represented by a MOVETYPE segment.
106 
107 Closed paths are discussed in :hdref refid=close..
108 
109 :h3.CopyPath() - Physically Duplicating a Path
110 
111 This simple function illustrates moving through the path linked list.
112 Duplicating a segment just involves making a copy of it, except for
113 text, which has some auxilliary things involved. We don't feel
114 competent to duplicate text in this module, so we call someone who
115 knows how (in the FONTS module).
116 */
117 struct segment *CopyPath(
118  register struct segment *p0) /* path to duplicate */
119 {
120  register struct segment *p,*n,*last,*anchor;
121 
122  for (p = p0, anchor = NULL; p != NULL; p = p->link) {
123 
124  ARGCHECK((!ISPATHTYPE(p->type) || (p != p0 && p->last != NULL)),
125  "CopyPath: invalid segment", p, NULL, (0), struct segment *);
126 
127  if (p->type == TEXTTYPE)
128  n = (struct segment *) CopyText(p);
129  else
130  n = (struct segment *)Allocate(p->size, p, 0);
131  n->last = NULL;
132  if (anchor == NULL)
133  anchor = n;
134  else
135  last->link = n;
136  last = n;
137  }
138 /*
139 At this point we have a chain of newly allocated segments hanging off
140 'anchor'. We need to make sure the first segment points to the last:
141 */
142  if (anchor != NULL) {
143  n->link = NULL;
144  anchor->last = n;
145  }
146 
147  return(anchor);
148 }
149 /*
150 :h3.KillPath() - Destroying a Path
151 
152 Destroying a path is simply a matter of freeing each segment in the
153 linked list. Again, we let the experts handle text.
154 */
155 void KillPath(
156  register struct segment *p) /* path to destroy */
157 {
158  register struct segment *linkp; /* temp register holding next segment*/
159 
160  /* return conditional based on reference count 3-26-91 PNM */
161  if ( (--(p->references) > 1) ||
162  ( (p->references == 1) && !ISPERMANENT(p->flag) ) )
163  return;
164 
165  while (p != NULL) {
166  if (!ISPATHTYPE(p->type)) {
167  ArgErr("KillPath: bad segment", p, NULL);
168  return;
169  }
170  linkp = p->link;
171  if (p->type == TEXTTYPE)
172  KillText(p);
173  else
174  Free(p);
175  p = linkp;
176  }
177 }
178 
179 /*
180 :h2 id=location."location" Objects
181 
182 The TYPE1IMAGER user creates and destroys objects of type "location". These
183 objects locate points for the primitive path operators. We play a trick
184 here and store these objects in the same "segment" structure used for
185 paths, with a type field == MOVETYPE.
186 
187 This allows the Line() operator, for example, to be very trivial:
188 It merely stamps its input structure as a LINETYPE and returns it to the
189 caller--assuming, of course, the input structure was not permanent (as
190 it usually isn't).
191 
192 :h3.The "movesegment" Template Structure
193 
194 This template is used as a generic segment structure for Allocate:
195 */
196 
197 /* added reference field 1 to temporary template below 3-26-91 PNM */
198 static struct segment movetemplate = { MOVETYPE, 0, 1, sizeof(struct segment), 0,
199  NULL, NULL, { 0, 0 } };
200 /*
201 :h3.Loc() - Create an "Invisible Line" Between (0,0) and a Point
202 
203 */
204 
205 struct segment *t1_Loc(
206  register struct XYspace *S, /* coordinate space to interpret X,Y */
207  DOUBLE x, DOUBLE y) /* destination point */
208 {
209  register struct segment *r;
210 
211 
212  IfTrace3((MustTraceCalls),"..Loc(S=%p, x=%f, y=%f)\n", S, x, y);
213 
214  r = (struct segment *)Allocate(sizeof(struct segment), &movetemplate, 0);
215  TYPECHECK("Loc", S, SPACETYPE, r, (0), struct segment *);
216 
217  r->last = r;
218  r->context = S->context;
219  (*S->convert)(&r->dest, S, x, y);
220  ConsumeSpace(S);
221  return(r);
222 }
223 /*
224 :h3.ILoc() - Loc() With Integer Arguments
225 
226 */
227 struct segment *ILoc(
228  register struct XYspace *S, /* coordinate space to interpret X,Y */
229  register int x, register int y) /* destination point */
230 {
231  register struct segment *r;
232 
233  IfTrace3((MustTraceCalls),"..ILoc(S=%p, x=%d, y=%d)\n",
234  S, (int32_t) x, (int32_t) y);
235  r = (struct segment *)Allocate(sizeof(struct segment), &movetemplate, 0);
236  TYPECHECK("Loc", S, SPACETYPE, r, (0), struct segment *);
237 
238  r->last = r;
239  r->context = S->context;
240  (*S->iconvert)(&r->dest, S, (int32_t) x, (int32_t) y);
241  ConsumeSpace(S);
242  return(r);
243 }
244 
245 /*
246 :h2.Straight Line Segments
247 
248 :h3.PathSegment() - Create a Generic Path Segment
249 
250 Many routines need a LINETYPE or MOVETYPE path segment, but do not
251 want to go through the external user's interface, because, for example,
252 they already know the "fractpel" destination of the segment and the
253 conversion is unnecessary. PathSegment() is an internal routine
254 provided to the rest of TYPE1IMAGER for handling these cases.
255 */
256 
258  int type, /* LINETYPE or MOVETYPE */
259  fractpel x, fractpel y) /* where to go to, if known */
260 {
261  register struct segment *r; /* newly created segment */
262 
263  r = (struct segment *)Allocate(sizeof(struct segment), &movetemplate, 0);
264  r->type = type;
265  r->last = r; /* last points to itself for singleton */
266  r->dest.x = x;
267  r->dest.y = y;
268  return(r);
269 }
270 /*
271 :h3.Line() - Create a Line Segment Between (0,0) and a Point P
272 
273 This involves just creating and filling out a segment structure:
274 */
275 struct segment *Line(
276  register struct segment *P) /* relevant coordinate space */
277 {
278 
279  IfTrace1((MustTraceCalls),"..Line(%p)\n", P);
280  ARGCHECK(!ISLOCATION(P), "Line: arg not a location", P, NULL, (0), struct segment *);
281 
282  P = UniquePath(P);
283  P->type = LINETYPE;
284  return(P);
285 }
286 /*
287 :h2.Curved Path Segments
288 
289 We need more points to describe curves. So, the structures for curved
290 path segments are slightly different. The first part is identical;
291 the curved structures are larger with the extra points on the end.
292 
293 :h3.Bezier Segment Structure
294 
295 We support third order Bezier curves. They are specified with four
296 control points A, B, C, and D. The curve starts at A with slope AB
297 and ends at D with slope CD. The curvature at the point A is inversely
298 related to the length |AB|, and the curvature at the point D is
299 inversely related to the length |CD|. Point A is always point (0,0).
300 
301 */
302 
303 /*SHARED LINE(S) ORIGINATED HERE*/
304 /*
305 :h3.Bezier() - Generate a Bezier Segment
306 
307 This is just a simple matter of filling out a 'beziersegment' structure:
308 */
309 
310 struct beziersegment *Bezier(
311  register struct segment *B, /* second control point */
312  register struct segment *C, /* third control point */
313  register struct segment *D) /* fourth control point (ending point) */
314 {
315 /* added reference field of 1 to temporary template below 3-26-91 PNM */
316  static struct beziersegment template =
317  { BEZIERTYPE, 0, 1, sizeof(struct beziersegment), 0,
318  NULL, NULL, { 0, 0 }, { 0, 0 }, { 0, 0 } };
319 
320  register struct beziersegment *r; /* output segment */
321 
322  IfTrace3((MustTraceCalls),"..Bezier(%p, %p, %p)\n", B, C, D);
323  ARGCHECK(!ISLOCATION(B), "Bezier: bad B", B, NULL, (2,C,D), struct beziersegment *);
324  ARGCHECK(!ISLOCATION(C), "Bezier: bad C", C, NULL, (2,B,D), struct beziersegment *);
325  ARGCHECK(!ISLOCATION(D), "Bezier: bad D", D, NULL, (2,B,C), struct beziersegment *);
326 
327  r = (struct beziersegment *)Allocate(sizeof(struct beziersegment), &template, 0);
328  r->last = (struct segment *) r;
329  r->dest.x = D->dest.x;
330  r->dest.y = D->dest.y;
331  r->B.x = B->dest.x;
332  r->B.y = B->dest.y;
333  r->C.x = C->dest.x;
334  r->C.y = C->dest.y;
335 
336  ConsumePath(B);
337  ConsumePath(C);
338  ConsumePath(D);
339  return(r);
340 }
341 
342 /*
343 :h2.Font "Hint" Segments
344 
345 :h3.Hint() - A Font 'Hint' Segment
346 
347 This is temporary code while we experiment with hints.
348 */
349 
350 /*SHARED LINE(S) ORIGINATED HERE*/
351 struct hintsegment *Hint(
352  struct XYspace *S,
353  float ref,
354  float width,
355  char orientation,
356  char hinttype,
357  char adjusttype,
358  char direction,
359  int label)
360 {
361 /* added reference field of 1 to hintsegment template below 3-26-91 PNM */
362  static struct hintsegment template = { HINTTYPE, 0, 1, sizeof(struct hintsegment), 0,
363  NULL, NULL, { 0, 0 }, { 0, 0 }, { 0, 0 },
364  ' ', ' ', ' ', ' ', 0};
365 
366  register struct hintsegment *r;
367 
368  r = (struct hintsegment *)Allocate(sizeof(struct hintsegment), &template, 0);
369 
370  r->orientation = orientation;
371  if (width == 0.0) width = 1.0;
372 
373  if (orientation == 'h') {
374  (*S->convert)(&r->ref, S, 0.0, ref);
375  (*S->convert)(&r->width, S, 0.0, width);
376  }
377  else if (orientation == 'v') {
378  (*S->convert)(&r->ref, S, ref, 0.0);
379  (*S->convert)(&r->width, S, width, 0.0);
380  }
381  else
382  return((struct hintsegment *)ArgErr("Hint: orient not 'h' or 'v'", NULL, NULL));
383  if (r->width.x < 0) r->width.x = - r->width.x;
384  if (r->width.y < 0) r->width.y = - r->width.y;
385  r->hinttype = hinttype;
386  r->adjusttype = adjusttype;
387  r->direction = direction;
388  r->label = label;
389  r->last = (struct segment *) r;
390  ConsumeSpace(S);
391  return(r);
392 }
393 
394 /*
395 */
396 
397 /*SHARED LINE(S) ORIGINATED HERE*/
398 
399 /*
400 POP removes the first segment in a path 'p' and Frees it. 'p' is left
401 pointing to the end of the path:
402 */
403 #define POP(p) \
404  { register struct segment *linkp; \
405  linkp = p->link; \
406  if (linkp != NULL) \
407  linkp->last = p->last; \
408  Free(p); \
409  p = linkp; }
410 /*
411 INSERT inserts a single segment in the middle of a chain. 'b' is
412 the segment before, 'p' the segment to be inserted, and 'a' the
413 segment after.
414 */
415 #define INSERT(b,p,a) b->link=p; p->link=a; p->last=NULL
416 
417 /*
418 :h3.Join() - Join Two Objects Together
419 
420 If these are paths, this operator simply invokes the CONCAT macro.
421 Why so much code then, you ask? Well we have to check for object
422 types other than paths, and also check for certain path consistency
423 rules.
424 */
425 
426 struct segment *Join(
427  register struct segment *p1, register struct segment *p2)
428 {
429  IfTrace2((MustTraceCalls),"..Join(%p, %p)\n", p1, p2);
430 /*
431 We start with a whole bunch of very straightforward argument tests:
432 */
433  if (p2 != NULL) {
434  if (!ISPATHTYPE(p2->type)) {
435 
436  if (p1 == NULL)
437  return((struct segment *)Unique((struct xobject *)p2));
438 
439  switch (p1->type) {
440 
441  case REGIONTYPE:
442 
443  case STROKEPATHTYPE:
444  p1 = CoercePath(p1);
445  break;
446 
447  default:
448  return((struct segment *)BegHandle(p1, p2));
449  }
450  }
451 
452  ARGCHECK((p2->last == NULL), "Join: right arg not anchor", p2, NULL, (1,p1), struct segment *);
453  p2 = UniquePath(p2);
454 
455 /*
456 In certain circumstances, we don't have to duplicate a permanent
457 location. (We would just end up destroying it anyway). These cases
458 are when 'p2' begins with a move-type segment:
459 */
460  if (p2->type == TEXTTYPE || p2->type == MOVETYPE) {
461  if (p1 == NULL)
462  return(p2);
463  if (ISLOCATION(p1)) {
464  p2->dest.x += p1->dest.x;
465  p2->dest.y += p1->dest.y;
466  ConsumePath(p1);
467  return(p2);
468  }
469  }
470  }
471  else
472  return((struct segment *)Unique((struct xobject *)p1));
473 
474  if (p1 != NULL) {
475  if (!ISPATHTYPE(p1->type))
476 
477  switch (p2->type) {
478 
479  case REGIONTYPE:
480 
481  case STROKEPATHTYPE:
482  p2 = CoercePath(p2);
483  break;
484 
485  default:
486  return((struct segment *)EndHandle(p1, p2));
487  }
488 
489  ARGCHECK((p1->last == NULL), "Join: left arg not anchor", p1, NULL, (1,p2), struct segment *);
490  p1 = UniquePath(p1);
491  }
492  else
493  return(p2);
494 
495 /*
496 At this point all the checking is done. We have two temporary non-null
497 path types in 'p1' and 'p2'. If p1 ends with a MOVE, and p2 begins with
498 a MOVE, we collapse the two MOVEs into one. We enforce the rule that
499 there may not be two MOVEs in a row:
500 */
501 
502  if (p1->last->type == MOVETYPE && p2->type == MOVETYPE) {
503  p1->last->flag |= p2->flag;
504  p1->last->dest.x += p2->dest.x;
505  p1->last->dest.y += p2->dest.y;
506  POP(p2);
507  if (p2 == NULL)
508  return(p1);
509  }
510 /*
511 Now we check for another silly rule. If a path has any TEXTTYPEs,
512 then it must have only TEXTTYPEs and MOVETYPEs, and furthermore,
513 it must begin with a TEXTTYPE. This rule makes it easy to check
514 for the special case of text. If necessary, we will coerce
515 TEXTTYPEs into paths so we don't mix TEXTTYPEs with normal paths.
516 */
517  if (p1->type == TEXTTYPE) {
518  if (p2->type != TEXTTYPE && !ISLOCATION(p2))
519  p1 = CoerceText(p1);
520  }
521  else {
522  if (p2->type == TEXTTYPE) {
523  if (ISLOCATION(p1)) {
524  p2->dest.x += p1->dest.x;
525  p2->dest.y += p1->dest.y;
526  Free(p1);
527  return(p2);
528  }
529  else
530  p2 = CoerceText(p2);
531  }
532  }
533 /*
534 Thank God! Finally! It's hard to believe, but we are now able to
535 actually do the join. This is just invoking the CONCAT macro:
536 */
537  CONCAT(p1, p2);
538 
539  return(p1);
540 }
541 
542 /*
543 :h3.JoinSegment() - Create a Path Segment and Join It to a Known Path
544 
545 This internal function is quicker than a full-fledged join because
546 it can do much less checking.
547 */
548 
550  register struct segment *before, /* path to join before new segment */
551  int type, /* type of new segment (MOVETYPE or LINETYPE) */
552  fractpel x, fractpel y, /* x,y of new segment */
553  register struct segment *after) /* path to join after new segment */
554 {
555  register struct segment *r; /* returned path built here */
556 
557  r = PathSegment(type, x, y);
558  if (before != NULL) {
559  CONCAT(before, r);
560  r = before;
561  }
562  else
563  r->context = after->context;
564  if (after != NULL)
565  CONCAT(r, after);
566  return(r);
567 }
568 
569 /*
570 :h2.Other Path Functions
571 
572 */
573 
574 
576  register struct segment *p0, /* path to close */
577  register int lastonly) /* flag deciding to close all subpaths or... */
578 {
579  register struct segment *p,*last,*start; /* used in looping through path */
580  register fractpel x,y; /* current position in path */
581  register fractpel firstx,firsty; /* start position of sub path */
582  register struct segment *lastnonhint; /* last non-hint segment in path */
583 
584  IfTrace1((MustTraceCalls),"ClosePath(%p)\n", p0);
585  if (p0 != NULL && p0->type == TEXTTYPE)
586  return(UniquePath(p0));
587  if (p0->type == STROKEPATHTYPE)
588  return((struct segment *)Unique((struct xobject *)p0));
589  /*
590  * NOTE: a null closed path is different from a null open path
591  * and is denoted by a closed (0,0) move segment. We make
592  * sure this path begins and ends with a MOVETYPE:
593  */
594  if (p0 == NULL || p0->type != MOVETYPE)
595  p0 = JoinSegment(NULL, MOVETYPE, 0, 0, p0);
596  TYPECHECK("ClosePath", p0, MOVETYPE, NULL, (0), struct segment *);
597  if (p0->last->type != MOVETYPE)
598  p0 = JoinSegment(p0, MOVETYPE, 0, 0, NULL);
599 
600  p0 = UniquePath(p0);
601 
602  lastnonhint = NULL;
603 /*
604 We now begin a loop through the path,
605 incrementing current 'x' and 'y'. We are searching
606 for MOVETYPE segments (breaks in the path) that are not already closed.
607 At each break, we insert a close segment.
608 */
609  for (p = p0, x = y = 0, start = NULL;
610  p != NULL;
611  x += p->dest.x, y += p->dest.y, last = p, p = p->link) {
612 
613  if (p->type == MOVETYPE) {
614  if (start != NULL && (lastonly?p->link==NULL:TRUE) &&
615  !(ISCLOSED(start->flag) && LASTCLOSED(last->flag))) {
616  register struct segment *r; /* newly created */
617 
618  start->flag |= ISCLOSED(ON);
619  r = PathSegment(LINETYPE, firstx - x,
620  firsty - y);
621  INSERT(last, r, p);
622  r->flag |= LASTCLOSED(ON);
623  /*< adjust 'last' if possible for a 0,0 close >*/
624 
625 #define CLOSEFUDGE 3 /* if we are this close, let's change last segment */
626  if (r->dest.x != 0 || r->dest.y != 0) {
627  if (r->dest.x <= CLOSEFUDGE && r->dest.x >= -CLOSEFUDGE
628  && r->dest.y <= CLOSEFUDGE && r->dest.y >= -CLOSEFUDGE) {
630  "ClosePath forced closed by (%d,%d)\n",
631  r->dest.x, r->dest.y);
632  if (lastnonhint == NULL)
633  t1_abort("unexpected NULL pointer in ClosePath");
634  lastnonhint->dest.x += r->dest.x;
635  lastnonhint->dest.y += r->dest.y;
636  r->dest.x = r->dest.y = 0;
637  }
638  }
639  if (p->link != NULL) {
640  p->dest.x += x - firstx;
641  p->dest.y += y - firsty;
642  x = firstx;
643  y = firsty;
644  }
645  }
646  start = p;
647  firstx = x + p->dest.x;
648  firsty = y + p->dest.y;
649  }
650  else if (p->type != HINTTYPE)
651  lastnonhint = p;
652  }
653  return(p0);
654 }
655 /*
656 */
657 /*
658 :h2.Reversing the Direction of a Path
659 
660 This turned out to be more difficult than I thought at first. The
661 trickiness was due to the fact that closed paths must remain closed,
662 etc.
663 
664 We need three subroutines:
665 */
666 
667 static struct segment *SplitPath(struct segment *, struct segment *); /* break a path at any point */
668 static struct segment *DropSubPath(struct segment *); /* breaks a path after first sub-path */
669 static struct segment *ReverseSubPath(struct segment *); /* reverses a single sub-path */
670 
671 /*
672 :h3.Reverse() - User Operator to Reverse a Path
673 
674 This operator reverses the entire path.
675 */
676 
677 struct segment *Reverse(
678  register struct segment *p) /* full path to reverse */
679 {
680  register struct segment *r; /* output path built here */
681  register struct segment *nextp; /* contains next sub-path */
682 
683  IfTrace1((MustTraceCalls),"Reverse(%p)\n", p);
684 
685  if (p == NULL)
686  return(NULL);
687 
688  ARGCHECK(!ISPATHANCHOR(p), "Reverse: invalid path", p, NULL, (0), struct segment *);
689 
690  if (p->type == TEXTTYPE)
691  p = CoerceText(p);
692  p = UniquePath(p);
693 
694  r = NULL;
695 
696  do {
697  nextp = DropSubPath(p);
698  p = ReverseSubPath(p);
699  r = Join(p, r);
700  p = nextp;
701 
702  } while (p != NULL);
703 
704  return(r);
705 }
706 
707 /*
708 :h4.ReverseSubPath() - Subroutine to Reverse a Single Sub-Path
709 */
710 
711 static struct segment *ReverseSubPath(
712  register struct segment *p) /* input path */
713 {
714  register struct segment *r; /* reversed path will be created here */
715  register struct segment *nextp; /* temporary variable used in loop */
716  register int wasclosed; /* flag, path was closed */
717 
718  if (p == NULL)
719  return(NULL);
720 
721  wasclosed = ISCLOSED(p->flag);
722  r = NULL;
723 
724  do {
725 /*
726 First we reverse the direction of this segment and clean up its flags:
727 */
728  p->dest.x = - p->dest.x; p->dest.y = - p->dest.y;
729  p->flag &= ~(ISCLOSED(ON) | LASTCLOSED(ON));
730 
731  switch (p->type) {
732 
733  case LINETYPE:
734  case MOVETYPE:
735  break;
736 
737  case CONICTYPE:
738  {
739 /*
740 The logic of this is that the new M point (stored relative to the new
741 beginning) is (M - C). However, C ("dest") has already been reversed
742 So, we add "dest" instead of subtracting it:
743 */
744  register struct conicsegment *cp = (struct conicsegment *) p;
745 
746  cp->M.x += cp->dest.x; cp->M.y += cp->dest.y;
747  }
748  break;
749 
750  case BEZIERTYPE:
751  {
752  register struct beziersegment *bp = (struct beziersegment *) p;
753 
754  bp->B.x += bp->dest.x; bp->B.y += bp->dest.y;
755  bp->C.x += bp->dest.x; bp->C.y += bp->dest.y;
756  }
757  break;
758 
759  case HINTTYPE:
760  {
761  register struct hintsegment *hp = (struct hintsegment *) p;
762 
763  hp->ref.x = -hp->ref.x; hp->ref.y = -hp->ref.y;
764  }
765  break;
766 
767  default:
768  t1_abort("Reverse: bad path segment");
769  }
770 /*
771 We need to reverse the order of segments too, so we break this segment
772 off of the input path, and tack it on the front of the growing path
773 in 'r':
774 */
775  nextp = p->link;
776  p->link = NULL;
777  p->last = p;
778  if (r != NULL)
779  CONCAT(p,r); /* leaves result in 'p'... not what we want */
780  r = p;
781  p = nextp; /* advance to next segment in input path */
782 
783  } while (p != NULL);
784 
785  if (wasclosed)
786  r = ClosePath(r);
787 
788  return(r);
789 }
790 
791 /*
792 :h4.DropSubPath() - Drops the First Sub-Path Off a Path
793 
794 This subroutine returns the remaining sub-path(s). While doing so, it
795 breaks the input path after the first sub-path so that a pointer to
796 the original path now contains the first sub-path only.
797 */
798 
799 static struct segment *DropSubPath(
800  register struct segment *p0) /* original path */
801 {
802  register struct segment *p; /* returned remainder here */
803 
804  for (p = p0; p->link != NULL; p = p->link) {
805  if (p->link->type == MOVETYPE)
806  break;
807  }
808 
809  return(SplitPath(p0, p));
810 }
811 
812 static struct segment *SplitPath(
813  register struct segment *anchor,
814  register struct segment *before)
815 {
816  register struct segment *r;
817 
818  if (before == anchor->last)
819  return(NULL);
820 
821  r = before->link;
822  r->last = anchor->last;
823  anchor->last = before;
824  before->link = NULL;
825 
826  return(r);
827 }
828 
829 
830 /*
831 :h3.ReverseSubPaths() - Reverse the Direction of Sub-paths Within a Path
832 
833 This user operator reverses the sub-paths in a path, but leaves the
834 'move' segments unchanged. It builds on top of the subroutines
835 already established.
836 */
837 
838 struct segment *ReverseSubPaths(
839  register struct segment *p) /* input path */
840 {
841  register struct segment *r; /* reversed path will be created here */
842  register struct segment *nextp; /* temporary variable used in loop */
843  int wasclosed; /* flag; subpath was closed */
844  register struct segment *nomove; /* the part of sub-path without move segment */
845  struct fractpoint delta;
846 
847  IfTrace1((MustTraceCalls),"ReverseSubPaths(%p)\n", p);
848 
849  if (p == NULL)
850  return(NULL);
851 
852  ARGCHECK(!ISPATHANCHOR(p), "ReverseSubPaths: invalid path", p, NULL, (0), struct segment *);
853 
854  if (p->type == TEXTTYPE)
855  p = CoerceText(p);
856  if (p->type != MOVETYPE)
857  p = JoinSegment(NULL, MOVETYPE, 0, 0, p);
858 
859  p = UniquePath(p);
860 
861  r = NULL;
862 
863  for (; p != NULL;) {
864  nextp = DropSubPath(p);
865  wasclosed = ISCLOSED(p->flag);
866  if (wasclosed)
867  UnClose(p);
868 
869  nomove = SplitPath(p, p);
870  r = Join(r, p);
871 
872  PathDelta(nomove, &delta);
873 
874  nomove = ReverseSubPath(nomove);
875  p->dest.x += delta.x;
876  p->dest.y += delta.y;
877  if (nextp != NULL) {
878  nextp->dest.x += delta.x;
879  nextp->dest.y += delta.y;
880  }
881  if (wasclosed) {
882  nomove = ClosePath(nomove);
883  nextp->dest.x -= delta.x;
884  nextp->dest.y -= delta.y;
885  }
886  r = Join(r, nomove);
887  p = nextp;
888 
889  }
890 
891  return(r);
892 }
893 
894 static void UnClose(register struct segment *p0)
895 {
896  register struct segment *p;
897 
898  for (p=p0; p->link->link != NULL; p=p->link) { ; }
899 
900  if (!LASTCLOSED(p->link->flag))
901  t1_abort("UnClose: no LASTCLOSED");
902 
903  Free(SplitPath(p0, p));
904  p0->flag &= ~~ISCLOSED(ON);
905 }
906 
907 /*
908 :h2.Transforming and Putting Handles on Paths
909 
910 :h3.PathTransform() - Transform a Path
911 
912 Transforming a path involves transforming all the points. In order
913 that closed paths do not become "unclosed" when their relative
914 positions are slightly changed due to loss of arithmetic precision,
915 all point transformations are in absolute coordinates.
916 
917 (It might be better to reset the "absolute" coordinates every time a
918 move segment is encountered. This would mean that we could accumulate
919 error from subpath to subpath, but we would be less likely to make
920 the "big error" where our fixed point arithmetic "wraps". However, I
921 think I'll keep it this way until something happens to convince me
922 otherwise.)
923 
924 The transform is described as a "space", that way we can use our
925 old friend the "iconvert" function, which should be very efficient.
926 */
927 
928 struct segment *PathTransform(
929  register struct segment *p0, /* path to transform */
930  register struct XYspace *S) /* pseudo space to transform in */
931 {
932  register struct segment *p; /* to loop through path with */
933  register fractpel newx,newy; /* current transformed position in path */
934  register fractpel oldx,oldy; /* current untransformed position in path */
935  register fractpel savex,savey; /* save path delta x,y */
936 
937  p0 = UniquePath(p0);
938 
939  newx = newy = oldx = oldy = 0;
940 
941  for (p=p0; p != NULL; p=p->link) {
942 
943  savex = p->dest.x; savey = p->dest.y;
944 
945  (*S->iconvert)(&p->dest, S, p->dest.x + oldx, p->dest.y + oldy);
946  p->dest.x -= newx;
947  p->dest.y -= newy;
948 
949  switch (p->type) {
950 
951  case LINETYPE:
952  case MOVETYPE:
953  break;
954 
955  case CONICTYPE:
956  {
957  register struct conicsegment *cp = (struct conicsegment *) p;
958 
959  (*S->iconvert)(&cp->M, S, cp->M.x + oldx, cp->M.y + oldy);
960  cp->M.x -= newx;
961  cp->M.y -= newy;
962  /*
963  * Note roundness doesn't change... linear transform
964  */
965  break;
966  }
967 
968 
969  case BEZIERTYPE:
970  {
971  register struct beziersegment *bp = (struct beziersegment *) p;
972 
973  (*S->iconvert)(&bp->B, S, bp->B.x + oldx, bp->B.y + oldy);
974  bp->B.x -= newx;
975  bp->B.y -= newy;
976  (*S->iconvert)(&bp->C, S, bp->C.x + oldx, bp->C.y + oldy);
977  bp->C.x -= newx;
978  bp->C.y -= newy;
979  break;
980  }
981 
982  case HINTTYPE:
983  {
984  register struct hintsegment *hp = (struct hintsegment *) p;
985 
986  (*S->iconvert)(&hp->ref, S, hp->ref.x + oldx, hp->ref.y + oldy);
987  hp->ref.x -= newx;
988  hp->ref.y -= newy;
989  (*S->iconvert)(&hp->width, S, hp->width.x, hp->width.y);
990  /* Note: width is not relative to origin */
991  break;
992  }
993 
994  case TEXTTYPE:
995  {
996  XformText(p,S);
997  break;
998  }
999 
1000  default:
1001  IfTrace1(TRUE,"path = %p\n", p);
1002  t1_abort("PathTransform: invalid segment");
1003  }
1004  oldx += savex;
1005  oldy += savey;
1006  newx += p->dest.x;
1007  newy += p->dest.y;
1008  }
1009  return(p0);
1010 }
1011 
1012 /*
1013 :h3.PathDelta() - Return a Path's Ending Point
1014 */
1015 
1016 void PathDelta(
1017  register struct segment *p, /* input path */
1018  register struct fractpoint *pt) /* pointer to x,y to set */
1019 {
1020  register fractpel x,y; /* working variables for path current point */
1021 
1022  for (x=y=0; p != NULL; p=p->link) {
1023  x += p->dest.x;
1024  y += p->dest.y;
1025 #if 0 /* fonts.h defines TextDelta as empty, thus mypoint is not initialized */
1026  if (p->type == TEXTTYPE) {
1027  struct fractpoint mypoint;
1028 
1029  TextDelta(p, &mypoint);
1030  x += mypoint.x;
1031  y += mypoint.y;
1032  }
1033 #endif
1034  }
1035 
1036  pt->x = x;
1037  pt->y = y;
1038 }
1039 
1040 /*
1041 :h3.BoundingBox() - Produce a Bounding Box Path
1042 
1043 This function is called by image code, when we know the size of the
1044 image in pels, and need to get a bounding box path that surrounds it.
1045 The starting/ending handle is in the lower right hand corner.
1046 */
1047 struct segment *BoundingBox(
1048  register pel h, register pel w) /* size of box */
1049 {
1050  register struct segment *path;
1051 
1055  path = ClosePath(path);
1056 
1057  return(path);
1058 }
1059 
1060 /*
1061 :h2.Querying Locations and Paths
1062 
1063 :h3.QueryLoc() - Return the X,Y of a Locition
1064 */
1065 
1066 void QueryLoc(
1067  register struct segment *P, /* location to query, not consumed */
1068  register struct XYspace *S, /* XY space to return coordinates in */
1069  register DOUBLE *xP, /* coordinates ... */
1070  register DOUBLE *yP) /* ... returned here */
1071 {
1072  IfTrace4((MustTraceCalls),"QueryLoc(P=%p, S=%p, (%p, %p))\n",
1073  P, S, xP, yP);
1074  if (!ISLOCATION(P)) {
1075  ArgErr("QueryLoc: first arg not a location", P, NULL);
1076  return;
1077  }
1078  if (S->type != SPACETYPE) {
1079  ArgErr("QueryLoc: second arg not a space", S, NULL);
1080  return;
1081  }
1082  UnConvert(S, &P->dest, xP, yP);
1083 }
1084 /*
1085 :h3.QueryPath() - Find Out the Type of Segment at the Head of a Path
1086 
1087 This is a very simple routine that looks at the first segment of a
1088 path and tells the caller what it is, as well as returning the control
1089 point(s) of the path segment. Different path segments have different
1090 number of control points. If the caller knows that the segment is
1091 a move segment, for example, he only needs to pass pointers to return
1092 one control point.
1093 */
1094 
1095 void QueryPath(
1096  register struct segment *path, /* path to check */
1097  register int *typeP, /* return the type of path here */
1098  register struct segment **Bp, /* return location of first point */
1099  register struct segment **Cp, /* return location of second point */
1100  register struct segment **Dp, /* return location of third point */
1101  register DOUBLE *fP) /* return Conic sharpness */
1102 {
1103  register int coerced = FALSE; /* did I coerce a text path? */
1104 
1105  IfTrace3((MustTraceCalls), "QueryPath(%p, %p, %p, ...)\n",
1106  path, typeP, Bp);
1107  if (path == NULL) {
1108  *typeP = -1;
1109  return;
1110  }
1111  if (!ISPATHANCHOR(path)) {
1112  ArgErr("QueryPath: arg not a valid path", path, NULL);
1113  }
1114  if (path->type == TEXTTYPE) {
1115  path = CoerceText(path);
1116  coerced = TRUE;
1117  }
1118 
1119  switch (path->type) {
1120 
1121  case MOVETYPE:
1122  *typeP = 0;
1123  *Bp = PathSegment(MOVETYPE, path->dest.x, path->dest.y);
1124  break;
1125 
1126  case LINETYPE:
1127  *typeP = (LASTCLOSED(path->flag)) ? 4 : 1;
1128  *Bp = PathSegment(MOVETYPE, path->dest.x, path->dest.y);
1129  break;
1130 
1131  case CONICTYPE:
1132  {
1133  register struct conicsegment *cp = (struct conicsegment *) path;
1134 
1135  *typeP = 2;
1136  *Bp = PathSegment(MOVETYPE, cp->M.x, cp->M.y);
1137  *Cp = PathSegment(MOVETYPE, cp->dest.x, cp->dest.y);
1138  *fP = cp->roundness;
1139  }
1140  break;
1141 
1142  case BEZIERTYPE:
1143  {
1144  register struct beziersegment *bp = (struct beziersegment *) path;
1145 
1146  *typeP = 3;
1147  *Bp = PathSegment(MOVETYPE, bp->B.x, bp->B.y);
1148  *Cp = PathSegment(MOVETYPE, bp->C.x, bp->C.y);
1149  *Dp = PathSegment(MOVETYPE, bp->dest.x, bp->dest.y);
1150  }
1151  break;
1152 
1153  case HINTTYPE:
1154  *typeP = 5;
1155  break;
1156 
1157  default:
1158  t1_abort("QueryPath: unknown segment");
1159  }
1160  if (coerced)
1161  KillPath(path);
1162 }
1163 /*
1164 :h3.QueryBounds() - Return the Bounding Box of a Path
1165 
1166 Returns the bounding box by setting the user's variables.
1167 */
1168 
1169 void QueryBounds(
1170  register struct segment *p0, /* object to check for bound */
1171  struct XYspace *S, /* coordinate space of returned values */
1172  DOUBLE *xminP, DOUBLE *yminP,
1173  /* lower left hand corner (set by routine) */
1174  DOUBLE *xmaxP, DOUBLE *ymaxP)
1175  /* upper right hand corner (set by routine) */
1176 {
1177  register struct segment *path; /* loop variable for path segments */
1178  register fractpel lastx,lasty; /* loop variables: previous endingpoint */
1179  register fractpel x,y; /* loop variables: current ending point */
1180  struct fractpoint min; /* registers to keep lower left hand corner */
1181  struct fractpoint max; /* registers to keep upper right hand corner */
1182  int coerced = FALSE; /* we have coerced the path from another object */
1183  DOUBLE x1,y1,x2,y2,x3,y3,x4,y4; /* corners of rectangle in space X */
1184 
1185  IfTrace2((MustTraceCalls), "QueryBounds(%p, %p,", p0, S);
1186  IfTrace4((MustTraceCalls), " %p, %p, %p, %p)\n",
1187  xminP, yminP, xmaxP, ymaxP);
1188  if (S->type != SPACETYPE) {
1189  ArgErr("QueryBounds: bad XYspace", S, NULL);
1190  return;
1191  }
1192 
1193  min.x = min.y = max.x = max.y = 0;
1194  if (p0 != NULL) {
1195  if (!ISPATHANCHOR(p0)) {
1196  switch(p0->type) {
1197  case STROKEPATHTYPE:
1198  /* replaced DupStrokePath() with Dup() 3-26-91 PNM */
1199  p0 = (struct segment *) DoStroke(Dup((struct xobject *)p0));
1200  /* no break here, we have a region in p0 */
1201  case REGIONTYPE:
1202  p0 = RegionBounds((struct region *)p0);
1203  break;
1204 
1205  case PICTURETYPE:
1206  p0 = PictureBounds(p0);
1207  break;
1208 
1209  default:
1210  ArgErr("QueryBounds: bad object", p0, NULL);
1211  return;
1212  }
1213  coerced = TRUE;
1214  }
1215  if (p0->type == TEXTTYPE) {
1216  /* replaced CopyPath() with Dup() 3-26-91 PNM */
1217  p0 = (struct segment *)CoerceText(Dup((struct xobject *)p0)); /* there are faster ways */
1218  coerced = TRUE;
1219  }
1220  if (p0->type == MOVETYPE) {
1221  min.x = max.x = p0->dest.x;
1222  min.y = max.y = p0->dest.y;
1223  }
1224  }
1225  lastx = lasty = 0;
1226 
1227  for (path = p0; path != NULL; path = path->link) {
1228 
1229  x = lastx + path->dest.x;
1230  y = lasty + path->dest.y;
1231 
1232  switch (path->type) {
1233 
1234  case LINETYPE:
1235  break;
1236 
1237  case CONICTYPE:
1238  {
1239  register struct conicsegment *cp = (struct conicsegment *) path;
1240  register fractpel Mx = lastx + cp->M.x;
1241  register fractpel My = lasty + cp->M.y;
1242  register fractpel deltax = 0.5 * cp->roundness * cp->dest.x;
1243  register fractpel deltay = 0.5 * cp->roundness * cp->dest.y;
1244  register fractpel Px = Mx - deltax;
1245  register fractpel Py = My - deltay;
1246  register fractpel Qx = Mx + deltax;
1247  register fractpel Qy = My + deltay;
1248 
1249 
1250  if (Mx < min.x) min.x = Mx;
1251  else if (Mx > max.x) max.x = Mx;
1252  if (My < min.y) min.y = My;
1253  else if (My > max.y) max.y = My;
1254 
1255  if (Px < min.x) min.x = Px;
1256  else if (Px > max.x) max.x = Px;
1257  if (Py < min.y) min.y = Py;
1258  else if (Py > max.y) max.y = Py;
1259 
1260  if (Qx < min.x) min.x = Qx;
1261  else if (Qx > max.x) max.x = Qx;
1262  if (Qy < min.y) min.y = Qy;
1263  else if (Qy > max.y) max.y = Qy;
1264  }
1265  break;
1266 
1267 
1268  case MOVETYPE:
1269  /*
1270  * We can't risk adding trailing Moves to the
1271  * bounding box:
1272  */
1273  if (path->link == NULL)
1274  goto done; /* God forgive me */
1275  break;
1276 
1277  case BEZIERTYPE:
1278  {
1279  register struct beziersegment *bp = (struct beziersegment *) path;
1280  register fractpel Bx = lastx + bp->B.x;
1281  register fractpel By = lasty + bp->B.y;
1282  register fractpel Cx = lastx + bp->C.x;
1283  register fractpel Cy = lasty + bp->C.y;
1284 
1285  if (Bx < min.x) min.x = Bx;
1286  else if (Bx > max.x) max.x = Bx;
1287  if (By < min.y) min.y = By;
1288  else if (By > max.y) max.y = By;
1289 
1290  if (Cx < min.x) min.x = Cx;
1291  else if (Cx > max.x) max.x = Cx;
1292  if (Cy < min.y) min.y = Cy;
1293  else if (Cy > max.y) max.y = Cy;
1294  }
1295  break;
1296 
1297  case HINTTYPE:
1298  break;
1299  default:
1300  t1_abort("QueryBounds: unknown type");
1301  }
1302 
1303  if (x < min.x) min.x = x;
1304  else if (x > max.x) max.x = x;
1305  if (y < min.y) min.y = y;
1306  else if (y > max.y) max.y = y;
1307 
1308  lastx = x; lasty = y;
1309  }
1310 done:
1311  UnConvert(S, &min, &x1, &y1);
1312  UnConvert(S, &max, &x4, &y4);
1313  x = min.x; min.x = max.x; max.x = x;
1314  UnConvert(S, &min, &x2, &y2);
1315  UnConvert(S, &max, &x3, &y3);
1316 
1317  *xminP = *xmaxP = x1;
1318  if (x2 < *xminP) *xminP = x2;
1319  else if (x2 > *xmaxP) *xmaxP = x2;
1320  if (x3 < *xminP) *xminP = x3;
1321  else if (x3 > *xmaxP) *xmaxP = x3;
1322  if (x4 < *xminP) *xminP = x4;
1323  else if (x4 > *xmaxP) *xmaxP = x4;
1324 
1325  *yminP = *ymaxP = y1;
1326  if (y2 < *yminP) *yminP = y2;
1327  else if (y2 > *ymaxP) *ymaxP = y2;
1328  if (y3 < *yminP) *yminP = y3;
1329  else if (y3 > *ymaxP) *ymaxP = y3;
1330  if (y4 < *yminP) *yminP = y4;
1331  else if (y4 > *ymaxP) *ymaxP = y4;
1332 
1333  if (coerced)
1334  Destroy(p0);
1335 }
1336 /*
1337 :h3.BoxPath()
1338 */
1339 struct segment *BoxPath(struct XYspace *S, int h, int w)
1340 {
1341  struct segment *path;
1342 
1343  path = Join( Line(ILoc(S, w, 0)), Line(ILoc(S, 0, h)) );
1344  path = JoinSegment(path, LINETYPE, -path->dest.x, -path->dest.y, NULL);
1345  return(ClosePath(path));
1346 }
1347 
1348 /*
1349 :h3.DropSegment() - Drop the First Segment in a Path
1350 
1351 This routine takes the path and returns a new path that is one segment
1352 shorter. It can be used in conjunction with QueryPath(), for example,
1353 to ask about an entire path.
1354 */
1355 
1356 struct segment *DropSegment(register struct segment *path)
1357 {
1358  IfTrace1((MustTraceCalls),"DropSegment(%p)\n", path);
1359  if (path != NULL && path->type == STROKEPATHTYPE)
1360  path = CoercePath(path);
1361  ARGCHECK((path == NULL || !ISPATHANCHOR(path)),
1362  "DropSegment: arg not a non-null path", path, path, (0), struct segment *);
1363  if (path->type == TEXTTYPE)
1364  path = CoerceText(path);
1365  path = UniquePath(path);
1366 
1367  POP(path);
1368  return(path);
1369 }
1370 /*
1371 :h3.HeadSegment() - Return the First Segment in a Path
1372 
1373 This routine takes the path and returns a new path consists of the
1374 first segment only.
1375 */
1376 
1377 struct segment *HeadSegment(
1378  register struct segment *path) /* input path */
1379 {
1380  IfTrace1((MustTraceCalls),"HeadSegment(%p)\n", path);
1381  if (path == NULL)
1382  return(NULL);
1383  if (path->type == STROKEPATHTYPE)
1384  path = CoercePath(path);
1385  ARGCHECK(!ISPATHANCHOR(path), "HeadSegment: arg not a path", path, path, (0), struct segment *);
1386  if (path->type == TEXTTYPE)
1387  path = CoerceText(path);
1388  path = UniquePath(path);
1389 
1390  if (path->link != NULL)
1391  KillPath(path->link);
1392  path->link = NULL;
1393  path->last = path;
1394  return(path);
1395 }
bp
Definition: action.c:1035
cp
Definition: action.c:1035
#define C
Definition: afm2pl.c:546
#define width(a)
Definition: aptex-macros.h:198
#define type(a)
Definition: aptex-macros.h:171
#define x3
#define y4
#define before
Definition: aptex-macros.h:256
#define x4
#define y3
void Bezier(double x1, double y1, double x2, double y2, double x3, double y3)
Definition: axohelp.c:352
void Line(double *)
Definition: axohelp.c:1395
char * p2
Definition: bmpfont.h:62
char * p1
Definition: bmpfont.h:62
#define n
Definition: t4ht.c:1290
#define Bp
@ FALSE
Definition: dd.h:101
@ TRUE
Definition: dd.h:102
#define Free(x)
Definition: dd.h:135
int w
Definition: dviconv.c:26
int h
Definition: dviconv.c:9
#define CoerceText(t)
Definition: fonts.h:39
#define XformText(p, s)
Definition: fonts.h:41
#define TextDelta(t, pt)
Definition: fonts.h:40
#define CopyText(t)
Definition: fonts.h:37
#define KillText(t)
Definition: fonts.h:36
#define p0
paragraph P
const unsigned D
Definition: image.cpp:30
#define NULL
Definition: ftobjs.h:61
small capitals from c petite p
Definition: afcover.h:72
kerning y
Definition: ttdriver.c:212
signed int int32_t
Definition: stdint.h:77
#define TYPECHECK(o, t)
Definition: pdfobj.c:868
#define QueryPath(p, t, B, C, D, r)
Definition: paths.h:54
#define ILoc(S, x, y)
Definition: paths.h:34
#define Join(p1, p2)
Definition: paths.h:36
#define QueryBounds(p, S, x1, y1, x2, y2)
Definition: paths.h:55
#define LASTCLOSED(flag)
Definition: paths.h:138
#define CopyPath(p)
Definition: paths.h:94
#define PathSegment(t, x, y)
Definition: paths.h:99
#define BoxPath(S, h, w)
Definition: paths.h:102
#define HeadSegment(p)
Definition: paths.h:52
#define KillPath(p)
Definition: paths.h:95
#define ReverseSubPaths(p)
Definition: paths.h:46
#define BoundingBox(h, w)
Definition: paths.h:98
#define PathDelta(p, pt)
Definition: paths.h:97
#define Hint(S, r, w, o, h, a, d, l)
Definition: paths.h:44
#define UniquePath(p)
Definition: paths.h:123
#define JoinSegment(b, t, x, y, a)
Definition: paths.h:100
#define ISCLOSED(flag)
Definition: paths.h:137
#define ISPATHANCHOR(p)
Definition: paths.h:149
#define Reverse(p)
Definition: paths.h:45
#define ConsumePath(p)
Definition: paths.h:122
#define QueryLoc(P, S, x, y)
Definition: paths.h:53
#define DropSegment(p)
Definition: paths.h:51
#define ISLOCATION(p)
Definition: paths.h:157
#define PathTransform(p, m)
Definition: paths.h:96
#define ClosePath(p)
Definition: paths.h:37
double DOUBLE
Definition: types.h:28
float x
Definition: cordic.py:15
def ref(x)
Definition: pdf-org.py:104
void t1_abort(const char *str)
Definition: objects.c:1088
#define PICTURETYPE
Definition: objects.h:141
#define CONICTYPE
Definition: objects.h:150
char MustTraceCalls
#define IfTrace2(condition, model, arg0, arg1)
Definition: objects.h:237
#define TEXTTYPE
Definition: objects.h:155
#define IfTrace4(condition, model, arg0, arg1, arg2, arg3)
Definition: objects.h:241
#define Destroy(obj)
Definition: objects.h:43
#define LINETYPE
Definition: objects.h:149
char PathDebug
#define STROKEPATHTYPE
Definition: objects.h:145
#define Allocate(n, t, s)
Definition: objects.h:59
#define BEZIERTYPE
Definition: objects.h:151
#define ARGCHECK(test, msg, obj, whenBAD, consumables, rettype)
Definition: objects.h:196
#define Dup(obj)
Definition: objects.h:44
#define Unique(obj)
Definition: objects.h:66
#define ArgErr(s, o, r)
Definition: objects.h:63
#define ISPERMANENT(flag)
Definition: objects.h:160
#define SPACETYPE
Definition: objects.h:142
#define IfTrace3(condition, model, arg0, arg1, arg2)
Definition: objects.h:239
#define REGIONTYPE
Definition: objects.h:140
#define IfTrace1(condition, model, arg0)
Definition: objects.h:235
#define HINTTYPE
Definition: objects.h:152
#define ISPATHTYPE(type)
Definition: objects.h:148
#define MOVETYPE
Definition: objects.h:154
struct segment * t1_ClosePath(register struct segment *p0, register int lastonly)
Definition: paths.c:575
#define POP(p)
Definition: paths.c:403
static struct segment * ReverseSubPath(struct segment *)
static struct segment * SplitPath(struct segment *, struct segment *)
struct segment * t1_PathSegment(int type, fractpel x, fractpel y)
Definition: paths.c:257
static void UnClose(struct segment *)
static struct segment * DropSubPath(struct segment *)
#define CLOSEFUDGE
struct segment * t1_Loc(register struct XYspace *S, DOUBLE x, DOUBLE y)
Definition: paths.c:205
static struct segment movetemplate
Definition: paths.c:198
#define INSERT(b, p, a)
Definition: paths.c:415
struct segment * t1_JoinSegment(register struct segment *before, int type, fractpel x, fractpel y, register struct segment *after)
Definition: paths.c:549
#define min(a, b)
Definition: pbmplus.h:223
#define max(a, b)
Definition: pbmto4425.c:11
static int delta
Definition: pbmtolj.c:36
#define PictureBounds(P)
Definition: pictures.h:37
#define EndHandle(o, m)
Definition: pictures.h:36
#define BegHandle(o, m)
Definition: pictures.h:35
static int32_t last
Definition: ppagelist.c:29
#define B(x, y)
int r
Definition: ppmqvga.c:68
#define x1
#define y1
#define y2
#define x2
@ CONCAT
#define RegionBounds(r)
Definition: regions.h:135
mp_ptr hp
Definition: sec_pi1_div.c:86
#define direction(p, c)
Definition: sh12.c:109
#define ConsumeSpace(s)
Definition: spaces.h:144
SHORT pel
Definition: spaces.h:36
#define UnConvert(S, pt, xp, yp)
Definition: spaces.h:116
#define TOFRACTPEL(p)
Definition: spaces.h:44
int32_t fractpel
Definition: spaces.h:37
#define int32_t
Definition: stdint.in.h:167
#define DoStroke(sp)
Definition: strokes.h:37
#define CoercePath(sp)
Definition: strokes.h:36
Definition: spaces.h:60
fractpel y
Definition: spaces.h:81
fractpel x
Definition: spaces.h:81
Definition: tpic.c:45
double x
Definition: tpic.c:46
double y
Definition: tpic.c:46
unsigned int type[5]
Definition: regions.h:31
Definition: paths.h:128
struct segment * last
Definition: paths.h:133
struct fractpoint dest
Definition: paths.h:134
pointer path
Definition: t1imager.h:36
struct def_label label[1024]
Definition: t1part.c:286
@ after
Definition: texnodes.h:374
@ ON
Definition: ubidiimp.h:55
@ S
Definition: ubidiimp.h:53
@ start
Definition: preamble.c:52
PATTERN * pt
Definition: vlna.c:74