~ubuntu-branches/ubuntu/trusty/libxfont/trusty-proposed

« back to all changes in this revision

Viewing changes to src/Type1/paths.c

  • Committer: Bazaar Package Importer
  • Author(s): Bryce Harrington
  • Date: 2007-07-18 16:46:59 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20070718164659-h894n91b3dynfwi2
Tags: 1:1.3.0-0ubuntu1
* New upstream release.
* debian/control:
  - Maintainer field updated
* debian/copyright:
  - Added packaging copyright

Show diffs side-by-side

added added

removed removed

Lines of Context:
246
246
}
247
247
 
248
248
/*
249
 
:h3.SubLoc() - Vector Subtraction of Two Locition Objects
250
 
 
251
 
This user operator subtracts two location objects, yielding a new
252
 
location object that is the result.
253
 
 
254
 
The symmetrical function AddLoc() is totally redundent with Join(),
255
 
so it is not provided.
256
 
*/
257
 
 
258
 
struct segment *
259
 
SubLoc(struct segment *p1, struct segment *p2)
260
 
{
261
 
       ARGCHECK(!ISLOCATION(p1), "SubLoc: bad first arg", p1, NULL, (0), struct segment *);
262
 
       ARGCHECK(!ISLOCATION(p2), "SubLoc: bad second arg", p2, NULL, (0), struct segment *);
263
 
       p1 = UniquePath(p1);
264
 
       p1->dest.x -= p2->dest.x;
265
 
       p1->dest.y -= p2->dest.y;
266
 
       ConsumePath(p2);
267
 
       return(p1);
268
 
}
269
 
 
270
 
/*
271
249
:h2.Straight Line Segments
272
250
 
273
251
:h3.PathSegment() - Create a Generic Path Segment
361
339
       return(r);
362
340
}
363
341
 
364
 
/*
365
 
:h2.Font "Hint" Segments
366
 
 
367
 
:h3.Hint() - A Font 'Hint' Segment
368
 
 
369
 
This is temporary code while we experiment with hints.
370
 
*/
371
 
 
372
 
/*SHARED LINE(S) ORIGINATED HERE*/
373
 
struct hintsegment *
374
 
Hint(struct XYspace *S, float ref, float width, 
375
 
     char orientation, char hinttype, char adjusttype, char direction, 
376
 
     int label)
377
 
{
378
 
/* added reference field of 1 to hintsegment template below 3-26-91 PNM */
379
 
       static struct hintsegment template = { HINTTYPE, 0, 1, sizeof(struct hintsegment), 0,
380
 
                                          NULL, NULL, { 0, 0 }, { 0, 0 }, { 0, 0 },
381
 
                                          ' ', ' ', ' ', ' ', 0};
382
 
 
383
 
       register struct hintsegment *r;
384
 
 
385
 
       r = (struct hintsegment *)Allocate(sizeof(struct hintsegment), &template, 0);
386
 
 
387
 
       r->orientation = orientation;
388
 
       if (width == 0.0)  width = 1.0;
389
 
 
390
 
       if (orientation == 'h') {
391
 
               (*S->convert)(&r->ref, S, 0.0, ref);
392
 
               (*S->convert)(&r->width, S, 0.0, width);
393
 
       }
394
 
       else if (orientation == 'v') {
395
 
               (*S->convert)(&r->ref, S, ref, 0.0);
396
 
               (*S->convert)(&r->width, S, width, 0.0);
397
 
       }
398
 
       else
399
 
               return((struct hintsegment *)ArgErr("Hint: orient not 'h' or 'v'", NULL, NULL));
400
 
       if (r->width.x < 0)  r->width.x = - r->width.x;
401
 
       if (r->width.y < 0)  r->width.y = - r->width.y;
402
 
       r->hinttype = hinttype;
403
 
       r->adjusttype = adjusttype;
404
 
       r->direction = direction;
405
 
       r->label = label;
406
 
       r->last = (struct segment *) r;
407
 
       ConsumeSpace(S);
408
 
       return(r);
409
 
}
410
 
 
411
 
/*
412
 
*/
413
 
 
414
342
/*SHARED LINE(S) ORIGINATED HERE*/
415
343
 
416
344
/*
665
593
       }
666
594
       return(p0);
667
595
}
668
 
/*
669
 
*/
670
 
/*
671
 
:h2.Reversing the Direction of a Path
672
 
 
673
 
This turned out to be more difficult than I thought at first.  The
674
 
trickiness was due to the fact that closed paths must remain closed,
675
 
etc.
676
 
 
677
 
We need three subroutines:
678
 
*/
679
 
 
680
 
/* break a path at any point             */
681
 
static struct segment *SplitPath ( struct segment *anchor, 
682
 
                                          struct segment *before );
683
 
/* breaks a path after first sub-path */
684
 
static struct segment *DropSubPath ( struct segment *p0 );
685
 
/* reverses a single sub-path      */
686
 
static struct segment *ReverseSubPath ( struct segment *p );
687
 
 
688
 
/*
689
 
:h3.Reverse() - User Operator to Reverse a Path
690
 
 
691
 
This operator reverses the entire path.
692
 
*/
693
 
 
694
 
struct segment *
695
 
Reverse(struct segment *p)            /* full path to reverse                */
696
 
{
697
 
       register struct segment *r;    /* output path built here              */
698
 
       register struct segment *nextp;  /* contains next sub-path            */
699
 
 
700
 
       if (p == NULL)
701
 
               return(NULL);
702
 
 
703
 
       ARGCHECK(!ISPATHANCHOR(p), "Reverse: invalid path", p, NULL, (0), struct segment *);
704
 
 
705
 
       if (p->type == TEXTTYPE)
706
 
               p = CoerceText(p);
707
 
       p = UniquePath(p);
708
 
 
709
 
       r = NULL;
710
 
 
711
 
       do {
712
 
               nextp = DropSubPath(p);
713
 
               p = ReverseSubPath(p);
714
 
               r = Join(p, r);
715
 
               p = nextp;
716
 
 
717
 
       } while (p != NULL);
718
 
 
719
 
       return(r);
720
 
}
721
 
 
722
 
/*
723
 
:h4.ReverseSubPath() - Subroutine to Reverse a Single Sub-Path
724
 
*/
725
 
 
726
 
static struct segment *
727
 
ReverseSubPath(struct segment *p)   /* input path                            */
728
 
{
729
 
       register struct segment *r;  /* reversed path will be created here    */
730
 
       register struct segment *nextp;  /* temporary variable used in loop   */
731
 
       register int wasclosed;  /* flag, path was closed                     */
732
 
 
733
 
       if (p == NULL)
734
 
               return(NULL);
735
 
 
736
 
       wasclosed = ISCLOSED(p->flag);
737
 
       r = NULL;
738
 
 
739
 
       do {
740
 
/*
741
 
First we reverse the direction of this segment and clean up its flags:
742
 
*/
743
 
               p->dest.x = - p->dest.x;  p->dest.y = - p->dest.y;
744
 
               p->flag &= ~(ISCLOSED(ON) | LASTCLOSED(ON));
745
 
 
746
 
               switch (p->type) {
747
 
 
748
 
                   case LINETYPE:
749
 
                   case MOVETYPE:
750
 
                       break;
751
 
 
752
 
                   case CONICTYPE:
753
 
                   {
754
 
/*
755
 
The logic of this is that the new M point (stored relative to the new
756
 
beginning) is (M - C).  However, C ("dest") has already been reversed
757
 
So, we add "dest" instead of subtracting it:
758
 
*/
759
 
                       register struct conicsegment *cp = (struct conicsegment *) p;
760
 
 
761
 
                       cp->M.x += cp->dest.x;  cp->M.y += cp->dest.y;
762
 
                   }
763
 
                       break;
764
 
 
765
 
                   case BEZIERTYPE:
766
 
                   {
767
 
                       register struct beziersegment *bp = (struct beziersegment *) p;
768
 
 
769
 
                       bp->B.x += bp->dest.x;  bp->B.y += bp->dest.y;
770
 
                       bp->C.x += bp->dest.x;  bp->C.y += bp->dest.y;
771
 
                   }
772
 
                       break;
773
 
 
774
 
                   case HINTTYPE:
775
 
                   {
776
 
                       register struct hintsegment *hp = (struct hintsegment *) p;
777
 
 
778
 
                       hp->ref.x = -hp->ref.x;  hp->ref.y = -hp->ref.y;
779
 
                   }
780
 
                       break;
781
 
 
782
 
                   default:
783
 
                       Abort("Reverse: bad path segment");
784
 
               }
785
 
/*
786
 
We need to reverse the order of segments too, so we break this segment
787
 
off of the input path, and tack it on the front of the growing path
788
 
in 'r':
789
 
*/
790
 
               nextp = p->link;
791
 
               p->link = NULL;
792
 
               p->last = p;
793
 
               if (r != NULL)
794
 
                       CONCAT(p,r);  /* leaves result in 'p'... not what we want */
795
 
               r = p;
796
 
               p = nextp;    /* advance to next segment in input path        */
797
 
 
798
 
       } while (p != NULL);
799
 
 
800
 
       if (wasclosed)
801
 
               r = ClosePath(r);
802
 
 
803
 
       return(r);
804
 
}
805
 
 
806
 
/*
807
 
:h4.DropSubPath() - Drops the First Sub-Path Off a Path
808
 
 
809
 
This subroutine returns the remaining sub-path(s).  While doing so, it
810
 
breaks the input path after the first sub-path so that a pointer to
811
 
the original path now contains the first sub-path only.
812
 
*/
813
 
 
814
 
static struct segment *
815
 
DropSubPath(struct segment *p0)     /* original path                         */
816
 
{
817
 
       register struct segment *p;  /* returned remainder here               */
818
 
 
819
 
       for (p = p0; p->link != NULL; p = p->link) {
820
 
               if (p->link->type == MOVETYPE)
821
 
                       break;
822
 
       }
823
 
 
824
 
       return(SplitPath(p0, p));
825
 
}
826
 
 
827
 
static struct segment *
828
 
SplitPath(struct segment *anchor, struct segment *before)
829
 
{
830
 
       register struct segment *r;
831
 
 
832
 
       if (before == anchor->last)
833
 
               return(NULL);
834
 
 
835
 
       r = before->link;
836
 
       r->last = anchor->last;
837
 
       anchor->last = before;
838
 
       before->link = NULL;
839
 
 
840
 
       return(r);
841
 
}
842
 
 
843
 
static void
844
 
UnClose(struct segment *p0)
845
 
{
846
 
       register struct segment *p;
847
 
 
848
 
       for (p=p0; p->link->link != NULL; p=p->link) { ; }
849
 
 
850
 
       if (!LASTCLOSED(p->link->flag))
851
 
               Abort("UnClose:  no LASTCLOSED");
852
 
 
853
 
       Free(SplitPath(p0, p));
854
 
       p0->flag &= ~ISCLOSED(ON);
855
 
}
856
 
 
857
 
/*
858
 
:h3.ReverseSubPaths() - Reverse the Direction of Sub-paths Within a Path
859
 
 
860
 
This user operator reverses the sub-paths in a path, but leaves the
861
 
'move' segments unchanged.  It builds on top of the subroutines
862
 
already established.
863
 
*/
864
 
 
865
 
struct segment *
866
 
ReverseSubPaths(struct segment *p)  /* input path                            */
867
 
{
868
 
       register struct segment *r;  /* reversed path will be created here    */
869
 
       register struct segment *nextp;  /* temporary variable used in loop   */
870
 
       int wasclosed;        /* flag; subpath was closed                     */
871
 
       register struct segment *nomove;  /* the part of sub-path without move segment */
872
 
       struct fractpoint delta;
873
 
 
874
 
       if (p == NULL)
875
 
               return(NULL);
876
 
 
877
 
       ARGCHECK(!ISPATHANCHOR(p), "ReverseSubPaths: invalid path", p, NULL, (0), struct segment *);
878
 
 
879
 
       if (p->type == TEXTTYPE)
880
 
               p = CoerceText(p);
881
 
       if (p->type != MOVETYPE)
882
 
               p = JoinSegment(NULL, MOVETYPE, 0, 0, p);
883
 
 
884
 
       p = UniquePath(p);
885
 
 
886
 
       r = NULL;
887
 
 
888
 
       for (; p != NULL;) {
889
 
               nextp = DropSubPath(p);
890
 
               wasclosed = ISCLOSED(p->flag);
891
 
               if (wasclosed)
892
 
                       UnClose(p);
893
 
 
894
 
               nomove = SplitPath(p, p);
895
 
               r = Join(r, p);
896
 
 
897
 
               PathDelta(nomove, &delta);
898
 
 
899
 
               nomove = ReverseSubPath(nomove);
900
 
               p->dest.x += delta.x;
901
 
               p->dest.y += delta.y;
902
 
               if (nextp != NULL) {
903
 
                       nextp->dest.x += delta.x;
904
 
                       nextp->dest.y += delta.y;
905
 
               }
906
 
               if (wasclosed) {
907
 
                       nomove = ClosePath(nomove);
908
 
                       nextp->dest.x -= delta.x;
909
 
                       nextp->dest.y -= delta.y;
910
 
               }
911
 
               r = Join(r, nomove);
912
 
               p = nextp;
913
 
 
914
 
       }
915
 
 
916
 
       return(r);
917
 
}
918
596
 
919
597
/*
920
598
:h2.Transforming and Putting Handles on Paths
1030
708
{
1031
709
       struct fractpoint mypoint;  /* I pass this to TextDelta               */
1032
710
       register fractpel x,y;  /* working variables for path current point   */
 
711
 
 
712
       mypoint.x = mypoint.y = 0;
1033
713
 
1034
714
       for (x=y=0; p != NULL; p=p->link) {
1035
715
               x += p->dest.x;
1046
726
}
1047
727
 
1048
728
/*
1049
 
:h3.BoundingBox() - Produce a Bounding Box Path
1050
 
 
1051
 
This function is called by image code, when we know the size of the
1052
 
image in pels, and need to get a bounding box path that surrounds it.
1053
 
The starting/ending handle is in the lower right hand corner.
1054
 
*/
1055
 
struct segment *
1056
 
BoundingBox(pel h, pel w)    /* size of box                                  */
1057
 
{
1058
 
       register struct segment *path;
1059
 
 
1060
 
       path = PathSegment(LINETYPE, -TOFRACTPEL(w), 0);
1061
 
       path = JoinSegment(NULL, LINETYPE, 0, -TOFRACTPEL(h), path);
1062
 
       path = JoinSegment(NULL, LINETYPE, TOFRACTPEL(w), 0, path);
1063
 
       path = ClosePath(path);
1064
 
 
1065
 
       return(path);
1066
 
}
1067
 
 
1068
 
/*
1069
729
:h2.Querying Locations and Paths
1070
730
 
1071
731
:h3.QueryLoc() - Return the X,Y of a Locition
1086
746
       }
1087
747
       UnConvert(S, &P->dest, xP, yP);
1088
748
}
1089
 
/*
1090
 
:h3.QueryPath() - Find Out the Type of Segment at the Head of a Path
1091
 
 
1092
 
This is a very simple routine that looks at the first segment of a
1093
 
path and tells the caller what it is, as well as returning the control
1094
 
point(s) of the path segment.  Different path segments have different
1095
 
number of control points.  If the caller knows that the segment is
1096
 
a move segment, for example, he only needs to pass pointers to return
1097
 
one control point.
1098
 
*/
1099
 
 
1100
 
void 
1101
 
QueryPath(struct segment *path, /* path to check                             */
1102
 
          int *typeP,        /* return the type of path here                 */
1103
 
          struct segment **Bp,  /* return location of first point            */
1104
 
          struct segment **Cp,  /* return location of second point           */
1105
 
          struct segment **Dp,  /* return location of third point            */
1106
 
          double *fP)           /* return Conic sharpness                    */
1107
 
{
1108
 
       register int coerced = FALSE;  /* did I coerce a text path?           */
1109
 
 
1110
 
       if (path == NULL) {
1111
 
               *typeP = -1;
1112
 
               return;
1113
 
       }
1114
 
       if (!ISPATHANCHOR(path)) {
1115
 
               ArgErr("QueryPath: arg not a valid path", path, NULL);
1116
 
       }
1117
 
       if (path->type == TEXTTYPE) {
1118
 
               path = CoerceText(path);
1119
 
               coerced = TRUE;
1120
 
       }
1121
 
 
1122
 
       switch (path->type) {
1123
 
 
1124
 
           case MOVETYPE:
1125
 
               *typeP = 0;
1126
 
               *Bp = PathSegment(MOVETYPE, path->dest.x, path->dest.y);
1127
 
               break;
1128
 
 
1129
 
           case LINETYPE:
1130
 
               *typeP = (LASTCLOSED(path->flag)) ? 4 : 1;
1131
 
               *Bp = PathSegment(MOVETYPE, path->dest.x, path->dest.y);
1132
 
               break;
1133
 
 
1134
 
           case CONICTYPE:
1135
 
           {
1136
 
               register struct conicsegment *cp = (struct conicsegment *) path;
1137
 
 
1138
 
               *typeP = 2;
1139
 
               *Bp = PathSegment(MOVETYPE, cp->M.x, cp->M.y);
1140
 
               *Cp = PathSegment(MOVETYPE, cp->dest.x, cp->dest.y);
1141
 
               *fP = cp->roundness;
1142
 
           }
1143
 
               break;
1144
 
 
1145
 
           case BEZIERTYPE:
1146
 
           {
1147
 
               register struct beziersegment *bp = (struct beziersegment *) path;
1148
 
 
1149
 
               *typeP = 3;
1150
 
               *Bp = PathSegment(MOVETYPE, bp->B.x, bp->B.y);
1151
 
               *Cp = PathSegment(MOVETYPE, bp->C.x, bp->C.y);
1152
 
               *Dp = PathSegment(MOVETYPE, bp->dest.x, bp->dest.y);
1153
 
           }
1154
 
               break;
1155
 
 
1156
 
           case HINTTYPE:
1157
 
               *typeP = 5;
1158
 
               break;
1159
 
 
1160
 
           default:
1161
 
               Abort("QueryPath: unknown segment");
1162
 
       }
1163
 
       if (coerced)
1164
 
               KillPath(path);
1165
 
}
1166
 
/*
1167
 
:h3.QueryBounds() - Return the Bounding Box of a Path
1168
 
 
1169
 
Returns the bounding box by setting the user's variables.
1170
 
*/
1171
 
 
1172
 
void 
1173
 
QueryBounds(struct segment *p0, /* object to check for bound                 */
1174
 
            struct XYspace *S, /* coordinate space of returned values        */
1175
 
            double *xminP,   /* lower left hand corner (set by routine)      */
1176
 
            double *yminP,
1177
 
            double *xmaxP,   /* upper right hand corner (set by routine)     */
1178
 
            double *ymaxP)
1179
 
{
1180
 
       register struct segment *path;  /* loop variable for path segments    */
1181
 
       register fractpel lastx,lasty;  /* loop variables:  previous endingpoint */
1182
 
       register fractpel x,y;  /* loop variables:  current ending point      */
1183
 
       struct fractpoint min;  /* registers to keep lower left hand corner   */
1184
 
       struct fractpoint max;  /* registers to keep upper right hand corner  */
1185
 
       int coerced = FALSE;  /* we have coerced the path from another object */
1186
 
       double x1,y1,x2,y2,x3,y3,x4,y4;  /* corners of rectangle in space X   */
1187
 
 
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(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(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
 
                       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 *
1340
 
BoxPath(struct XYspace *S, int h, int w)
1341
 
{
1342
 
       struct segment *path;
1343
 
 
1344
 
       path = Join( Line(ILoc(S, w, 0)), Line(ILoc(S, 0, h)) );
1345
 
       path = JoinSegment(path, LINETYPE, -path->dest.x, -path->dest.y, NULL);
1346
 
       return(ClosePath(path));
1347
 
}
1348
 
 
1349
 
/*
1350
 
:h3.DropSegment() - Drop the First Segment in a Path
1351
 
 
1352
 
This routine takes the path and returns a new path that is one segment
1353
 
shorter.  It can be used in conjunction with QueryPath(), for example,
1354
 
to ask about an entire path.
1355
 
*/
1356
 
 
1357
 
struct segment *
1358
 
DropSegment(struct segment *path)
1359
 
{
1360
 
       if (path != NULL && path->type == STROKEPATHTYPE)
1361
 
               path = CoercePath(path);
1362
 
       ARGCHECK((path == NULL || !ISPATHANCHOR(path)),
1363
 
                 "DropSegment: arg not a non-null path", path, path, (0), struct segment *);
1364
 
       if (path->type == TEXTTYPE)
1365
 
               path = CoerceText(path);
1366
 
       path = UniquePath(path);
1367
 
 
1368
 
       POP(path);
1369
 
       return(path);
1370
 
}
1371
 
/*
1372
 
:h3.HeadSegment() - Return the First Segment in a Path
1373
 
 
1374
 
This routine takes the path and returns a new path consists of the
1375
 
first segment only.
1376
 
*/
1377
 
 
1378
 
struct segment *
1379
 
HeadSegment(struct segment *path)     /* input path                         */
1380
 
{
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
 
}
1396
 
 
1397
 
/*
1398
 
:h2.Path Debug Routines
1399
 
 
1400
 
:h3.DumpPath() - Display a Path on the Trace File
1401
 
*/
1402
 
 
1403
 
void 
1404
 
DumpPath(struct segment *p)
1405
 
{
1406
 
}