[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

/libraries/tcpdf/fonts/ttf2ufm/ttf2ufm-src/ -> pt1.c (source)

   1  /*
   2   * see COPYRIGHT
   3   */
   4  
   5  #include <stdio.h>
   6  #include <stdlib.h>
   7  #include <string.h>
   8  #include <sys/types.h>
   9  #include <sys/stat.h>
  10  #include <fcntl.h>
  11  #include <time.h>
  12  #include <ctype.h>
  13  #include <math.h>
  14  
  15  #ifndef WINDOWS
  16  #    include <netinet/in.h>
  17  #    include <unistd.h>
  18  #else
  19  #    include "windows.h"
  20  #endif
  21  
  22  #include "ttf.h"
  23  #include "pt1.h"
  24  #include "global.h"
  25  
  26  /* big and small values for comparisons */
  27  #define FBIGVAL    (1e20)
  28  #define FEPS    (100000./FBIGVAL)
  29  
  30  /* names of the axes */
  31  #define X    0
  32  #define    Y    1
  33  
  34  /* the GENTRY extension structure used in fforceconcise() */
  35  
  36  struct gex_con {
  37      double d[2 /*X, Y*/]; /* sizes of curve */
  38      double sin2; /* squared sinus of the angle to the next gentry */
  39      double len2; /* squared distance between the endpoints */
  40  
  41  /* number of reference dots taken from each curve */
  42  #define NREFDOTS    3
  43  
  44      double dots[NREFDOTS][2]; /* reference dots */
  45  
  46      int flags; /* flags for gentry and tits joint to the next gentry */
  47  /* a vertical or horizontal line may be in 2 quadrants at once */
  48  #define GEXF_QUL    0x00000001 /* in up-left quadrant */
  49  #define GEXF_QUR    0x00000002 /* in up-right quadrant */
  50  #define GEXF_QDR    0x00000004 /* in down-right quadrant */
  51  #define GEXF_QDL    0x00000008 /* in down-left quadrant */
  52  #define GEXF_QMASK    0x0000000F /* quadrant mask */
  53  
  54  /* if a line is nearly vertical or horizontal, we remember that idealized quartant too */
  55  #define GEXF_QTO_IDEAL(f)    (((f)&0xF)<<4)
  56  #define GEXF_QFROM_IDEAL(f)    (((f)&0xF0)>>4)
  57  #define GEXF_IDQ_L    0x00000090 /* left */
  58  #define GEXF_IDQ_R    0x00000060 /* right */
  59  #define GEXF_IDQ_U    0x00000030 /* up */
  60  #define GEXF_IDQ_D    0x000000C0 /* down */
  61  
  62  /* possibly can be joined with conditions: 
  63   * (in order of increasing preference, the numeric order is important) 
  64   */
  65  #define GEXF_JLINE    0x00000100 /* into one line */
  66  #define GEXF_JIGN    0x00000200 /* if one entry's tangent angle is ignored */
  67  #define GEXF_JID    0x00000400 /* if one entry is idealized to hor/vert */
  68  #define GEXF_JFLAT    0x00000800 /* if one entry is flattened */
  69  #define GEXF_JGOOD    0x00001000 /* perfectly, no additional maodifications */
  70  
  71  #define GEXF_JMASK    0x00001F00 /* the mask of all above */
  72  #define GEXF_JCVMASK    0x00001E00 /* the mask of all above except JLINE */
  73  
  74  /* which entry needs to be modified for conditional joining */
  75  #define GEXF_JIGN1    0x00002000
  76  #define GEXF_JIGN2    0x00004000
  77  #define GEXF_JIGNDIR(dir)    (GEXF_JIGN1<<(dir))
  78  #define GEXF_JID1    0x00008000
  79  #define GEXF_JID2    0x00010000
  80  #define GEXF_JIDDIR(dir)    (GEXF_JID1<<(dir))
  81  #define GEXF_JFLAT1    0x00020000
  82  #define GEXF_JFLAT2    0x00040000
  83  #define GEXF_JFLATDIR(dir)    (GEXF_JFLAT1<<(dir))
  84  
  85  #define GEXF_VERT    0x00100000 /* is nearly vertical */
  86  #define GEXF_HOR    0x00200000 /* is nearly horizontal */
  87  #define GEXF_FLAT    0x00400000 /* is nearly flat */
  88  
  89  #define GEXF_VDOTS    0x01000000 /* the dots are valid */
  90  
  91      signed char isd[2 /*X,Y*/]; /* signs of the sizes */
  92  };
  93  typedef struct gex_con GEX_CON;
  94  
  95  /* convenience macros */
  96  #define    X_CON(ge)    ((GEX_CON *)((ge)->ext))
  97  #define X_CON_D(ge)    (X_CON(ge)->d)
  98  #define X_CON_DX(ge)    (X_CON(ge)->d[0])
  99  #define X_CON_DY(ge)    (X_CON(ge)->d[1])
 100  #define X_CON_ISD(ge)    (X_CON(ge)->isd)
 101  #define X_CON_ISDX(ge)    (X_CON(ge)->isd[0])
 102  #define X_CON_ISDY(ge)    (X_CON(ge)->isd[1])
 103  #define X_CON_SIN2(ge)    (X_CON(ge)->sin2)
 104  #define X_CON_LEN2(ge)    (X_CON(ge)->len2)
 105  #define X_CON_F(ge)    (X_CON(ge)->flags)
 106  
 107  /* performance statistics about guessing the concise curves */
 108  static int ggoodcv=0, ggoodcvdots=0, gbadcv=0, gbadcvdots=0;
 109  
 110  int      stdhw, stdvw;    /* dominant stems widths */
 111  int      stemsnaph[12], stemsnapv[12];    /* most typical stem width */
 112  
 113  int      bluevalues[14];
 114  int      nblues;
 115  int      otherblues[10];
 116  int      notherb;
 117  int      bbox[4];    /* the FontBBox array */
 118  double   italic_angle;
 119  
 120  GLYPH   *glyph_list;
 121  int    encoding[ENCTABSZ];    /* inverse of glyph[].char_no */
 122  int    kerning_pairs = 0;
 123  
 124  /* prototypes */
 125  static void fixcvdir( GENTRY * ge, int dir);
 126  static void fixcvends( GENTRY * ge);
 127  static int fgetcvdir( GENTRY * ge);
 128  static int igetcvdir( GENTRY * ge);
 129  static int fiszigzag( GENTRY *ge);
 130  static int iiszigzag( GENTRY *ge);
 131  static GENTRY * freethisge( GENTRY *ge);
 132  static void addgeafter( GENTRY *oge, GENTRY *nge );
 133  static GENTRY * newgentry( int flags);
 134  static void debugstems( char *name, STEM * hstems, int nhs, STEM * vstems, int nvs);
 135  static int addbluestems( STEM *s, int n);
 136  static void sortstems( STEM * s, int n);
 137  static int stemoverlap( STEM * s1, STEM * s2);
 138  static int steminblue( STEM *s);
 139  static void markbluestems( STEM *s, int nold);
 140  static int joinmainstems( STEM * s, int nold, int useblues);
 141  static void joinsubstems( STEM * s, short *pairs, int nold, int useblues);
 142  static void fixendpath( GENTRY *ge);
 143  static void fdelsmall( GLYPH *g, double minlen);
 144  static void alloc_gex_con( GENTRY *ge);
 145  static double fjointsin2( GENTRY *ge1, GENTRY *ge2);
 146  static double fcvarea( GENTRY *ge);
 147  static double fcvval( GENTRY *ge, int axis, double t);
 148  static void fsampledots( GENTRY *ge, double dots[][2], int ndots);
 149  static void fnormalizege( GENTRY *ge);
 150  static void fanalyzege( GENTRY *ge);
 151  static void fanalyzejoint( GENTRY *ge);
 152  static void fconcisecontour( GLYPH *g, GENTRY *ge);
 153  static double fclosegap( GENTRY *from, GENTRY *to, int axis,
 154      double gap, double *ret);
 155  
 156  int
 157  isign(
 158       int x
 159  )
 160  {
 161      if (x > 0)
 162          return 1;
 163      else if (x < 0)
 164          return -1;
 165      else
 166          return 0;
 167  }
 168  
 169  int
 170  fsign(
 171       double x
 172  )
 173  {
 174      if (x > 0.0)
 175          return 1;
 176      else if (x < 0.0)
 177          return -1;
 178      else
 179          return 0;
 180  }
 181  
 182  static GENTRY *
 183  newgentry(
 184      int flags
 185  )
 186  {
 187      GENTRY         *ge;
 188  
 189      ge = calloc(1, sizeof(GENTRY));
 190  
 191      if (ge == 0) {
 192          fprintf(stderr, "***** Memory allocation error *****\n");
 193          exit(255);
 194      }
 195      ge->stemid = -1;
 196      ge->flags = flags;
 197      /* the rest is set to 0 by calloc() */
 198      return ge;
 199  }
 200  
 201  /*
 202   * Routines to print out Postscript functions with optimization
 203   */
 204  
 205  void
 206  rmoveto(
 207      int dx,
 208      int dy
 209  )
 210  {
 211      if (optimize && dx == 0)
 212          fprintf(pfa_file, "%d vmoveto\n", dy);
 213      else if (optimize && dy == 0)
 214          fprintf(pfa_file, "%d hmoveto\n", dx);
 215      else
 216          fprintf(pfa_file, "%d %d rmoveto\n", dx, dy);
 217  }
 218  
 219  void
 220  rlineto(
 221      int dx,
 222      int dy
 223  )
 224  {
 225      if (optimize && dx == 0 && dy == 0)    /* for special pathologic
 226                           * case */
 227          return;
 228      else if (optimize && dx == 0)
 229          fprintf(pfa_file, "%d vlineto\n", dy);
 230      else if (optimize && dy == 0)
 231          fprintf(pfa_file, "%d hlineto\n", dx);
 232      else
 233          fprintf(pfa_file, "%d %d rlineto\n", dx, dy);
 234  }
 235  
 236  void
 237  rrcurveto(
 238        int dx1,
 239        int dy1,
 240        int dx2,
 241        int dy2,
 242        int dx3,
 243        int dy3
 244  )
 245  {
 246      /* first two ifs are for crazy cases that occur surprisingly often */
 247      if (optimize && dx1 == 0 && dx2 == 0 && dx3 == 0)
 248          rlineto(0, dy1 + dy2 + dy3);
 249      else if (optimize && dy1 == 0 && dy2 == 0 && dy3 == 0)
 250          rlineto(dx1 + dx2 + dx3, 0);
 251      else if (optimize && dy1 == 0 && dx3 == 0)
 252          fprintf(pfa_file, "%d %d %d %d hvcurveto\n",
 253              dx1, dx2, dy2, dy3);
 254      else if (optimize && dx1 == 0 && dy3 == 0)
 255          fprintf(pfa_file, "%d %d %d %d vhcurveto\n",
 256              dy1, dx2, dy2, dx3);
 257      else
 258          fprintf(pfa_file, "%d %d %d %d %d %d rrcurveto\n",
 259              dx1, dy1, dx2, dy2, dx3, dy3);
 260  }
 261  
 262  void
 263  closepath(void)
 264  {
 265      fprintf(pfa_file, "closepath\n");
 266  }
 267  
 268  /*
 269   * Many of the path processing routines exist (or will exist) in
 270   * both floating-point and integer version. Fimally most of the
 271   * processing will go in floating point and the integer processing
 272   * will become legacy.
 273   * The names of floating routines start with f, names of integer 
 274   * routines start with i, and those old routines existing in one 
 275   * version only have no such prefix at all.
 276   */
 277  
 278  /*
 279  ** Routine that checks integrity of the path, for debugging
 280  */
 281  
 282  void
 283  assertpath(
 284         GENTRY * from,
 285         char *file,
 286         int line,
 287         char *name
 288  )
 289  {
 290      GENTRY         *first, *pe, *ge;
 291      int    isfloat;
 292  
 293      if(from==0)
 294          return;
 295      isfloat = (from->flags & GEF_FLOAT);
 296      pe = from->prev;
 297      for (ge = from; ge != 0; pe = ge, ge = ge->next) {
 298          if( (ge->flags & GEF_FLOAT) ^ isfloat ) {
 299              fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
 300              fprintf(stderr, "float flag changes from %s to %s at 0x%p (type %c, prev type %c)\n",
 301                  (isfloat ? "TRUE" : "FALSE"), (isfloat ? "FALSE" : "TRUE"), ge, ge->type, pe->type);
 302              abort();
 303          }
 304          if (pe != ge->prev) {
 305              fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
 306              fprintf(stderr, "unidirectional chain 0x%x -next-> 0x%x -prev-> 0x%x \n",
 307                  pe, ge, ge->prev);
 308              abort();
 309          }
 310  
 311          switch(ge->type) {
 312          case GE_MOVE:
 313              break;
 314          case GE_PATH:
 315              if (ge->prev == 0) {
 316                  fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
 317                  fprintf(stderr, "empty path at 0x%x \n", ge);
 318                  abort();
 319              }
 320              break;
 321          case GE_LINE:
 322          case GE_CURVE:
 323              if(ge->frwd->bkwd != ge) {
 324                  fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
 325                  fprintf(stderr, "unidirectional chain 0x%x -frwd-> 0x%x -bkwd-> 0x%x \n",
 326                      ge, ge->frwd, ge->frwd->bkwd);
 327                  abort();
 328              }
 329              if(ge->prev->type == GE_MOVE) {
 330                  first = ge;
 331                  if(ge->bkwd->next->type != GE_PATH) {
 332                      fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
 333                      fprintf(stderr, "broken first backlink 0x%x -bkwd-> 0x%x -next-> 0x%x \n",
 334                          ge, ge->bkwd, ge->bkwd->next);
 335                      abort();
 336                  }
 337              }
 338              if(ge->next->type == GE_PATH) {
 339                  if(ge->frwd != first) {
 340                      fprintf(stderr, "**! assertpath: called from %s line %d (%s) ****\n", file, line, name);
 341                      fprintf(stderr, "broken loop 0x%x -...-> 0x%x -frwd-> 0x%x \n",
 342                          first, ge, ge->frwd);
 343                      abort();
 344                  }
 345              }
 346              break;
 347          }
 348  
 349      }
 350  }
 351  
 352  void
 353  assertisfloat(
 354      GLYPH *g,
 355      char *msg
 356  )
 357  {
 358      if( !(g->flags & GF_FLOAT) ) {
 359          fprintf(stderr, "**! Glyph %s is not float: %s\n", g->name, msg);
 360          abort();
 361      }
 362      if(g->lastentry) {
 363          if( !(g->lastentry->flags & GEF_FLOAT) ) {
 364              fprintf(stderr, "**! Glyphs %s last entry is int: %s\n", g->name, msg);
 365              abort();
 366          }
 367      }
 368  }
 369  
 370  void
 371  assertisint(
 372      GLYPH *g,
 373      char *msg
 374  )
 375  {
 376      if( (g->flags & GF_FLOAT) ) {
 377          fprintf(stderr, "**! Glyph %s is not int: %s\n", g->name, msg);
 378          abort();
 379      }
 380      if(g->lastentry) {
 381          if( (g->lastentry->flags & GEF_FLOAT) ) {
 382              fprintf(stderr, "**! Glyphs %s last entry is float: %s\n", g->name, msg);
 383              abort();
 384          }
 385      }
 386  }
 387  
 388  
 389  /*
 390   * Routines to save the generated data about glyph
 391   */
 392  
 393  void
 394  fg_rmoveto(
 395        GLYPH * g,
 396        double x,
 397        double y)
 398  {
 399      GENTRY         *oge;
 400  
 401      if (ISDBG(BUILDG))
 402          fprintf(stderr, "%s: f rmoveto(%g, %g)\n", g->name, x, y);
 403  
 404      assertisfloat(g, "adding float MOVE");
 405  
 406      if ((oge = g->lastentry) != 0) {
 407          if (oge->type == GE_MOVE) {    /* just eat up the first move */
 408              oge->fx3 = x;
 409              oge->fy3 = y;
 410          } else if (oge->type == GE_LINE || oge->type == GE_CURVE) {
 411              fprintf(stderr, "Glyph %s: MOVE in middle of path\n", g->name);
 412          } else {
 413              GENTRY         *nge;
 414  
 415              nge = newgentry(GEF_FLOAT);
 416              nge->type = GE_MOVE;
 417              nge->fx3 = x;
 418              nge->fy3 = y;
 419  
 420              oge->next = nge;
 421              nge->prev = oge;
 422              g->lastentry = nge;
 423          }
 424      } else {
 425          GENTRY         *nge;
 426  
 427          nge = newgentry(GEF_FLOAT);
 428          nge->type = GE_MOVE;
 429          nge->fx3 = x;
 430          nge->fy3 = y;
 431          nge->bkwd = (GENTRY*)&g->entries;
 432          g->entries = g->lastentry = nge;
 433      }
 434  
 435      if (0 && ISDBG(BUILDG))
 436          dumppaths(g, NULL, NULL);
 437  }
 438  
 439  void
 440  ig_rmoveto(
 441        GLYPH * g,
 442        int x,
 443        int y)
 444  {
 445      GENTRY         *oge;
 446  
 447      if (ISDBG(BUILDG))
 448          fprintf(stderr, "%s: i rmoveto(%d, %d)\n", g->name, x, y);
 449  
 450      assertisint(g, "adding int MOVE");
 451  
 452      if ((oge = g->lastentry) != 0) {
 453          if (oge->type == GE_MOVE) {    /* just eat up the first move */
 454              oge->ix3 = x;
 455              oge->iy3 = y;
 456          } else if (oge->type == GE_LINE || oge->type == GE_CURVE) {
 457              fprintf(stderr, "Glyph %s: MOVE in middle of path, ignored\n", g->name);
 458          } else {
 459              GENTRY         *nge;
 460  
 461              nge = newgentry(0);
 462              nge->type = GE_MOVE;
 463              nge->ix3 = x;
 464              nge->iy3 = y;
 465  
 466              oge->next = nge;
 467              nge->prev = oge;
 468              g->lastentry = nge;
 469          }
 470      } else {
 471          GENTRY         *nge;
 472  
 473          nge = newgentry(0);
 474          nge->type = GE_MOVE;
 475          nge->ix3 = x;
 476          nge->iy3 = y;
 477          nge->bkwd = (GENTRY*)&g->entries;
 478          g->entries = g->lastentry = nge;
 479      }
 480  
 481  }
 482  
 483  void
 484  fg_rlineto(
 485        GLYPH * g,
 486        double x,
 487        double y)
 488  {
 489      GENTRY         *oge, *nge;
 490  
 491      if (ISDBG(BUILDG))
 492          fprintf(stderr, "%s: f rlineto(%g, %g)\n", g->name, x, y);
 493  
 494      assertisfloat(g, "adding float LINE");
 495  
 496      nge = newgentry(GEF_FLOAT);
 497      nge->type = GE_LINE;
 498      nge->fx3 = x;
 499      nge->fy3 = y;
 500  
 501      if ((oge = g->lastentry) != 0) {
 502          if (x == oge->fx3 && y == oge->fy3) {    /* empty line */
 503              /* ignore it or we will get in troubles later */
 504              free(nge);
 505              return;
 506          }
 507          if (g->path == 0) {
 508              g->path = nge;
 509              nge->bkwd = nge->frwd = nge;
 510          } else {
 511              oge->frwd = nge;
 512              nge->bkwd = oge;
 513              g->path->bkwd = nge;
 514              nge->frwd = g->path;
 515          }
 516  
 517          oge->next = nge;
 518          nge->prev = oge;
 519          g->lastentry = nge;
 520      } else {
 521          WARNING_1 fprintf(stderr, "Glyph %s: LINE outside of path\n", g->name);
 522          free(nge);
 523      }
 524  
 525      if (0 && ISDBG(BUILDG))
 526          dumppaths(g, NULL, NULL);
 527  }
 528  
 529  void
 530  ig_rlineto(
 531        GLYPH * g,
 532        int x,
 533        int y)
 534  {
 535      GENTRY         *oge, *nge;
 536  
 537      if (ISDBG(BUILDG))
 538          fprintf(stderr, "%s: i rlineto(%d, %d)\n", g->name, x, y);
 539  
 540      assertisint(g, "adding int LINE");
 541  
 542      nge = newgentry(0);
 543      nge->type = GE_LINE;
 544      nge->ix3 = x;
 545      nge->iy3 = y;
 546  
 547      if ((oge = g->lastentry) != 0) {
 548          if (x == oge->ix3 && y == oge->iy3) {    /* empty line */
 549              /* ignore it or we will get in troubles later */
 550              free(nge);
 551              return;
 552          }
 553          if (g->path == 0) {
 554              g->path = nge;
 555              nge->bkwd = nge->frwd = nge;
 556          } else {
 557              oge->frwd = nge;
 558              nge->bkwd = oge;
 559              g->path->bkwd = nge;
 560              nge->frwd = g->path;
 561          }
 562  
 563          oge->next = nge;
 564          nge->prev = oge;
 565          g->lastentry = nge;
 566      } else {
 567          WARNING_1 fprintf(stderr, "Glyph %s: LINE outside of path\n", g->name);
 568          free(nge);
 569      }
 570  
 571  }
 572  
 573  void
 574  fg_rrcurveto(
 575          GLYPH * g,
 576          double x1,
 577          double y1,
 578          double x2,
 579          double y2,
 580          double x3,
 581          double y3)
 582  {
 583      GENTRY         *oge, *nge;
 584  
 585      oge = g->lastentry;
 586  
 587      if (ISDBG(BUILDG))
 588          fprintf(stderr, "%s: f rrcurveto(%g, %g, %g, %g, %g, %g)\n"
 589              ,g->name, x1, y1, x2, y2, x3, y3);
 590  
 591      assertisfloat(g, "adding float CURVE");
 592  
 593      if (oge && oge->fx3 == x1 && x1 == x2 && x2 == x3)    /* check if it's
 594                                   * actually a line */
 595          fg_rlineto(g, x1, y3);
 596      else if (oge && oge->fy3 == y1 && y1 == y2 && y2 == y3)
 597          fg_rlineto(g, x3, y1);
 598      else {
 599          nge = newgentry(GEF_FLOAT);
 600          nge->type = GE_CURVE;
 601          nge->fx1 = x1;
 602          nge->fy1 = y1;
 603          nge->fx2 = x2;
 604          nge->fy2 = y2;
 605          nge->fx3 = x3;
 606          nge->fy3 = y3;
 607  
 608          if (oge != 0) {
 609              if (x3 == oge->fx3 && y3 == oge->fy3) {
 610                  free(nge);    /* consider this curve empty */
 611                  /* ignore it or we will get in troubles later */
 612                  return;
 613              }
 614              if (g->path == 0) {
 615                  g->path = nge;
 616                  nge->bkwd = nge->frwd = nge;
 617              } else {
 618                  oge->frwd = nge;
 619                  nge->bkwd = oge;
 620                  g->path->bkwd = nge;
 621                  nge->frwd = g->path;
 622              }
 623  
 624              oge->next = nge;
 625              nge->prev = oge;
 626              g->lastentry = nge;
 627          } else {
 628              WARNING_1 fprintf(stderr, "Glyph %s: CURVE outside of path\n", g->name);
 629              free(nge);
 630          }
 631      }
 632  
 633      if (0 && ISDBG(BUILDG))
 634          dumppaths(g, NULL, NULL);
 635  }
 636  
 637  void
 638  ig_rrcurveto(
 639          GLYPH * g,
 640          int x1,
 641          int y1,
 642          int x2,
 643          int y2,
 644          int x3,
 645          int y3)
 646  {
 647      GENTRY         *oge, *nge;
 648  
 649      oge = g->lastentry;
 650  
 651      if (ISDBG(BUILDG))
 652          fprintf(stderr, "%s: i rrcurveto(%d, %d, %d, %d, %d, %d)\n"
 653              ,g->name, x1, y1, x2, y2, x3, y3);
 654  
 655      assertisint(g, "adding int CURVE");
 656  
 657      if (oge && oge->ix3 == x1 && x1 == x2 && x2 == x3)    /* check if it's
 658                                   * actually a line */
 659          ig_rlineto(g, x1, y3);
 660      else if (oge && oge->iy3 == y1 && y1 == y2 && y2 == y3)
 661          ig_rlineto(g, x3, y1);
 662      else {
 663          nge = newgentry(0);
 664          nge->type = GE_CURVE;
 665          nge->ix1 = x1;
 666          nge->iy1 = y1;
 667          nge->ix2 = x2;
 668          nge->iy2 = y2;
 669          nge->ix3 = x3;
 670          nge->iy3 = y3;
 671  
 672          if (oge != 0) {
 673              if (x3 == oge->ix3 && y3 == oge->iy3) {
 674                  free(nge);    /* consider this curve empty */
 675                  /* ignore it or we will get in troubles later */
 676                  return;
 677              }
 678              if (g->path == 0) {
 679                  g->path = nge;
 680                  nge->bkwd = nge->frwd = nge;
 681              } else {
 682                  oge->frwd = nge;
 683                  nge->bkwd = oge;
 684                  g->path->bkwd = nge;
 685                  nge->frwd = g->path;
 686              }
 687  
 688              oge->next = nge;
 689              nge->prev = oge;
 690              g->lastentry = nge;
 691          } else {
 692              WARNING_1 fprintf(stderr, "Glyph %s: CURVE outside of path\n", g->name);
 693              free(nge);
 694          }
 695      }
 696  }
 697  
 698  void
 699  g_closepath(
 700          GLYPH * g
 701  )
 702  {
 703      GENTRY         *oge, *nge;
 704  
 705      if (ISDBG(BUILDG))
 706          fprintf(stderr, "%s: closepath\n", g->name);
 707  
 708      oge = g->lastentry;
 709  
 710      if (g->path == 0) {
 711          WARNING_1 fprintf(stderr, "Warning: **** closepath on empty path in glyph \"%s\" ****\n",
 712              g->name);
 713          if (oge == 0) {
 714              WARNING_1 fprintf(stderr, "No previois entry\n");
 715          } else {
 716              WARNING_1 fprintf(stderr, "Previous entry type: %c\n", oge->type);
 717              if (oge->type == GE_MOVE) {
 718                  g->lastentry = oge->prev;
 719                  if (oge->prev == 0)
 720                      g->entries = 0;
 721                  else
 722                      g->lastentry->next = 0;
 723                  free(oge);
 724              }
 725          }
 726          return;
 727      }
 728  
 729      nge = newgentry(oge->flags & GEF_FLOAT); /* keep the same type */
 730      nge->type = GE_PATH;
 731  
 732      g->path = 0;
 733  
 734      oge->next = nge;
 735      nge->prev = oge;
 736      g->lastentry = nge;
 737  
 738      if (0 && ISDBG(BUILDG))
 739          dumppaths(g, NULL, NULL);
 740  }
 741  
 742  /*
 743   * * SB * Routines to smooth and fix the glyphs
 744   */
 745  
 746  /*
 747  ** we don't want to see the curves with coinciding middle and
 748  ** outer points
 749  */
 750  
 751  static void
 752  fixcvends(
 753        GENTRY * ge
 754  )
 755  {
 756      int             dx, dy;
 757      int             x0, y0, x1, y1, x2, y2, x3, y3;
 758  
 759      if (ge->type != GE_CURVE)
 760          return;
 761  
 762      if(ge->flags & GEF_FLOAT) {
 763          fprintf(stderr, "**! fixcvends(0x%x) on floating entry, ABORT\n", ge);
 764          abort(); /* dump core */
 765      }
 766  
 767      x0 = ge->prev->ix3;
 768      y0 = ge->prev->iy3;
 769      x1 = ge->ix1;
 770      y1 = ge->iy1;
 771      x2 = ge->ix2;
 772      y2 = ge->iy2;
 773      x3 = ge->ix3;
 774      y3 = ge->iy3;
 775  
 776  
 777      /* look at the start of the curve */
 778      if (x1 == x0 && y1 == y0) {
 779          dx = x2 - x1;
 780          dy = y2 - y1;
 781  
 782          if (dx == 0 && dy == 0
 783              || x2 == x3 && y2 == y3) {
 784              /* Oops, we actually have a straight line */
 785              /*
 786               * if it's small, we hope that it will get optimized
 787               * later
 788               */
 789              if (abs(x3 - x0) <= 2 || abs(y3 - y0) <= 2) {
 790                  ge->ix1 = x3;
 791                  ge->iy1 = y3;
 792                  ge->ix2 = x0;
 793                  ge->iy2 = y0;
 794              } else {/* just make it a line */
 795                  ge->type = GE_LINE;
 796              }
 797          } else {
 798              if (abs(dx) < 4 && abs(dy) < 4) {    /* consider it very
 799                                   * small */
 800                  ge->ix1 = x2;
 801                  ge->iy1 = y2;
 802              } else if (abs(dx) < 8 && abs(dy) < 8) {    /* consider it small */
 803                  ge->ix1 += dx / 2;
 804                  ge->iy1 += dy / 2;
 805              } else {
 806                  ge->ix1 += dx / 4;
 807                  ge->iy1 += dy / 4;
 808              }
 809              /* make sure that it's still on the same side */
 810              if (abs(x3 - x0) * abs(dy) < abs(y3 - y0) * abs(dx)) {
 811                  if (abs(x3 - x0) * abs(ge->iy1 - y0) > abs(y3 - y0) * abs(ge->ix1 - x0))
 812                      ge->ix1 += isign(dx);
 813              } else {
 814                  if (abs(x3 - x0) * abs(ge->iy1 - y0) < abs(y3 - y0) * abs(ge->ix1 - x0))
 815                      ge->iy1 += isign(dy);
 816              }
 817  
 818              ge->ix2 += (x3 - x2) / 8;
 819              ge->iy2 += (y3 - y2) / 8;
 820              /* make sure that it's still on the same side */
 821              if (abs(x3 - x0) * abs(y3 - y2) < abs(y3 - y0) * abs(x3 - x2)) {
 822                  if (abs(x3 - x0) * abs(y3 - ge->iy2) > abs(y3 - y0) * abs(x3 - ge->ix2))
 823                      ge->iy1 -= isign(y3 - y2);
 824              } else {
 825                  if (abs(x3 - x0) * abs(y3 - ge->iy2) < abs(y3 - y0) * abs(x3 - ge->ix2))
 826                      ge->ix1 -= isign(x3 - x2);
 827              }
 828  
 829          }
 830      } else if (x2 == x3 && y2 == y3) {
 831          dx = x1 - x2;
 832          dy = y1 - y2;
 833  
 834          if (dx == 0 && dy == 0) {
 835              /* Oops, we actually have a straight line */
 836              /*
 837               * if it's small, we hope that it will get optimized
 838               * later
 839               */
 840              if (abs(x3 - x0) <= 2 || abs(y3 - y0) <= 2) {
 841                  ge->ix1 = x3;
 842                  ge->iy1 = y3;
 843                  ge->ix2 = x0;
 844                  ge->iy2 = y0;
 845              } else {/* just make it a line */
 846                  ge->type = GE_LINE;
 847              }
 848          } else {
 849              if (abs(dx) < 4 && abs(dy) < 4) {    /* consider it very
 850                                   * small */
 851                  ge->ix2 = x1;
 852                  ge->iy2 = y1;
 853              } else if (abs(dx) < 8 && abs(dy) < 8) {    /* consider it small */
 854                  ge->ix2 += dx / 2;
 855                  ge->iy2 += dy / 2;
 856              } else {
 857                  ge->ix2 += dx / 4;
 858                  ge->iy2 += dy / 4;
 859              }
 860              /* make sure that it's still on the same side */
 861              if (abs(x3 - x0) * abs(dy) < abs(y3 - y0) * abs(dx)) {
 862                  if (abs(x3 - x0) * abs(ge->iy2 - y3) > abs(y3 - y0) * abs(ge->ix2 - x3))
 863                      ge->ix2 += isign(dx);
 864              } else {
 865                  if (abs(x3 - x0) * abs(ge->iy2 - y3) < abs(y3 - y0) * abs(ge->ix2 - x3))
 866                      ge->iy2 += isign(dy);
 867              }
 868  
 869              ge->ix1 += (x0 - x1) / 8;
 870              ge->iy1 += (y0 - y1) / 8;
 871              /* make sure that it's still on the same side */
 872              if (abs(x3 - x0) * abs(y0 - y1) < abs(y3 - y0) * abs(x0 - x1)) {
 873                  if (abs(x3 - x0) * abs(y0 - ge->iy1) > abs(y3 - y0) * abs(x0 - ge->ix1))
 874                      ge->iy1 -= isign(y0 - y1);
 875              } else {
 876                  if (abs(x3 - x0) * abs(y0 - ge->iy1) < abs(y3 - y0) * abs(x0 - ge->ix1))
 877                      ge->ix1 -= isign(x0 - x1);
 878              }
 879  
 880          }
 881      }
 882  }
 883  
 884  /*
 885  ** After transformations we want to make sure that the resulting
 886  ** curve is going in the same quadrant as the original one,
 887  ** because rounding errors introduced during transformations
 888  ** may make the result completeley wrong.
 889  **
 890  ** `dir' argument describes the direction of the original curve,
 891  ** it is the superposition of two values for the front and
 892  ** rear ends of curve:
 893  **
 894  ** >EQUAL - goes over the line connecting the ends
 895  ** =EQUAL - coincides with the line connecting the ends
 896  ** <EQUAL - goes under the line connecting the ends
 897  **
 898  ** See CVDIR_* for exact definitions.
 899  */
 900  
 901  static void
 902  fixcvdir(
 903       GENTRY * ge,
 904       int dir
 905  )
 906  {
 907      int             a, b, c, d;
 908      double          kk, kk1, kk2;
 909      int             changed;
 910      int             fdir, rdir;
 911  
 912      if(ge->flags & GEF_FLOAT) {
 913          fprintf(stderr, "**! fixcvdir(0x%x) on floating entry, ABORT\n", ge);
 914          abort(); /* dump core */
 915      }
 916  
 917      fdir = (dir & CVDIR_FRONT) - CVDIR_FEQUAL;
 918      if ((dir & CVDIR_REAR) == CVDIR_RSAME)
 919          rdir = fdir; /* we need only isign, exact value doesn't matter */
 920      else
 921          rdir = (dir & CVDIR_REAR) - CVDIR_REQUAL;
 922  
 923      fixcvends(ge);
 924  
 925      c = isign(ge->ix3 - ge->prev->ix3);    /* note the direction of
 926                           * curve */
 927      d = isign(ge->iy3 - ge->prev->iy3);
 928  
 929      a = ge->iy3 - ge->prev->iy3;
 930      b = ge->ix3 - ge->prev->ix3;
 931      kk = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
 932      a = ge->iy1 - ge->prev->iy3;
 933      b = ge->ix1 - ge->prev->ix3;
 934      kk1 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
 935      a = ge->iy3 - ge->iy2;
 936      b = ge->ix3 - ge->ix2;
 937      kk2 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
 938  
 939      changed = 1;
 940      while (changed) {
 941          if (ISDBG(FIXCVDIR)) {
 942              /* for debugging */
 943              fprintf(stderr, "fixcvdir %d %d (%d %d %d %d %d %d) %f %f %f\n",
 944                  fdir, rdir,
 945                  ge->ix1 - ge->prev->ix3,
 946                  ge->iy1 - ge->prev->iy3,
 947                  ge->ix2 - ge->ix1,
 948                  ge->iy2 - ge->iy1,
 949                  ge->ix3 - ge->ix2,
 950                  ge->iy3 - ge->iy2,
 951                  kk1, kk, kk2);
 952          }
 953          changed = 0;
 954  
 955          if (fdir > 0) {
 956              if (kk1 > kk) {    /* the front end has problems */
 957                  if (c * (ge->ix1 - ge->prev->ix3) > 0) {
 958                      ge->ix1 -= c;
 959                      changed = 1;
 960                  } if (d * (ge->iy2 - ge->iy1) > 0) {
 961                      ge->iy1 += d;
 962                      changed = 1;
 963                  }
 964                  /* recalculate the coefficients */
 965                  a = ge->iy3 - ge->prev->iy3;
 966                  b = ge->ix3 - ge->prev->ix3;
 967                  kk = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
 968                  a = ge->iy1 - ge->prev->iy3;
 969                  b = ge->ix1 - ge->prev->ix3;
 970                  kk1 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
 971              }
 972          } else if (fdir < 0) {
 973              if (kk1 < kk) {    /* the front end has problems */
 974                  if (c * (ge->ix2 - ge->ix1) > 0) {
 975                      ge->ix1 += c;
 976                      changed = 1;
 977                  } if (d * (ge->iy1 - ge->prev->iy3) > 0) {
 978                      ge->iy1 -= d;
 979                      changed = 1;
 980                  }
 981                  /* recalculate the coefficients */
 982                  a = ge->iy1 - ge->prev->iy3;
 983                  b = ge->ix1 - ge->prev->ix3;
 984                  kk1 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
 985                  a = ge->iy3 - ge->prev->iy3;
 986                  b = ge->ix3 - ge->prev->ix3;
 987                  kk = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
 988              }
 989          }
 990          if (rdir > 0) {
 991              if (kk2 < kk) {    /* the rear end has problems */
 992                  if (c * (ge->ix2 - ge->ix1) > 0) {
 993                      ge->ix2 -= c;
 994                      changed = 1;
 995                  } if (d * (ge->iy3 - ge->iy2) > 0) {
 996                      ge->iy2 += d;
 997                      changed = 1;
 998                  }
 999                  /* recalculate the coefficients */
1000                  a = ge->iy3 - ge->prev->iy3;
1001                  b = ge->ix3 - ge->prev->ix3;
1002                  kk = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
1003                  a = ge->iy3 - ge->iy2;
1004                  b = ge->ix3 - ge->ix2;
1005                  kk2 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
1006              }
1007          } else if (rdir < 0) {
1008              if (kk2 > kk) {    /* the rear end has problems */
1009                  if (c * (ge->ix3 - ge->ix2) > 0) {
1010                      ge->ix2 += c;
1011                      changed = 1;
1012                  } if (d * (ge->iy2 - ge->iy1) > 0) {
1013                      ge->iy2 -= d;
1014                      changed = 1;
1015                  }
1016                  /* recalculate the coefficients */
1017                  a = ge->iy3 - ge->prev->iy3;
1018                  b = ge->ix3 - ge->prev->ix3;
1019                  kk = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
1020                  a = ge->iy3 - ge->iy2;
1021                  b = ge->ix3 - ge->ix2;
1022                  kk2 = fabs(a == 0 ? (b == 0 ? 1. : 100000.) : ((double) b / (double) a));
1023              }
1024          }
1025      }
1026      fixcvends(ge);
1027  }
1028  
1029  /* Get the directions of ends of curve for further usage */
1030  
1031  /* expects that the previous element is also float */
1032  
1033  static int
1034  fgetcvdir(
1035       GENTRY * ge
1036  )
1037  {
1038      double          a, b;
1039      double          k, k1, k2;
1040      int             dir = 0;
1041  
1042      if( !(ge->flags & GEF_FLOAT) ) {
1043          fprintf(stderr, "**! fgetcvdir(0x%x) on int entry, ABORT\n", ge);
1044          abort(); /* dump core */
1045      }
1046  
1047      a = fabs(ge->fy3 - ge->prev->fy3);
1048      b = fabs(ge->fx3 - ge->prev->fx3);
1049      k = a < FEPS ? (b < FEPS ? 1. : 100000.) : ( b / a);
1050  
1051      a = fabs(ge->fy1 - ge->prev->fy3);
1052      b = fabs(ge->fx1 - ge->prev->fx3);
1053      if(a < FEPS) {
1054          if(b < FEPS) {
1055              a = fabs(ge->fy2 - ge->prev->fy3);
1056              b = fabs(ge->fx2 - ge->prev->fx3);
1057              k1 = a < FEPS ? (b < FEPS ? k : 100000.) : ( b / a);
1058          } else
1059              k1 = FBIGVAL;
1060      } else
1061          k1 = b / a;
1062  
1063      a = fabs(ge->fy3 - ge->fy2);
1064      b = fabs(ge->fx3 - ge->fx2);
1065      if(a < FEPS) {
1066          if(b < FEPS) {
1067              a = fabs(ge->fy3 - ge->fy1);
1068              b = fabs(ge->fx3 - ge->fx1);
1069              k2 = a < FEPS ? (b < FEPS ? k : 100000.) : ( b / a);
1070          } else
1071              k2 = FBIGVAL;
1072      } else
1073          k2 = b / a;
1074  
1075      if(fabs(k1-k) < 0.0001)
1076          dir |= CVDIR_FEQUAL;
1077      else if (k1 < k)
1078          dir |= CVDIR_FUP;
1079      else
1080          dir |= CVDIR_FDOWN;
1081  
1082      if(fabs(k2-k) < 0.0001)
1083          dir |= CVDIR_REQUAL;
1084      else if (k2 > k)
1085          dir |= CVDIR_RUP;
1086      else
1087          dir |= CVDIR_RDOWN;
1088  
1089      return dir;
1090  }
1091  
1092  
1093  /* expects that the previous element is also int */
1094  
1095  static int
1096  igetcvdir(
1097       GENTRY * ge
1098  )
1099  {
1100      int             a, b;
1101      double          k, k1, k2;
1102      int             dir = 0;
1103  
1104      if(ge->flags & GEF_FLOAT) {
1105          fprintf(stderr, "**! igetcvdir(0x%x) on floating entry, ABORT\n", ge);
1106          abort(); /* dump core */
1107      }
1108  
1109      a = ge->iy3 - ge->prev->iy3;
1110      b = ge->ix3 - ge->prev->ix3;
1111      k = (a == 0) ? (b == 0 ? 1. : 100000.) : fabs((double) b / (double) a);
1112  
1113      a = ge->iy1 - ge->prev->iy3;
1114      b = ge->ix1 - ge->prev->ix3;
1115      if(a == 0) {
1116          if(b == 0) {
1117              a = ge->iy2 - ge->prev->iy3;
1118              b = ge->ix2 - ge->prev->ix3;
1119              k1 = (a == 0) ? (b == 0 ? k : 100000.) : fabs((double) b / (double) a);
1120          } else
1121              k1 = FBIGVAL;
1122      } else
1123          k1 = fabs((double) b / (double) a);
1124  
1125      a = ge->iy3 - ge->iy2;
1126      b = ge->ix3 - ge->ix2;
1127      if(a == 0) {
1128          if(b == 0) {
1129              a = ge->iy3 - ge->iy1;
1130              b = ge->ix3 - ge->ix1;
1131              k2 = (a == 0) ? (b == 0 ? k : 100000.) : fabs((double) b / (double) a);
1132          } else
1133              k2 = FBIGVAL;
1134      } else
1135          k2 = fabs((double) b / (double) a);
1136  
1137      if(fabs(k1-k) < 0.0001)
1138          dir |= CVDIR_FEQUAL;
1139      else if (k1 < k)
1140          dir |= CVDIR_FUP;
1141      else
1142          dir |= CVDIR_FDOWN;
1143  
1144      if(fabs(k2-k) < 0.0001)
1145          dir |= CVDIR_REQUAL;
1146      else if (k2 > k)
1147          dir |= CVDIR_RUP;
1148      else
1149          dir |= CVDIR_RDOWN;
1150  
1151      return dir;
1152  }
1153  
1154  #if 0
1155  /* a function just to test the work of fixcvdir() */
1156  static void
1157  testfixcvdir(
1158           GLYPH * g
1159  )
1160  {
1161      GENTRY         *ge;
1162      int             dir;
1163  
1164      for (ge = g->entries; ge != 0; ge = ge->next) {
1165          if (ge->type == GE_CURVE) {
1166              dir = igetcvdir(ge);
1167              fixcvdir(ge, dir);
1168          }
1169      }
1170  }
1171  #endif
1172  
1173  static int
1174  iround(
1175      double val
1176  )
1177  {
1178      return (int) (val > 0 ? val + 0.5 : val - 0.5);
1179  }
1180      
1181  /* for debugging - dump the glyph
1182   * mark with a star the entries from start to end inclusive
1183   * (start == NULL means don't mark any, end == NULL means to the last)
1184   */
1185  
1186  void
1187  dumppaths(
1188      GLYPH *g,
1189      GENTRY *start,
1190      GENTRY *end
1191  )
1192  {
1193      GENTRY *ge;
1194      int i;
1195      char mark=' ';
1196  
1197      fprintf(stderr, "Glyph %s:\n", g->name);
1198  
1199      /* now do the conversion */
1200      for(ge = g->entries; ge != 0; ge = ge->next) {
1201          if(ge == start)
1202              mark = '*';
1203          fprintf(stderr, " %c %8x", mark, ge);
1204          switch(ge->type) {
1205          case GE_MOVE:
1206          case GE_LINE:
1207              if(ge->flags & GEF_FLOAT)
1208                  fprintf(stderr," %c float (%g, %g)\n", ge->type, ge->fx3, ge->fy3);
1209              else
1210                  fprintf(stderr," %c int (%d, %d)\n", ge->type, ge->ix3, ge->iy3);
1211              break;
1212          case GE_CURVE:
1213              if(ge->flags & GEF_FLOAT) {
1214                  fprintf(stderr," C float ");
1215                  for(i=0; i<3; i++)
1216                      fprintf(stderr,"(%g, %g) ", ge->fxn[i], ge->fyn[i]);
1217                  fprintf(stderr,"\n");
1218              } else {
1219                  fprintf(stderr," C int ");
1220                  for(i=0; i<3; i++)
1221                      fprintf(stderr,"(%d, %d) ", ge->ixn[i], ge->iyn[i]);
1222                  fprintf(stderr,"\n");
1223              }
1224              break;
1225          default:
1226              fprintf(stderr, " %c\n", ge->type);
1227              break;
1228          }
1229          if(ge == end)
1230              mark = ' ';
1231      }
1232  }
1233  
1234  /*
1235   * Routine that converts all entries in the path from float to int
1236   */
1237  
1238  void
1239  pathtoint(
1240      GLYPH *g
1241  )
1242  {
1243      GENTRY *ge;
1244      int x[3], y[3];
1245      int i;
1246  
1247  
1248      if(ISDBG(TOINT))
1249          fprintf(stderr, "TOINT: glyph %s\n", g->name);
1250      assertisfloat(g, "converting path to int\n");
1251  
1252      fdelsmall(g, 1.0); /* get rid of sub-pixel contours */
1253      assertpath(g->entries, __FILE__, __LINE__, g->name);
1254  
1255      /* 1st pass, collect the directions of the curves: have
1256       * to do that in advance, while everyting is float
1257       */
1258      for(ge = g->entries; ge != 0; ge = ge->next) {
1259          if( !(ge->flags & GEF_FLOAT) ) {
1260              fprintf(stderr, "**! glyphs %s has int entry, found in conversion to int\n",
1261                  g->name);
1262              exit(1);
1263          }
1264          if(ge->type == GE_CURVE) {
1265              ge->dir = fgetcvdir(ge);
1266          }
1267      }
1268  
1269      /* now do the conversion */
1270      for(ge = g->entries; ge != 0; ge = ge->next) {
1271          switch(ge->type) {
1272          case GE_MOVE:
1273          case GE_LINE:
1274              if(ISDBG(TOINT))
1275                  fprintf(stderr," %c float x=%g y=%g\n", ge->type, ge->fx3, ge->fy3);
1276              x[0] = iround(ge->fx3);
1277              y[0] = iround(ge->fy3);
1278              for(i=0; i<3; i++) { /* put some valid values everywhere, for convenience */
1279                  ge->ixn[i] = x[0];
1280                  ge->iyn[i] = y[0];
1281              }
1282              if(ISDBG(TOINT))
1283                  fprintf(stderr,"   int   x=%d y=%d\n", ge->ix3, ge->iy3);
1284              break;
1285          case GE_CURVE:
1286              if(ISDBG(TOINT))
1287                  fprintf(stderr," %c float ", ge->type);
1288  
1289              for(i=0; i<3; i++) {
1290                  if(ISDBG(TOINT))
1291                      fprintf(stderr,"(%g, %g) ", ge->fxn[i], ge->fyn[i]);
1292                  x[i] = iround(ge->fxn[i]);
1293                  y[i] = iround(ge->fyn[i]);
1294              }
1295  
1296              if(ISDBG(TOINT))
1297                  fprintf(stderr,"\n   int   ");
1298  
1299              for(i=0; i<3; i++) {
1300                  ge->ixn[i] = x[i];
1301                  ge->iyn[i] = y[i];
1302                  if(ISDBG(TOINT))
1303                      fprintf(stderr,"(%d, %d) ", ge->ixn[i], ge->iyn[i]);
1304              }
1305              ge->flags &= ~GEF_FLOAT; /* for fixcvdir */
1306              fixcvdir(ge, ge->dir);
1307  
1308              if(ISDBG(TOINT)) {
1309                  fprintf(stderr,"\n   fixed ");
1310                  for(i=0; i<3; i++)
1311                      fprintf(stderr,"(%d, %d) ", ge->ixn[i], ge->iyn[i]);
1312                  fprintf(stderr,"\n");
1313              }
1314  
1315              break;
1316          }
1317          ge->flags &= ~GEF_FLOAT;
1318      }
1319      g->flags &= ~GF_FLOAT;
1320  }
1321  
1322  
1323  /* check whether we can fix up the curve to change its size by (dx,dy) */
1324  /* 0 means NO, 1 means YES */
1325  
1326  /* for float: if scaling would be under 10% */
1327  
1328  int
1329  fcheckcv(
1330      GENTRY * ge,
1331      double dx,
1332      double dy
1333  )
1334  {
1335      if( !(ge->flags & GEF_FLOAT) ) {
1336          fprintf(stderr, "**! fcheckcv(0x%x) on int entry, ABORT\n", ge);
1337          abort(); /* dump core */
1338      }
1339  
1340      if (ge->type != GE_CURVE)
1341          return 0;
1342  
1343      if( fabs(ge->fx3 - ge->prev->fx3) < fabs(dx) * 10 )
1344          return 0;
1345  
1346      if( fabs(ge->fy3 - ge->prev->fy3) < fabs(dy) * 10 )
1347          return 0;
1348  
1349      return 1;
1350  }
1351  
1352  /* for int: if won't create new zigzags at the ends */
1353  
1354  int
1355  icheckcv(
1356      GENTRY * ge,
1357      int dx,
1358      int dy
1359  )
1360  {
1361      int             xdep, ydep;
1362  
1363      if(ge->flags & GEF_FLOAT) {
1364          fprintf(stderr, "**! icheckcv(0x%x) on floating entry, ABORT\n", ge);
1365          abort(); /* dump core */
1366      }
1367  
1368      if (ge->type != GE_CURVE)
1369          return 0;
1370  
1371      xdep = ge->ix3 - ge->prev->ix3;
1372      ydep = ge->iy3 - ge->prev->iy3;
1373  
1374      if (ge->type == GE_CURVE
1375          && (xdep * (xdep + dx)) > 0
1376          && (ydep * (ydep + dy)) > 0) {
1377          return 1;
1378      } else
1379          return 0;
1380  }
1381  
1382  /* float connect the ends of open contours */
1383  
1384  void
1385  fclosepaths(
1386         GLYPH * g
1387  )
1388  {
1389      GENTRY         *ge, *fge, *xge, *nge;
1390      int             i;
1391  
1392      assertisfloat(g, "fclosepaths float\n");
1393  
1394      for (xge = g->entries; xge != 0; xge = xge->next) {
1395          if( xge->type != GE_PATH )
1396              continue;
1397  
1398          ge = xge->prev;
1399          if(ge == 0 || ge->type != GE_LINE && ge->type!= GE_CURVE) {
1400              fprintf(stderr, "**! Glyph %s got empty path\n",
1401                  g->name);
1402              exit(1);
1403          }
1404  
1405          fge = ge->frwd;
1406          if (fge->prev == 0 || fge->prev->type != GE_MOVE) {
1407              fprintf(stderr, "**! Glyph %s got strange beginning of path\n",
1408                  g->name);
1409              exit(1);
1410          }
1411          fge = fge->prev;
1412          if (fge->fx3 != ge->fx3 || fge->fy3 != ge->fy3) {
1413              /* we have to fix this open path */
1414  
1415              WARNING_4 fprintf(stderr, "Glyph %s got path open by dx=%g dy=%g\n",
1416              g->name, fge->fx3 - ge->fx3, fge->fy3 - ge->fy3);
1417  
1418  
1419              /* add a new line */
1420              nge = newgentry(GEF_FLOAT);
1421              (*nge) = (*ge);
1422              nge->fx3 = fge->fx3;
1423              nge->fy3 = fge->fy3;
1424              nge->type = GE_LINE;
1425  
1426              addgeafter(ge, nge);
1427  
1428              if (fabs(ge->fx3 - fge->fx3) <= 2 && fabs(ge->fy3 - fge->fy3) <= 2) {
1429                  /*
1430                   * small change, try to get rid of the new entry
1431                   */
1432  
1433                  double df[2];
1434  
1435                  for(i=0; i<2; i++) {
1436                      df[i] = ge->fpoints[i][2] - fge->fpoints[i][2];
1437                      df[i] = fclosegap(nge, nge, i, df[i], NULL);
1438                  }
1439  
1440                  if(df[0] == 0. && df[1] == 0.) {
1441                      /* closed gap successfully, remove the added entry */
1442                      freethisge(nge);
1443                  }
1444              }
1445          }
1446      }
1447  }
1448  
1449  void
1450  smoothjoints(
1451           GLYPH * g
1452  )
1453  {
1454      GENTRY         *ge, *ne;
1455      int             dx1, dy1, dx2, dy2, k;
1456      int             dir;
1457  
1458      return; /* this stuff seems to create problems */
1459  
1460      assertisint(g, "smoothjoints int");
1461  
1462      if (g->entries == 0)    /* nothing to do */
1463          return;
1464  
1465      for (ge = g->entries->next; ge != 0; ge = ge->next) {
1466          ne = ge->frwd;
1467  
1468          /*
1469           * although there should be no one-line path * and any path
1470           * must end with CLOSEPATH, * nobody can say for sure
1471           */
1472  
1473          if (ge == ne || ne == 0)
1474              continue;
1475  
1476          /* now handle various joints */
1477  
1478          if (ge->type == GE_LINE && ne->type == GE_LINE) {
1479              dx1 = ge->ix3 - ge->prev->ix3;
1480              dy1 = ge->iy3 - ge->prev->iy3;
1481              dx2 = ne->ix3 - ge->ix3;
1482              dy2 = ne->iy3 - ge->iy3;
1483  
1484              /* check whether they have the same direction */
1485              /* and the same slope */
1486              /* then we can join them into one line */
1487  
1488              if (dx1 * dx2 >= 0 && dy1 * dy2 >= 0 && dx1 * dy2 == dy1 * dx2) {
1489                  /* extend the previous line */
1490                  ge->ix3 = ne->ix3;
1491                  ge->iy3 = ne->iy3;
1492  
1493                  /* and get rid of the next line */
1494                  freethisge(ne);
1495              }
1496          } else if (ge->type == GE_LINE && ne->type == GE_CURVE) {
1497              fixcvends(ne);
1498  
1499              dx1 = ge->ix3 - ge->prev->ix3;
1500              dy1 = ge->iy3 - ge->prev->iy3;
1501              dx2 = ne->ix1 - ge->ix3;
1502              dy2 = ne->iy1 - ge->iy3;
1503  
1504              /* if the line is nearly horizontal and we can fix it */
1505              if (dx1 != 0 && 5 * abs(dy1) / abs(dx1) == 0
1506                  && icheckcv(ne, 0, -dy1)
1507                  && abs(dy1) <= 4) {
1508                  dir = igetcvdir(ne);
1509                  ge->iy3 -= dy1;
1510                  ne->iy1 -= dy1;
1511                  fixcvdir(ne, dir);
1512                  if (ge->next != ne)
1513                      ne->prev->iy3 -= dy1;
1514                  dy1 = 0;
1515              } else if (dy1 != 0 && 5 * abs(dx1) / abs(dy1) == 0
1516                     && icheckcv(ne, -dx1, 0)
1517                     && abs(dx1) <= 4) {
1518                  /* the same but vertical */
1519                  dir = igetcvdir(ne);
1520                  ge->ix3 -= dx1;
1521                  ne->ix1 -= dx1;
1522                  fixcvdir(ne, dir);
1523                  if (ge->next != ne)
1524                      ne->prev->ix3 -= dx1;
1525                  dx1 = 0;
1526              }
1527              /*
1528               * if line is horizontal and curve begins nearly
1529               * horizontally
1530               */
1531              if (dy1 == 0 && dx2 != 0 && 5 * abs(dy2) / abs(dx2) == 0) {
1532                  dir = igetcvdir(ne);
1533                  ne->iy1 -= dy2;
1534                  fixcvdir(ne, dir);
1535                  dy2 = 0;
1536              } else if (dx1 == 0 && dy2 != 0 && 5 * abs(dx2) / abs(dy2) == 0) {
1537                  /* the same but vertical */
1538                  dir = igetcvdir(ne);
1539                  ne->ix1 -= dx2;
1540                  fixcvdir(ne, dir);
1541                  dx2 = 0;
1542              }
1543          } else if (ge->type == GE_CURVE && ne->type == GE_LINE) {
1544              fixcvends(ge);
1545  
1546              dx1 = ge->ix3 - ge->ix2;
1547              dy1 = ge->iy3 - ge->iy2;
1548              dx2 = ne->ix3 - ge->ix3;
1549              dy2 = ne->iy3 - ge->iy3;
1550  
1551              /* if the line is nearly horizontal and we can fix it */
1552              if (dx2 != 0 && 5 * abs(dy2) / abs(dx2) == 0
1553                  && icheckcv(ge, 0, dy2)
1554                  && abs(dy2) <= 4) {
1555                  dir = igetcvdir(ge);
1556                  ge->iy3 += dy2;
1557                  ge->iy2 += dy2;
1558                  fixcvdir(ge, dir);
1559                  if (ge->next != ne)
1560                      ne->prev->iy3 += dy2;
1561                  dy2 = 0;
1562              } else if (dy2 != 0 && 5 * abs(dx2) / abs(dy2) == 0
1563                     && icheckcv(ge, dx2, 0)
1564                     && abs(dx2) <= 4) {
1565                  /* the same but vertical */
1566                  dir = igetcvdir(ge);
1567                  ge->ix3 += dx2;
1568                  ge->ix2 += dx2;
1569                  fixcvdir(ge, dir);
1570                  if (ge->next != ne)
1571                      ne->prev->ix3 += dx2;
1572                  dx2 = 0;
1573              }
1574              /*
1575               * if line is horizontal and curve ends nearly
1576               * horizontally
1577               */
1578              if (dy2 == 0 && dx1 != 0 && 5 * abs(dy1) / abs(dx1) == 0) {
1579                  dir = igetcvdir(ge);
1580                  ge->iy2 += dy1;
1581                  fixcvdir(ge, dir);
1582                  dy1 = 0;
1583              } else if (dx2 == 0 && dy1 != 0 && 5 * abs(dx1) / abs(dy1) == 0) {
1584                  /* the same but vertical */
1585                  dir = igetcvdir(ge);
1586                  ge->ix2 += dx1;
1587                  fixcvdir(ge, dir);
1588                  dx1 = 0;
1589              }
1590          } else if (ge->type == GE_CURVE && ne->type == GE_CURVE) {
1591              fixcvends(ge);
1592              fixcvends(ne);
1593  
1594              dx1 = ge->ix3 - ge->ix2;
1595              dy1 = ge->iy3 - ge->iy2;
1596              dx2 = ne->ix1 - ge->ix3;
1597              dy2 = ne->iy1 - ge->iy3;
1598  
1599              /*
1600               * check if we have a rather smooth joint at extremal
1601               * point
1602               */
1603              /* left or right extremal point */
1604              if (abs(dx1) <= 4 && abs(dx2) <= 4
1605                  && dy1 != 0 && 5 * abs(dx1) / abs(dy1) == 0
1606                  && dy2 != 0 && 5 * abs(dx2) / abs(dy2) == 0
1607                  && (ge->iy3 < ge->prev->iy3 && ne->iy3 < ge->iy3
1608                  || ge->iy3 > ge->prev->iy3 && ne->iy3 > ge->iy3)
1609                && (ge->ix3 - ge->prev->ix3) * (ne->ix3 - ge->ix3) < 0
1610                  ) {
1611                  dir = igetcvdir(ge);
1612                  ge->ix2 += dx1;
1613                  dx1 = 0;
1614                  fixcvdir(ge, dir);
1615                  dir = igetcvdir(ne);
1616                  ne->ix1 -= dx2;
1617                  dx2 = 0;
1618                  fixcvdir(ne, dir);
1619              }
1620              /* top or down extremal point */
1621              else if (abs(dy1) <= 4 && abs(dy2) <= 4
1622                   && dx1 != 0 && 5 * abs(dy1) / abs(dx1) == 0
1623                   && dx2 != 0 && 5 * abs(dy2) / abs(dx2) == 0
1624                   && (ge->ix3 < ge->prev->ix3 && ne->ix3 < ge->ix3
1625                  || ge->ix3 > ge->prev->ix3 && ne->ix3 > ge->ix3)
1626                   && (ge->iy3 - ge->prev->iy3) * (ne->iy3 - ge->iy3) < 0
1627                  ) {
1628                  dir = igetcvdir(ge);
1629                  ge->iy2 += dy1;
1630                  dy1 = 0;
1631                  fixcvdir(ge, dir);
1632                  dir = igetcvdir(ne);
1633                  ne->iy1 -= dy2;
1634                  dy2 = 0;
1635                  fixcvdir(ne, dir);
1636              }
1637              /* or may be we just have a smooth junction */
1638              else if (dx1 * dx2 >= 0 && dy1 * dy2 >= 0
1639                   && 10 * abs(k = abs(dx1 * dy2) - abs(dy1 * dx2)) < (abs(dx1 * dy2) + abs(dy1 * dx2))) {
1640                  int             tries[6][4];
1641                  int             results[6];
1642                  int             i, b;
1643  
1644                  /* build array of changes we are going to try */
1645                  /* uninitalized entries are 0 */
1646                  if (k > 0) {
1647                      static int      t1[6][4] = {
1648                          {0, 0, 0, 0},
1649                          {-1, 0, 1, 0},
1650                          {-1, 0, 0, 1},
1651                          {0, -1, 1, 0},
1652                          {0, -1, 0, 1},
1653                      {-1, -1, 1, 1}};
1654                      memcpy(tries, t1, sizeof tries);
1655                  } else {
1656                      static int      t1[6][4] = {
1657                          {0, 0, 0, 0},
1658                          {1, 0, -1, 0},
1659                          {1, 0, 0, -1},
1660                          {0, 1, -1, 0},
1661                          {0, 1, 0, -1},
1662                      {1, 1, -1, -1}};
1663                      memcpy(tries, t1, sizeof tries);
1664                  }
1665  
1666                  /* now try the changes */
1667                  results[0] = abs(k);
1668                  for (i = 1; i < 6; i++) {
1669                      results[i] = abs((abs(dx1) + tries[i][0]) * (abs(dy2) + tries[i][1]) -
1670                               (abs(dy1) + tries[i][2]) * (abs(dx2) + tries[i][3]));
1671                  }
1672  
1673                  /* and find the best try */
1674                  k = abs(k);
1675                  b = 0;
1676                  for (i = 1; i < 6; i++)
1677                      if (results[i] < k) {
1678                          k = results[i];
1679                          b = i;
1680                      }
1681                  /* and finally apply it */
1682                  if (dx1 < 0)
1683                      tries[b][0] = -tries[b][0];
1684                  if (dy2 < 0)
1685                      tries[b][1] = -tries[b][1];
1686                  if (dy1 < 0)
1687                      tries[b][2] = -tries[b][2];
1688                  if (dx2 < 0)
1689                      tries[b][3] = -tries[b][3];
1690  
1691                  dir = igetcvdir(ge);
1692                  ge->ix2 -= tries[b][0];
1693                  ge->iy2 -= tries[b][2];
1694                  fixcvdir(ge, dir);
1695                  dir = igetcvdir(ne);
1696                  ne->ix1 += tries[b][3];
1697                  ne->iy1 += tries[b][1];
1698                  fixcvdir(ne, dir);
1699              }
1700          }
1701      }
1702  }
1703  
1704  /* debugging: print out stems of a glyph */
1705  static void
1706  debugstems(
1707         char *name,
1708         STEM * hstems,
1709         int nhs,
1710         STEM * vstems,
1711         int nvs
1712  )
1713  {
1714      int             i;
1715  
1716      fprintf(pfa_file, "%% %s\n", name);
1717      fprintf(pfa_file, "%% %d horizontal stems:\n", nhs);
1718      for (i = 0; i < nhs; i++)
1719          fprintf(pfa_file, "%% %3d    %d (%d...%d) %c %c%c%c%c\n", i, hstems[i].value,
1720              hstems[i].from, hstems[i].to,
1721              ((hstems[i].flags & ST_UP) ? 'U' : 'D'),
1722              ((hstems[i].flags & ST_END) ? 'E' : '-'),
1723              ((hstems[i].flags & ST_FLAT) ? 'F' : '-'),
1724              ((hstems[i].flags & ST_ZONE) ? 'Z' : ' '),
1725              ((hstems[i].flags & ST_TOPZONE) ? 'T' : ' '));
1726      fprintf(pfa_file, "%% %d vertical stems:\n", nvs);
1727      for (i = 0; i < nvs; i++)
1728          fprintf(pfa_file, "%% %3d    %d (%d...%d) %c %c%c\n", i, vstems[i].value,
1729              vstems[i].from, vstems[i].to,
1730              ((vstems[i].flags & ST_UP) ? 'U' : 'D'),
1731              ((vstems[i].flags & ST_END) ? 'E' : '-'),
1732              ((vstems[i].flags & ST_FLAT) ? 'F' : '-'));
1733  }
1734  
1735  /* add pseudo-stems for the limits of the Blue zones to the stem array */
1736  static int
1737  addbluestems(
1738      STEM *s,
1739      int n
1740  )
1741  {
1742      int i;
1743  
1744      for(i=0; i<nblues && i<2; i+=2) { /* baseline */
1745          s[n].value=bluevalues[i];
1746          s[n].flags=ST_UP|ST_ZONE;
1747          /* don't overlap with anything */
1748          s[n].origin=s[n].from=s[n].to= -10000+i;
1749          n++;
1750          s[n].value=bluevalues[i+1];
1751          s[n].flags=ST_ZONE;
1752          /* don't overlap with anything */
1753          s[n].origin=s[n].from=s[n].to= -10000+i+1;
1754          n++;
1755      }
1756      for(i=2; i<nblues; i+=2) { /* top zones */
1757          s[n].value=bluevalues[i];
1758          s[n].flags=ST_UP|ST_ZONE|ST_TOPZONE;
1759          /* don't overlap with anything */
1760          s[n].origin=s[n].from=s[n].to= -10000+i;
1761          n++;
1762          s[n].value=bluevalues[i+1];
1763          s[n].flags=ST_ZONE|ST_TOPZONE;
1764          /* don't overlap with anything */
1765          s[n].origin=s[n].from=s[n].to= -10000+i+1;
1766          n++;
1767      }
1768      for(i=0; i<notherb; i+=2) { /* bottom zones */
1769          s[n].value=otherblues[i];
1770          s[n].flags=ST_UP|ST_ZONE;
1771          /* don't overlap with anything */
1772          s[n].origin=s[n].from=s[n].to= -10000+i+nblues;
1773          n++;
1774          s[n].value=otherblues[i+1];
1775          s[n].flags=ST_ZONE;
1776          /* don't overlap with anything */
1777          s[n].origin=s[n].from=s[n].to= -10000+i+1+nblues;
1778          n++;
1779      }
1780      return n;
1781  }
1782  
1783  /* sort stems in array */
1784  static void
1785  sortstems(
1786        STEM * s,
1787        int n
1788  )
1789  {
1790      int             i, j;
1791      STEM            x;
1792  
1793  
1794      /* a simple sorting */
1795      /* hm, the ordering criteria are not quite simple :-) 
1796       * if the values are tied
1797       * ST_UP always goes under not ST_UP
1798       * ST_ZONE goes on the most outer side
1799       * ST_END goes towards inner side after ST_ZONE
1800       * ST_FLAT goes on the inner side
1801       */
1802  
1803      for (i = 0; i < n; i++)
1804          for (j = i + 1; j < n; j++) {
1805              if(s[i].value < s[j].value)
1806                  continue;
1807              if(s[i].value == s[j].value) {
1808                  if( (s[i].flags & ST_UP) < (s[j].flags & ST_UP) )
1809                      continue;
1810                  if( (s[i].flags & ST_UP) == (s[j].flags & ST_UP) ) {
1811                      if( s[i].flags & ST_UP ) {
1812                          if(
1813                          (s[i].flags & (ST_ZONE|ST_FLAT|ST_END) ^ ST_FLAT)
1814                              >
1815                          (s[j].flags & (ST_ZONE|ST_FLAT|ST_END) ^ ST_FLAT)
1816                          )
1817                              continue;
1818                      } else {
1819                          if(
1820                          (s[i].flags & (ST_ZONE|ST_FLAT|ST_END) ^ ST_FLAT)
1821                              <
1822                          (s[j].flags & (ST_ZONE|ST_FLAT|ST_END) ^ ST_FLAT)
1823                          )
1824                              continue;
1825                      }
1826                  }
1827              }
1828              x = s[j];
1829              s[j] = s[i];
1830              s[i] = x;
1831          }
1832  }
1833  
1834  /* check whether two stem borders overlap */
1835  
1836  static int
1837  stemoverlap(
1838          STEM * s1,
1839          STEM * s2
1840  )
1841  {
1842      int             result;
1843  
1844      if (s1->from <= s2->from && s1->to >= s2->from
1845          || s2->from <= s1->from && s2->to >= s1->from)
1846          result = 1;
1847      else
1848          result = 0;
1849  
1850      if (ISDBG(STEMOVERLAP))
1851          fprintf(pfa_file, "%% overlap %d(%d..%d)x%d(%d..%d)=%d\n",
1852              s1->value, s1->from, s1->to, s2->value, s2->from, s2->to, result);
1853      return result;
1854  }
1855  
1856  /* 
1857   * check if the stem [border] is in an appropriate blue zone
1858   * (currently not used)
1859   */
1860  
1861  static int
1862  steminblue(
1863      STEM *s
1864  )
1865  {
1866      int i, val;
1867  
1868      val=s->value;
1869      if(s->flags & ST_UP) {
1870          /* painted size up, look at lower zones */
1871          if(nblues>=2 && val>=bluevalues[0] && val<=bluevalues[1] )
1872              return 1;
1873          for(i=0; i<notherb; i++) {
1874              if( val>=otherblues[i] && val<=otherblues[i+1] )
1875                  return 1;
1876          }
1877      } else {
1878          /* painted side down, look at upper zones */
1879          for(i=2; i<nblues; i++) {
1880              if( val>=bluevalues[i] && val<=bluevalues[i+1] )
1881                  return 1;
1882          }
1883      }
1884  
1885      return 0;
1886  }
1887  
1888  /* mark the outermost stem [borders] in the blue zones */
1889  
1890  static void
1891  markbluestems(
1892      STEM *s,
1893      int nold
1894  )
1895  {
1896      int i, j, a, b, c;
1897      /*
1898       * traverse the list of Blue Values, mark the lowest upper
1899       * stem in each bottom zone and the topmost lower stem in
1900       * each top zone with ST_BLUE
1901       */
1902  
1903      /* top zones */
1904      for(i=2; i<nblues; i+=2) {
1905          a=bluevalues[i]; b=bluevalues[i+1];
1906          if(ISDBG(BLUESTEMS))
1907              fprintf(pfa_file, "%% looking at blue zone %d...%d\n", a, b);
1908          for(j=nold-1; j>=0; j--) {
1909              if( s[j].flags & (ST_ZONE|ST_UP|ST_END) )
1910                  continue;
1911              c=s[j].value;
1912              if(c<a) /* too low */
1913                  break;
1914              if(c<=b) { /* found the topmost stem border */
1915                  /* mark all the stems with the same value */
1916                  if(ISDBG(BLUESTEMS))
1917                      fprintf(pfa_file, "%% found D BLUE at %d\n", s[j].value);
1918                  /* include ST_END values */
1919                  while( s[j+1].value==c && (s[j+1].flags & ST_ZONE)==0 )
1920                      j++;
1921                  s[j].flags |= ST_BLUE;
1922                  for(j--; j>=0 && s[j].value==c 
1923                          && (s[j].flags & (ST_UP|ST_ZONE))==0 ; j--)
1924                      s[j].flags |= ST_BLUE;
1925                  break;
1926              }
1927          }
1928      }
1929      /* baseline */
1930      if(nblues>=2) {
1931          a=bluevalues[0]; b=bluevalues[1];
1932          for(j=0; j<nold; j++) {
1933              if( (s[j].flags & (ST_ZONE|ST_UP|ST_END))!=ST_UP )
1934                  continue;
1935              c=s[j].value;
1936              if(c>b) /* too high */
1937                  break;
1938              if(c>=a) { /* found the lowest stem border */
1939                  /* mark all the stems with the same value */
1940                  if(ISDBG(BLUESTEMS))
1941                      fprintf(pfa_file, "%% found U BLUE at %d\n", s[j].value);
1942                  /* include ST_END values */
1943                  while( s[j-1].value==c && (s[j-1].flags & ST_ZONE)==0 )
1944                      j--;
1945                  s[j].flags |= ST_BLUE;
1946                  for(j++; j<nold && s[j].value==c
1947                          && (s[j].flags & (ST_UP|ST_ZONE))==ST_UP ; j++)
1948                      s[j].flags |= ST_BLUE;
1949                  break;
1950              }
1951          }
1952      }
1953      /* bottom zones: the logic is the same as for baseline */
1954      for(i=0; i<notherb; i+=2) {
1955          a=otherblues[i]; b=otherblues[i+1];
1956          for(j=0; j<nold; j++) {
1957              if( (s[j].flags & (ST_UP|ST_ZONE|ST_END))!=ST_UP )
1958                  continue;
1959              c=s[j].value;
1960              if(c>b) /* too high */
1961                  break;
1962              if(c>=a) { /* found the lowest stem border */
1963                  /* mark all the stems with the same value */
1964                  if(ISDBG(BLUESTEMS))
1965                      fprintf(pfa_file, "%% found U BLUE at %d\n", s[j].value);
1966                  /* include ST_END values */
1967                  while( s[j-1].value==c && (s[j-1].flags & ST_ZONE)==0 )
1968                      j--;
1969                  s[j].flags |= ST_BLUE;
1970                  for(j++; j<nold && s[j].value==c
1971                          && (s[j].flags & (ST_UP|ST_ZONE))==ST_UP ; j++)
1972                      s[j].flags |= ST_BLUE;
1973                  break;
1974              }
1975          }
1976      }
1977  }
1978  
1979  /* Eliminate invalid stems, join equivalent lines and remove nested stems
1980   * to build the main (non-substituted) set of stems.
1981   * XXX add consideration of the italic angle
1982   */
1983  static int
1984  joinmainstems(
1985        STEM * s,
1986        int nold,
1987        int useblues /* do we use the blue values ? */
1988  )
1989  {
1990  #define MAX_STACK    1000
1991      STEM            stack[MAX_STACK];
1992      int             nstack = 0;
1993      int             sbottom = 0;
1994      int             nnew;
1995      int             i, j, k;
1996      int             a, b, c, w1, w2, w3;
1997      int             fw, fd;
1998      /*
1999       * priority of the last found stem: 
2000       * 0 - nothing found yet 
2001       * 1 - has ST_END in it (one or more) 
2002       * 2 - has no ST_END and no ST_FLAT, can override only one stem 
2003       *     with priority 1 
2004       * 3 - has no ST_END and at least one ST_FLAT, can override one 
2005       *     stem with priority 2 or any number of stems with priority 1
2006       * 4 (handled separately) - has ST_BLUE, can override anything
2007       */
2008      int             readystem = 0;
2009      int             pri;
2010      int             nlps = 0;    /* number of non-committed
2011                       * lowest-priority stems */
2012  
2013  
2014      for (i = 0, nnew = 0; i < nold; i++) {
2015          if (s[i].flags & (ST_UP|ST_ZONE)) {
2016              if(s[i].flags & ST_BLUE) {
2017                  /* we just HAVE to use this value */
2018                  if (readystem)
2019                      nnew += 2;
2020                  readystem=0;
2021  
2022                  /* remember the list of Blue zone stems with the same value */
2023                  for(a=i, i++; i<nold && s[a].value==s[i].value
2024                      && (s[i].flags & ST_BLUE); i++)
2025                      {}
2026                  b=i; /* our range is a <= i < b */
2027                  c= -1; /* index of our best guess up to now */
2028                  pri=0;
2029                  /* try to find a match, don't cross blue zones */
2030                  for(; i<nold && (s[i].flags & ST_BLUE)==0; i++) {
2031                      if(s[i].flags & ST_UP) {
2032                          if(s[i].flags & ST_TOPZONE)
2033                              break;
2034                          else
2035                              continue;
2036                      }
2037                      for(j=a; j<b; j++) {
2038                          if(!stemoverlap(&s[j], &s[i]) )
2039                              continue;
2040                          /* consider priorities */
2041                          if( ( (s[j].flags|s[i].flags) & (ST_FLAT|ST_END) )==ST_FLAT ) {
2042                              c=i;
2043                              goto bluematch;
2044                          }
2045                          if( ((s[j].flags|s[i].flags) & ST_END)==0 )  {
2046                              if(pri < 2) {
2047                                  c=i; pri=2;
2048                              }
2049                          } else {
2050                              if(pri == 0) {
2051                                  c=i; pri=1;
2052                              }
2053                          }
2054                      }
2055                  }
2056              bluematch:
2057                  /* clean up the stack */
2058                  nstack=sbottom=0;
2059                  readystem=0;
2060                  /* add this stem */
2061                  s[nnew++]=s[a];
2062                  if(c<0) { /* make one-dot-wide stem */
2063                      if(nnew>=b) { /* have no free space */
2064                          for(j=nold; j>=b; j--) /* make free space */
2065                              s[j]=s[j-1];
2066                          b++;
2067                          nold++;
2068                      }
2069                      s[nnew]=s[a];
2070                      s[nnew].flags &= ~(ST_UP|ST_BLUE);
2071                      nnew++;
2072                      i=b-1;
2073                  } else {
2074                      s[nnew++]=s[c];
2075                      i=c; /* skip up to this point */
2076                  }
2077                  if (ISDBG(MAINSTEMS))
2078                      fprintf(pfa_file, "%% +stem %d...%d U BLUE\n",
2079                          s[nnew-2].value, s[nnew-1].value);
2080              } else {
2081                  if (nstack >= MAX_STACK) {
2082                      WARNING_1 fprintf(stderr, "Warning: **** converter's stem stack overflow ****\n");
2083                      nstack = 0;
2084                  }
2085                  stack[nstack++] = s[i];
2086              }
2087          } else if(s[i].flags & ST_BLUE) {
2088              /* again, we just HAVE to use this value */
2089              if (readystem)
2090                  nnew += 2;
2091              readystem=0;
2092  
2093              /* remember the list of Blue zone stems with the same value */
2094              for(a=i, i++; i<nold && s[a].value==s[i].value
2095                  && (s[i].flags & ST_BLUE); i++)
2096                  {}
2097              b=i; /* our range is a <= i < b */
2098              c= -1; /* index of our best guess up to now */
2099              pri=0;
2100              /* try to find a match */
2101              for (i = nstack - 1; i >= 0; i--) {
2102                  if( (stack[i].flags & ST_UP)==0 ) {
2103                      if( (stack[i].flags & (ST_ZONE|ST_TOPZONE))==ST_ZONE )
2104                          break;
2105                      else
2106                          continue;
2107                  }
2108                  for(j=a; j<b; j++) {
2109                      if(!stemoverlap(&s[j], &stack[i]) )
2110                          continue;
2111                      /* consider priorities */
2112                      if( ( (s[j].flags|stack[i].flags) & (ST_FLAT|ST_END) )==ST_FLAT ) {
2113                          c=i;
2114                          goto bluedownmatch;
2115                      }
2116                      if( ((s[j].flags|stack[i].flags) & ST_END)==0 )  {
2117                          if(pri < 2) {
2118                              c=i; pri=2;
2119                          }
2120                      } else {
2121                          if(pri == 0) {
2122                              c=i; pri=1;
2123                          }
2124                      }
2125                  }
2126              }
2127          bluedownmatch:
2128              /* if found no match make a one-dot-wide stem */
2129              if(c<0) {
2130                  c=0;
2131                  stack[0]=s[b-1];
2132                  stack[0].flags |= ST_UP;
2133                  stack[0].flags &= ~ST_BLUE;
2134              }
2135              /* remove all the stems conflicting with this one */
2136              readystem=0;
2137              for(j=nnew-2; j>=0; j-=2) {
2138                  if (ISDBG(MAINSTEMS))
2139                      fprintf(pfa_file, "%% ?stem %d...%d -- %d\n",
2140                          s[j].value, s[j+1].value, stack[c].value);
2141                  if(s[j+1].value < stack[c].value) /* no conflict */
2142                      break;
2143                  if(s[j].flags & ST_BLUE) {
2144                      /* oops, we don't want to spoil other blue zones */
2145                      stack[c].value=s[j+1].value+1;
2146                      break;
2147                  }
2148                  if( (s[j].flags|s[j+1].flags) & ST_END ) {
2149                      if (ISDBG(MAINSTEMS))
2150                          fprintf(pfa_file, "%% -stem %d...%d p=1\n",
2151                              s[j].value, s[j+1].value);
2152                      continue; /* pri==1, silently discard it */
2153                  }
2154                  /* we want to discard no nore than 2 stems of pri>=2 */
2155                  if( ++readystem > 2 ) {
2156                      /* change our stem to not conflict */
2157                      stack[c].value=s[j+1].value+1;
2158                      break;
2159                  } else {
2160                      if (ISDBG(MAINSTEMS))
2161                          fprintf(pfa_file, "%% -stem %d...%d p>=2\n",
2162                              s[j].value, s[j+1].value);
2163                      continue;
2164                  }
2165              }
2166              nnew=j+2;
2167              /* add this stem */
2168              if(nnew>=b-1) { /* have no free space */
2169                  for(j=nold; j>=b-1; j--) /* make free space */
2170                      s[j]=s[j-1];
2171                  b++;
2172                  nold++;
2173              }
2174              s[nnew++]=stack[c];
2175              s[nnew++]=s[b-1];
2176              /* clean up the stack */
2177              nstack=sbottom=0;
2178              readystem=0;
2179              /* set the next position to search */
2180              i=b-1;
2181              if (ISDBG(MAINSTEMS))
2182                  fprintf(pfa_file, "%% +stem %d...%d D BLUE\n",
2183                      s[nnew-2].value, s[nnew-1].value);
2184          } else if (nstack > 0) {
2185  
2186              /*
2187               * check whether our stem overlaps with anything in
2188               * stack
2189               */
2190              for (j = nstack - 1; j >= sbottom; j--) {
2191                  if (s[i].value <= stack[j].value)
2192                      break;
2193                  if (stack[j].flags & ST_ZONE)
2194                      continue;
2195  
2196                  if ((s[i].flags & ST_END)
2197                      || (stack[j].flags & ST_END))
2198                      pri = 1;
2199                  else if ((s[i].flags & ST_FLAT)
2200                       || (stack[j].flags & ST_FLAT))
2201                      pri = 3;
2202                  else
2203                      pri = 2;
2204  
2205                  if (pri < readystem && s[nnew + 1].value >= stack[j].value
2206                      || !stemoverlap(&stack[j], &s[i]))
2207                      continue;
2208  
2209                  if (readystem > 1 && s[nnew + 1].value < stack[j].value) {
2210                      nnew += 2;
2211                      readystem = 0;
2212                      nlps = 0;
2213                  }
2214                  /*
2215                   * width of the previous stem (if it's
2216                   * present)
2217                   */
2218                  w1 = s[nnew + 1].value - s[nnew].value;
2219  
2220                  /* width of this stem */
2221                  w2 = s[i].value - stack[j].value;
2222  
2223                  if (readystem == 0) {
2224                      /* nothing yet, just add a new stem */
2225                      s[nnew] = stack[j];
2226                      s[nnew + 1] = s[i];
2227                      readystem = pri;
2228                      if (pri == 1)
2229                          nlps = 1;
2230                      else if (pri == 2)
2231                          sbottom = j;
2232                      else {
2233                          sbottom = j + 1;
2234                          while (sbottom < nstack
2235                                 && stack[sbottom].value <= stack[j].value)
2236                              sbottom++;
2237                      }
2238                      if (ISDBG(MAINSTEMS))
2239                          fprintf(pfa_file, "%% +stem %d...%d p=%d n=%d\n",
2240                              stack[j].value, s[i].value, pri, nlps);
2241                  } else if (pri == 1) {
2242                      if (stack[j].value > s[nnew + 1].value) {
2243                          /*
2244                           * doesn't overlap with the
2245                           * previous one
2246                           */
2247                          nnew += 2;
2248                          nlps++;
2249                          s[nnew] = stack[j];
2250                          s[nnew + 1] = s[i];
2251                          if (ISDBG(MAINSTEMS))
2252                              fprintf(pfa_file, "%% +stem %d...%d p=%d n=%d\n",
2253                                  stack[j].value, s[i].value, pri, nlps);
2254                      } else if (w2 < w1) {
2255                          /* is narrower */
2256                          s[nnew] = stack[j];
2257                          s[nnew + 1] = s[i];
2258                          if (ISDBG(MAINSTEMS))
2259                              fprintf(pfa_file, "%% /stem %d...%d p=%d n=%d %d->%d\n",
2260                                  stack[j].value, s[i].value, pri, nlps, w1, w2);
2261                      }
2262                  } else if (pri == 2) {
2263                      if (readystem == 2) {
2264                          /* choose the narrower stem */
2265                          if (w1 > w2) {
2266                              s[nnew] = stack[j];
2267                              s[nnew + 1] = s[i];
2268                              sbottom = j;
2269                              if (ISDBG(MAINSTEMS))
2270                                  fprintf(pfa_file, "%% /stem %d...%d p=%d n=%d\n",
2271                                      stack[j].value, s[i].value, pri, nlps);
2272                          }
2273                          /* else readystem==1 */
2274                      } else if (stack[j].value > s[nnew + 1].value) {
2275                          /*
2276                           * value doesn't overlap with
2277                           * the previous one
2278                           */
2279                          nnew += 2;
2280                          nlps = 0;
2281                          s[nnew] = stack[j];
2282                          s[nnew + 1] = s[i];
2283                          sbottom = j;
2284                          readystem = pri;
2285                          if (ISDBG(MAINSTEMS))
2286                              fprintf(pfa_file, "%% +stem %d...%d p=%d n=%d\n",
2287                                  stack[j].value, s[i].value, pri, nlps);
2288                      } else if (nlps == 1
2289                             || stack[j].value > s[nnew - 1].value) {
2290                          /*
2291                           * we can replace the top
2292                           * stem
2293                           */
2294                          nlps = 0;
2295                          s[nnew] = stack[j];
2296                          s[nnew + 1] = s[i];
2297                          readystem = pri;
2298                          sbottom = j;
2299                          if (ISDBG(MAINSTEMS))
2300                              fprintf(pfa_file, "%% /stem %d...%d p=%d n=%d\n",
2301                                  stack[j].value, s[i].value, pri, nlps);
2302                      }
2303                  } else if (readystem == 3) {    /* that means also
2304                                   * pri==3 */
2305                      /* choose the narrower stem */
2306                      if (w1 > w2) {
2307                          s[nnew] = stack[j];
2308                          s[nnew + 1] = s[i];
2309                          sbottom = j + 1;
2310                          while (sbottom < nstack
2311                                 && stack[sbottom].value <= stack[j].value)
2312                              sbottom++;
2313                          if (ISDBG(MAINSTEMS))
2314                              fprintf(pfa_file, "%% /stem %d...%d p=%d n=%d\n",
2315                                  stack[j].value, s[i].value, pri, nlps);
2316                      }
2317                  } else if (pri == 3) {
2318                      /*
2319                       * we can replace as many stems as
2320                       * neccessary
2321                       */
2322                      nnew += 2;
2323                      while (nnew > 0 && s[nnew - 1].value >= stack[j].value) {
2324                          nnew -= 2;
2325                          if (ISDBG(MAINSTEMS))
2326                              fprintf(pfa_file, "%% -stem %d..%d\n",
2327                                  s[nnew].value, s[nnew + 1].value);
2328                      }
2329                      nlps = 0;
2330                      s[nnew] = stack[j];
2331                      s[nnew + 1] = s[i];
2332                      readystem = pri;
2333                      sbottom = j + 1;
2334                      while (sbottom < nstack
2335                             && stack[sbottom].value <= stack[j].value)
2336                          sbottom++;
2337                      if (ISDBG(MAINSTEMS))
2338                          fprintf(pfa_file, "%% +stem %d...%d p=%d n=%d\n",
2339                              stack[j].value, s[i].value, pri, nlps);
2340                  }
2341              }
2342          }
2343      }
2344      if (readystem)
2345          nnew += 2;
2346  
2347      /* change the 1-pixel-wide stems to 20-pixel-wide stems if possible 
2348       * the constant 20 is recommended in the Type1 manual 
2349       */
2350      if(useblues) {
2351          for(i=0; i<nnew; i+=2) {
2352              if(s[i].value != s[i+1].value)
2353                  continue;
2354              if( ((s[i].flags ^ s[i+1].flags) & ST_BLUE)==0 )
2355                  continue;
2356              if( s[i].flags & ST_BLUE ) {
2357                  if(nnew>i+2 && s[i+2].value<s[i].value+22)
2358                      s[i+1].value=s[i+2].value-2; /* compensate for fuzziness */
2359                  else
2360                      s[i+1].value+=20;
2361              } else {
2362                  if(i>0 && s[i-1].value>s[i].value-22)
2363                      s[i].value=s[i-1].value+2; /* compensate for fuzziness */
2364                  else
2365                      s[i].value-=20;
2366              }
2367          }
2368      }
2369      /* make sure that no stem it stretched between
2370       * a top zone and a bottom zone
2371       */
2372      if(useblues) {
2373          for(i=0; i<nnew; i+=2) {
2374              a=10000; /* lowest border of top zone crosing the stem */
2375              b= -10000; /* highest border of bottom zone crossing the stem */
2376  
2377              for(j=2; j<nblues; j++) {
2378                  c=bluevalues[j];
2379                  if( c>=s[i].value && c<=s[i+1].value && c<a )
2380                      a=c;
2381              }
2382              if(nblues>=2) {
2383                  c=bluevalues[1];
2384                  if( c>=s[i].value && c<=s[i+1].value && c>b )
2385                      b=c;
2386              }
2387              for(j=1; j<notherb; j++) {
2388                  c=otherblues[j];
2389                  if( c>=s[i].value && c<=s[i+1].value && c>b )
2390                      b=c;
2391              }
2392              if( a!=10000 && b!= -10000 ) { /* it is stretched */
2393                  /* split the stem into 2 ghost stems */
2394                  for(j=nnew+1; j>i+1; j--) /* make free space */
2395                      s[j]=s[j-2];
2396                  nnew+=2;
2397  
2398                  if(s[i].value+22 >= a)
2399                      s[i+1].value=a-2; /* leave space for fuzziness */
2400                  else
2401                      s[i+1].value=s[i].value+20;
2402  
2403                  if(s[i+3].value-22 <= b)
2404                      s[i+2].value=b+2; /* leave space for fuzziness */
2405                  else
2406                      s[i+2].value=s[i+3].value-20;
2407  
2408                  i+=2;
2409              }
2410          }
2411      }
2412      /* look for triple stems */
2413      for (i = 0; i < nnew; i += 2) {
2414          if (nnew - i >= 6) {
2415              a = s[i].value + s[i + 1].value;
2416              b = s[i + 2].value + s[i + 3].value;
2417              c = s[i + 4].value + s[i + 5].value;
2418  
2419              w1 = s[i + 1].value - s[i].value;
2420              w2 = s[i + 3].value - s[i + 2].value;
2421              w3 = s[i + 5].value - s[i + 4].value;
2422  
2423              fw = w3 - w1;    /* fuzz in width */
2424              fd = ((c - b) - (b - a));    /* fuzz in distance
2425                               * (doubled) */
2426  
2427              /* we are able to handle some fuzz */
2428              /*
2429               * it doesn't hurt if the declared stem is a bit
2430               * narrower than actual unless it's an edge in
2431               * a blue zone
2432               */
2433              if (abs(abs(fd) - abs(fw)) * 5 < w2
2434                  && abs(fw) * 20 < (w1 + w3)) {    /* width dirrerence <10% */
2435  
2436                  if(useblues) { /* check that we don't disturb any blue stems */
2437                      j=c; k=a;
2438                      if (fw > 0) {
2439                          if (fd > 0) {
2440                              if( s[i+5].flags & ST_BLUE )
2441                                  continue;
2442                              j -= fw;
2443                          } else {
2444                              if( s[i+4].flags & ST_BLUE )
2445                                  continue;
2446                              j += fw;
2447                          }
2448                      } else if(fw < 0) {
2449                          if (fd > 0) {
2450                              if( s[i+1].flags & ST_BLUE )
2451                                  continue;
2452                              k -= fw;
2453                          } else {
2454                              if( s[i].flags & ST_BLUE )
2455                                  continue;
2456                              k += fw;
2457                          }
2458                      }
2459                      pri = ((j - b) - (b - k));
2460  
2461                      if (pri > 0) {
2462                          if( s[i+2].flags & ST_BLUE )
2463                              continue;
2464                      } else if(pri < 0) {
2465                          if( s[i+3].flags & ST_BLUE )
2466                              continue;
2467                      }
2468                  }
2469  
2470                  /*
2471                   * first fix up the width of 1st and 3rd
2472                   * stems
2473                   */
2474                  if (fw > 0) {
2475                      if (fd > 0) {
2476                          s[i + 5].value -= fw;
2477                          c -= fw;
2478                      } else {
2479                          s[i + 4].value += fw;
2480                          c += fw;
2481                      }
2482                  } else {
2483                      if (fd > 0) {
2484                          s[i + 1].value -= fw;
2485                          a -= fw;
2486                      } else {
2487                          s[i].value += fw;
2488                          a += fw;
2489                      }
2490                  }
2491                  fd = ((c - b) - (b - a));
2492  
2493                  if (fd > 0) {
2494                      s[i + 2].value += abs(fd) / 2;
2495                  } else {
2496                      s[i + 3].value -= abs(fd) / 2;
2497                  }
2498  
2499                  s[i].flags |= ST_3;
2500                  i += 4;
2501              }
2502          }
2503      }
2504  
2505      return (nnew & ~1);    /* number of lines must be always even */
2506  }
2507  
2508  /*
2509   * these macros and function allow to set the base stem,
2510   * check that it's not empty and subtract another stem
2511   * from the base stem (possibly dividing it into multiple parts)
2512   */
2513  
2514  /* pairs for pieces of the base stem */
2515  static short xbstem[MAX_STEMS*2]; 
2516  /* index of the last point */
2517  static int xblast= -1; 
2518  
2519  #define setbasestem(from, to) \
2520      (xbstem[0]=from, xbstem[1]=to, xblast=1)
2521  #define isbaseempty()    (xblast<=0)
2522  
2523  /* returns 1 if was overlapping, 0 otherwise */
2524  static int
2525  subfrombase(
2526      int from,
2527      int to
2528  ) 
2529  {
2530      int a, b;
2531      int i, j;
2532  
2533      if(isbaseempty())
2534          return 0;
2535  
2536      /* handle the simple case simply */
2537      if(from > xbstem[xblast] || to < xbstem[0])
2538          return 0;
2539  
2540      /* the binary search may be more efficient */
2541      /* but for now the linear search is OK */
2542      for(b=1; from > xbstem[b]; b+=2) {} /* result: from <= xbstem[b] */
2543      for(a=xblast-1; to < xbstem[a]; a-=2) {} /* result: to >= xbstem[a] */
2544  
2545      /* now the interesting examples are:
2546       * (it was hard for me to understand, so I looked at the examples)
2547       * 1
2548       *     a|-----|          |-----|b   |-----|     |-----|
2549       *              f|-----|t
2550       * 2
2551       *     a|-----|b         |-----|    |-----|     |-----|
2552       *      f|--|t
2553       * 3
2554       *     a|-----|b         |-----|    |-----|     |-----|
2555       *           f|-----|t
2556       * 4
2557       *      |-----|b        a|-----|    |-----|     |-----|
2558       *          f|------------|t
2559       * 5
2560       *      |-----|          |-----|b   |-----|    a|-----|
2561       *                   f|-----------------------------|t
2562       * 6
2563       *      |-----|b         |-----|    |-----|    a|-----|
2564       *   f|--------------------------------------------------|t
2565       * 7
2566       *      |-----|b         |-----|   a|-----|     |-----|
2567       *          f|--------------------------|t
2568       */
2569  
2570      if(a < b-1) /* hits a gap  - example 1 */
2571          return 0;
2572  
2573      /* now the subtraction itself */
2574  
2575      if(a==b-1 && from > xbstem[a] && to < xbstem[b]) {
2576          /* overlaps with only one subrange and splits it - example 2 */
2577          j=xblast; i=(xblast+=2);
2578          while(j>=b)
2579              xbstem[i--]=xbstem[j--];
2580          xbstem[b]=from-1;
2581          xbstem[b+1]=to+1;
2582          return 1;
2583      /* becomes
2584       * 2a
2585       *     a|b   ||          |-----|    |-----|     |-----|
2586       *      f|--|t
2587       */
2588      }
2589  
2590      if(xbstem[b-1] < from) {
2591          /* cuts the back of this subrange - examples 3, 4, 7 */
2592          xbstem[b] = from-1;
2593          b+=2;
2594      /* becomes
2595       * 3a
2596       *     a|----|           |-----|b   |-----|     |-----|
2597       *           f|-----|t
2598       * 4a
2599       *      |---|           a|-----|b   |-----|     |-----|
2600       *          f|------------|t
2601       * 7a
2602       *      |---|            |-----|b  a|-----|     |-----|
2603       *          f|--------------------------|t
2604       */
2605      }
2606  
2607      if(xbstem[a+1] > to) {
2608          /* cuts the front of this subrange - examples 4a, 5, 7a */
2609          xbstem[a] = to+1;
2610          a-=2;
2611      /* becomes
2612       * 4b
2613       *     a|---|              |---|b   |-----|     |-----|
2614       *          f|------------|t
2615       * 5b
2616       *      |-----|          |-----|b  a|-----|          ||
2617       *                   f|-----------------------------|t
2618       * 7b
2619       *      |---|           a|-----|b        ||     |-----|
2620       *          f|--------------------------|t
2621       */
2622      }
2623  
2624      if(a < b-1) /* now after modification it hits a gap - examples 3a, 4b */
2625          return 1; /* because we have removed something */
2626  
2627      /* now remove the subranges completely covered by the new stem */
2628      /* examples 5b, 6, 7b */
2629      i=b-1; j=a+2;
2630      /* positioned as:
2631       * 5b                    i                           j
2632       *      |-----|          |-----|b  a|-----|          ||
2633       *                   f|-----------------------------|t
2634       * 6    i                                             xblast  j
2635       *      |-----|b         |-----|    |-----|    a|-----|
2636       *   f|--------------------------------------------------|t
2637       * 7b                    i               j
2638       *      |---|           a|-----|b        ||     |-----|
2639       *          f|--------------------------|t
2640       */
2641      while(j <= xblast)
2642          xbstem[i++]=xbstem[j++];
2643      xblast=i-1;
2644      return 1;
2645  }
2646  
2647  /* for debugging */
2648  static void
2649  printbasestem(void)
2650  {
2651      int i;
2652  
2653      printf("( ");
2654      for(i=0; i<xblast; i+=2)
2655          printf("%d-%d ", xbstem[i], xbstem[i+1]);
2656      printf(") %d\n", xblast);
2657  }
2658  
2659  /*
2660   * Join the stem borders to build the sets of substituted stems
2661   * XXX add consideration of the italic angle
2662   */
2663  static void
2664  joinsubstems(
2665        STEM * s,
2666        short *pairs,
2667        int nold,
2668        int useblues /* do we use the blue values ? */
2669  )
2670  {
2671      int i, j, x;
2672      static unsigned char mx[MAX_STEMS][MAX_STEMS];
2673  
2674      /* we do the substituted groups of stems first
2675       * and it looks like it's going to be REALLY SLOW 
2676       * AND PAINFUL but let's bother about it later
2677       */
2678  
2679      /* for the substituted stems we don't bother about [hv]stem3 -
2680       * anyway the X11R6 rasterizer does not bother about hstem3
2681       * at all and is able to handle only one global vstem3
2682       * per glyph 
2683       */
2684  
2685      /* clean the used part of matrix */
2686      for(i=0; i<nold; i++)
2687          for(j=0; j<nold; j++)
2688              mx[i][j]=0;
2689  
2690      /* build the matrix of stem pairs */
2691      for(i=0; i<nold; i++) {
2692          if( s[i].flags & ST_ZONE )
2693              continue;
2694          if(s[i].flags & ST_BLUE)
2695              mx[i][i]=1; /* allow to pair with itself if no better pair */
2696          if(s[i].flags & ST_UP) { /* the down-stems are already matched */
2697              setbasestem(s[i].from, s[i].to);
2698              for(j=i+1; j<nold; j++) {
2699                  if(s[i].value==s[j].value
2700                  || s[j].flags & ST_ZONE ) {
2701                      continue;
2702                  }
2703                  x=subfrombase(s[j].from, s[j].to);
2704  
2705                  if(s[j].flags & ST_UP) /* match only up+down pairs */
2706                      continue;
2707  
2708                  mx[i][j]=mx[j][i]=x;
2709  
2710                  if(isbaseempty()) /* nothing else to do */
2711                      break;
2712              }
2713          }
2714      }
2715  
2716      if(ISDBG(SUBSTEMS)) {
2717          fprintf(pfa_file, "%%     ");
2718          for(j=0; j<nold; j++)
2719              putc( j%10==0 ? '0'+(j/10)%10 : ' ', pfa_file);
2720          fprintf(pfa_file, "\n%%     ");
2721          for(j=0; j<nold; j++)
2722              putc('0'+j%10, pfa_file);
2723          putc('\n', pfa_file);
2724          for(i=0; i<nold; i++) {
2725              fprintf(pfa_file, "%% %3d ",i);
2726              for(j=0; j<nold; j++)
2727                  putc( mx[i][j] ? 'X' : '.', pfa_file);
2728              putc('\n', pfa_file);
2729          }
2730      }
2731  
2732      /* now use the matrix to find the best pair for each stem */
2733      for(i=0; i<nold; i++) {
2734          int pri, lastpri, v, f;
2735  
2736          x= -1; /* best pair: none */
2737          lastpri=0;
2738  
2739          v=s[i].value;
2740          f=s[i].flags;
2741  
2742          if(f & ST_ZONE) {
2743              pairs[i]= -1;
2744              continue;
2745          }
2746  
2747          if(f & ST_UP) {
2748              for(j=i+1; j<nold; j++) {
2749                  if(mx[i][j]==0)
2750                      continue;
2751  
2752                  if( (f | s[j].flags) & ST_END )
2753                      pri=1;
2754                  else if( (f | s[j].flags) & ST_FLAT )
2755                      pri=3;
2756                  else
2757                      pri=2;
2758  
2759                  if(lastpri==0
2760                  || pri > lastpri  
2761                  && ( lastpri==1 || s[j].value-v<20 || (s[x].value-v)*2 >= s[j].value-v ) ) {
2762                      lastpri=pri;
2763                      x=j;
2764                  }
2765              }
2766          } else {
2767              for(j=i-1; j>=0; j--) {
2768                  if(mx[i][j]==0)
2769                      continue;
2770  
2771                  if( (f | s[j].flags) & ST_END )
2772                      pri=1;
2773                  else if( (f | s[j].flags) & ST_FLAT )
2774                      pri=3;
2775                  else
2776                      pri=2;
2777  
2778                  if(lastpri==0
2779                  || pri > lastpri  
2780                  && ( lastpri==1 || v-s[j].value<20 || (v-s[x].value)*2 >= v-s[j].value ) ) {
2781                      lastpri=pri;
2782                      x=j;
2783                  }
2784              }
2785          }
2786          if(x== -1 && mx[i][i])
2787              pairs[i]=i; /* a special case */
2788          else
2789              pairs[i]=x;
2790      }
2791  
2792      if(ISDBG(SUBSTEMS)) {
2793          for(i=0; i<nold; i++) {
2794              j=pairs[i];
2795              if(j>0)
2796                  fprintf(pfa_file, "%% %d...%d  (%d x %d)\n", s[i].value, s[j].value, i, j);
2797          }
2798      }
2799  }
2800  
2801  /*
2802   * Make all the stems originating at the same value get the
2803   * same width. Without this the rasterizer may move the dots
2804   * randomly up or down by one pixel, and that looks bad.
2805   * The prioritisation is the same as in findstemat().
2806   */
2807  static void
2808  uniformstems(
2809        STEM * s,
2810        short *pairs,
2811        int ns
2812  )
2813  {
2814      int i, j, from, to, val, dir;
2815      int pri, prevpri[2], wd, prevwd[2], prevbest[2];
2816  
2817      for(from=0; from<ns; from=to) {
2818          prevpri[0] = prevpri[1] = 0;
2819          prevwd[0] = prevwd[1] = 0;
2820          prevbest[0] = prevbest[1] = -1;
2821          val = s[from].value;
2822  
2823          for(to = from; to<ns && s[to].value == val; to++) {
2824              dir = ((s[to].flags & ST_UP)!=0);
2825  
2826              i=pairs[to]; /* the other side of this stem */
2827              if(i<0 || i==to)
2828                  continue; /* oops, no other side */
2829              wd=abs(s[i].value-val);
2830              if(wd == 0)
2831                  continue;
2832              pri=1;
2833              if( (s[to].flags | s[i].flags) & ST_END )
2834                  pri=0;
2835              if( prevbest[dir] == -1 || pri > prevpri[dir] || wd<prevwd[dir] ) {
2836                  prevbest[dir]=i;
2837                  prevpri[dir]=pri;
2838                  prevwd[dir]=wd;
2839              }
2840          }
2841  
2842          for(i=from; i<to; i++) {
2843              dir = ((s[i].flags & ST_UP)!=0);
2844              if(prevbest[dir] >= 0) {
2845                  if(ISDBG(SUBSTEMS)) {
2846                      fprintf(stderr, "at %d (%s %d) pair %d->%d(%d)\n", i, 
2847                          (dir ? "UP":"DOWN"), s[i].value, pairs[i], prevbest[dir],
2848                          s[prevbest[dir]].value);
2849                  }
2850                  pairs[i] = prevbest[dir];
2851              }
2852          }
2853      }
2854  }
2855  
2856  /* 
2857   * Find the best stem in the array at the specified (value, origin),
2858   * related to the entry ge.
2859   * Returns its index in the array sp, -1 means "none".
2860   * prevbest is the result for the other end of the line, we must 
2861   * find something better than it or leave it as it is.
2862   */
2863  static int
2864  findstemat(
2865      int value,
2866      int origin,
2867      GENTRY *ge,
2868      STEM *sp,
2869      short *pairs,
2870      int ns,
2871      int prevbest /* -1 means "none" */
2872  )
2873  {
2874      int i, min, max;
2875      int v, si;
2876      int pri, prevpri; /* priority, 0 = has ST_END, 1 = no ST_END */
2877      int wd, prevwd; /* stem width */
2878  
2879      si= -1; /* nothing yet */
2880  
2881      /* stems are ordered by value, binary search */
2882      min=0; max=ns; /* min <= i < max */
2883      while( min < max ) {
2884          i=(min+max)/2;
2885          v=sp[i].value;
2886          if(v<value)
2887              min=i+1;
2888          else if(v>value)
2889              max=i;
2890          else {
2891              si=i; /* temporary value */
2892              break;
2893          }
2894      }
2895  
2896      if( si < 0 ) /* found nothing this time */
2897          return prevbest;
2898  
2899      /* find the priority of the prevbest */
2900      /* we expect that prevbest has a pair */
2901      if(prevbest>=0) {
2902          i=pairs[prevbest];
2903          prevpri=1;
2904          if( (sp[prevbest].flags | sp[i].flags) & ST_END )
2905              prevpri=0; 
2906          prevwd=abs(sp[i].value-value);
2907      }
2908  
2909      /* stems are not ordered by origin, so now do the linear search */
2910  
2911      while( si>0 && sp[si-1].value==value ) /* find the first one */
2912          si--;
2913  
2914      for(; si<ns && sp[si].value==value; si++) {
2915          if(sp[si].origin != origin) 
2916              continue;
2917          if(sp[si].ge != ge) {
2918              if(ISDBG(SUBSTEMS)) {
2919                  fprintf(stderr, 
2920                      "dbg: possible self-intersection at v=%d o=%d exp_ge=0x%x ge=0x%x\n",
2921                      value, origin, ge, sp[si].ge);
2922              }
2923              continue;
2924          }
2925          i=pairs[si]; /* the other side of this stem */
2926          if(i<0)
2927              continue; /* oops, no other side */
2928          pri=1;
2929          if( (sp[si].flags | sp[i].flags) & ST_END )
2930              pri=0;
2931          wd=abs(sp[i].value-value);
2932          if( prevbest == -1 || pri >prevpri 
2933          || pri==prevpri && prevwd==0 || wd!=0 && wd<prevwd ) {
2934              prevbest=si;
2935              prevpri=pri;
2936              prevwd=wd;
2937              continue;
2938          }
2939      }
2940  
2941      return prevbest;
2942  }
2943  
2944  /* add the substems for one glyph entry 
2945   * (called from groupsubstems())
2946   * returns 0 if all OK, 1 if too many groups
2947   */
2948  
2949  static int gssentry_lastgrp=0; /* reset to 0 for each new glyph */
2950  
2951  static int
2952  gssentry( /* crazy number of parameters */
2953      GENTRY *ge,
2954      STEM *hs, /* horizontal stems, sorted by value */
2955      short *hpairs,
2956      int nhs,
2957      STEM *vs, /* vertical stems, sorted by value */
2958      short *vpairs,
2959      int nvs,
2960      STEMBOUNDS *s,
2961      short *egp,
2962      int *nextvsi, 
2963      int *nexthsi /* -2 means "check by yourself" */
2964  ) {
2965      enum {
2966          SI_VP,    /* vertical primary */
2967          SI_HP,    /* horizontal primary */
2968          SI_SIZE /* size of the array */
2969      };
2970      int si[SI_SIZE]; /* indexes of relevant stems */
2971  
2972      /* the bounds of the existing relevant stems */
2973      STEMBOUNDS r[ sizeof(si) / sizeof(si[0]) * 2 ];
2974      char rexpand; /* by how much we need to expand the group */
2975      int nr; /* and the number of them */
2976  
2977      /* yet more temporary storage */
2978      short lb, hb, isvert;
2979      int conflict, grp;
2980      int i, j, x, y;
2981  
2982  
2983      /* for each line or curve we try to find a horizontal and
2984       * a vertical stem corresponding to its first point
2985       * (corresponding to the last point of the previous
2986       * glyph entry), because the directions of the lines
2987       * will be eventually reversed and it will then become the last
2988       * point. And the T1 rasterizer applies the hints to 
2989       * the last point.
2990       *
2991       */
2992  
2993      /* start with the common part, the first point */
2994      x=ge->prev->ix3;
2995      y=ge->prev->iy3;
2996  
2997      if(*nextvsi == -2)
2998          si[SI_VP]=findstemat(x, y, ge, vs, vpairs, nvs, -1);
2999      else {
3000          si[SI_VP]= *nextvsi; *nextvsi= -2;
3001      }
3002      if(*nexthsi == -2)
3003          si[SI_HP]=findstemat(y, x, ge, hs, hpairs, nhs, -1);
3004      else {
3005          si[SI_HP]= *nexthsi; *nexthsi= -2;
3006      }
3007  
3008      /*
3009       * For the horizontal lines we make sure that both
3010       * ends of the line have the same horizontal stem,
3011       * and the same thing for vertical lines and stems.
3012       * In both cases we enforce the stem for the next entry.
3013       * Otherwise unpleasant effects may arise.
3014       */
3015  
3016      if(ge->type==GE_LINE) {
3017          if(ge->ix3==x) { /* vertical line */
3018              *nextvsi=si[SI_VP]=findstemat(x, ge->iy3, ge->frwd, vs, vpairs, nvs, si[SI_VP]);
3019          } else if(ge->iy3==y) { /* horizontal line */
3020              *nexthsi=si[SI_HP]=findstemat(y, ge->ix3, ge->frwd, hs, hpairs, nhs, si[SI_HP]);
3021          }
3022      }
3023  
3024      if(si[SI_VP]+si[SI_HP] == -2) /* no stems, leave it alone */
3025          return 0;
3026  
3027      /* build the array of relevant bounds */
3028      nr=0;
3029      for(i=0; i< sizeof(si) / sizeof(si[0]); i++) {
3030          STEM *sp;
3031          short *pairs;
3032          int step;
3033          int f;
3034          int nzones, firstzone, binzone, einzone;
3035          int btype, etype;
3036  
3037          if(si[i] < 0)
3038              continue;
3039  
3040          if(i<SI_HP) {
3041              r[nr].isvert=1; sp=vs; pairs=vpairs;
3042          } else {
3043              r[nr].isvert=0; sp=hs; pairs=hpairs;
3044          }
3045  
3046          r[nr].low=sp[ si[i] ].value;
3047          r[nr].high=sp[ pairs[ si[i] ] ].value;
3048  
3049          if(r[nr].low > r[nr].high) {
3050              j=r[nr].low; r[nr].low=r[nr].high; r[nr].high=j;
3051              step= -1;
3052          } else {
3053              step=1;
3054          }
3055  
3056          /* handle the interaction with Blue Zones */
3057  
3058          if(i>=SI_HP) { /* only for horizontal stems */
3059              if(si[i]==pairs[si[i]]) {
3060                  /* special case, the outermost stem in the
3061                   * Blue Zone without a pair, simulate it to 20-pixel
3062                   */
3063                  if(sp[ si[i] ].flags & ST_UP) {
3064                      r[nr].high+=20;
3065                      for(j=si[i]+1; j<nhs; j++)
3066                          if( (sp[j].flags & (ST_ZONE|ST_TOPZONE))
3067                          == (ST_ZONE|ST_TOPZONE) ) {
3068                              if(r[nr].high > sp[j].value-2)
3069                                  r[nr].high=sp[j].value-2;
3070                              break;
3071                          }
3072                  } else {
3073                      r[nr].low-=20;
3074                      for(j=si[i]-1; j>=0; j--)
3075                          if( (sp[j].flags & (ST_ZONE|ST_TOPZONE))
3076                          == (ST_ZONE) ) {
3077                              if(r[nr].low < sp[j].value+2)
3078                                  r[nr].low=sp[j].value+2;
3079                              break;
3080                          }
3081                  }
3082              }
3083  
3084              /* check that the stem borders don't end up in
3085               * different Blue Zones */
3086              f=sp[ si[i] ].flags;
3087              nzones=0; einzone=binzone=0;
3088              for(j=si[i]; j!=pairs[ si[i] ]; j+=step) {
3089                  if( (sp[j].flags & ST_ZONE)==0 )
3090                      continue;
3091                  /* if see a zone border going in the same direction */
3092                  if( ((f ^ sp[j].flags) & ST_UP)==0 ) {
3093                      if( ++nzones == 1 ) {
3094                          firstzone=sp[j].value; /* remember the first one */
3095                          etype=sp[j].flags & ST_TOPZONE;
3096                      }
3097                      einzone=1;
3098  
3099                  } else { /* the opposite direction */
3100                      if(nzones==0) { /* beginning is in a blue zone */
3101                          binzone=1;
3102                          btype=sp[j].flags & ST_TOPZONE;
3103                      }
3104                      einzone=0;
3105                  }
3106              }
3107  
3108              /* beginning and end are in Blue Zones of different types */
3109              if( binzone && einzone && (btype ^ etype)!=0 ) {
3110                  if( sp[si[i]].flags & ST_UP ) {
3111                      if(firstzone > r[nr].low+22)
3112                          r[nr].high=r[nr].low+20;
3113                      else
3114                          r[nr].high=firstzone-2;
3115                  } else {
3116                      if(firstzone < r[nr].high-22)
3117                          r[nr].low=r[nr].high-20;
3118                      else
3119                          r[nr].low=firstzone+2;
3120                  }
3121              }
3122          }
3123  
3124          if(ISDBG(SUBSTEMS))
3125              fprintf(pfa_file, "%%  at(%d,%d)[%d,%d] %d..%d %c (%d x %d)\n", x, y, i, nr,
3126                  r[nr].low, r[nr].high, r[nr].isvert ? 'v' : 'h',
3127                  si[i], pairs[si[i]]);
3128  
3129          nr++;
3130      }
3131  
3132      /* now try to find a group */
3133      conflict=0; /* no conflicts found yet */
3134      for(j=0; j<nr; j++)
3135          r[j].already=0;
3136  
3137      /* check if it fits into the last group */
3138      grp = gssentry_lastgrp;
3139      i = (grp==0)? 0 : egp[grp-1];
3140      for(; i<egp[grp]; i++) {
3141          lb=s[i].low; hb=s[i].high; isvert=s[i].isvert;
3142          for(j=0; j<nr; j++)
3143              if( r[j].isvert==isvert  /* intersects */
3144              && r[j].low <= hb && r[j].high >= lb ) {
3145                  if( r[j].low == lb && r[j].high == hb ) /* coincides */
3146                      r[j].already=1;
3147                  else
3148                      conflict=1;
3149              }
3150  
3151          if(conflict) 
3152              break;
3153      }
3154  
3155      if(conflict) { /* nope, check all the groups */
3156          for(j=0; j<nr; j++)
3157              r[j].already=0;
3158  
3159          for(i=0, grp=0; i<egp[NSTEMGRP-1]; i++) {
3160              if(i == egp[grp]) { /* checked all stems in a group */
3161                  if(conflict) {
3162                      grp++; conflict=0; /* check the next group */
3163                      for(j=0; j<nr; j++)
3164                          r[j].already=0;
3165                  } else
3166                      break; /* insert into this group */
3167              }
3168  
3169              lb=s[i].low; hb=s[i].high; isvert=s[i].isvert;
3170              for(j=0; j<nr; j++)
3171                  if( r[j].isvert==isvert  /* intersects */
3172                  && r[j].low <= hb && r[j].high >= lb ) {
3173                      if( r[j].low == lb && r[j].high == hb ) /* coincides */
3174                          r[j].already=1;
3175                      else
3176                          conflict=1;
3177                  }
3178  
3179              if(conflict) 
3180                  i=egp[grp]-1; /* fast forward to the next group */
3181          }
3182      }
3183  
3184      /* do we have any empty group ? */
3185      if(conflict && grp < NSTEMGRP-1) {
3186          grp++; conflict=0;
3187          for(j=0; j<nr; j++)
3188              r[j].already=0;
3189      }
3190  
3191      if(conflict) { /* oops, can't find any group to fit */
3192          return 1;
3193      }
3194  
3195      /* OK, add stems to this group */
3196  
3197      rexpand = nr;
3198      for(j=0; j<nr; j++)
3199          rexpand -= r[j].already;
3200  
3201      if(rexpand > 0) {
3202          for(i=egp[NSTEMGRP-1]-1; i>=egp[grp]; i--)
3203              s[i+rexpand]=s[i];
3204          for(i=0; i<nr; i++)
3205              if(!r[i].already)
3206                  s[egp[grp]++]=r[i];
3207          for(i=grp+1; i<NSTEMGRP; i++)
3208              egp[i]+=rexpand;
3209      }
3210  
3211      ge->stemid = gssentry_lastgrp = grp;
3212      return 0;
3213  }
3214  
3215  /*
3216   * Create the groups of substituted stems from the list.
3217   * Each group will be represented by a subroutine in the Subs
3218   * array.
3219   */
3220  
3221  static void
3222  groupsubstems(
3223      GLYPH *g,
3224      STEM *hs, /* horizontal stems, sorted by value */
3225      short *hpairs,
3226      int nhs,
3227      STEM *vs, /* vertical stems, sorted by value */
3228      short *vpairs,
3229      int nvs
3230  )
3231  {
3232      GENTRY *ge;
3233      int i, j;
3234  
3235      /* temporary storage */
3236      STEMBOUNDS s[MAX_STEMS*2];
3237      /* indexes in there, pointing past the end each stem group */
3238      short egp[NSTEMGRP]; 
3239  
3240      int nextvsi, nexthsi; /* -2 means "check by yourself" */
3241  
3242      for(i=0; i<NSTEMGRP; i++)
3243          egp[i]=0;
3244  
3245      nextvsi=nexthsi= -2; /* processed no horiz/vert line */
3246  
3247      gssentry_lastgrp = 0; /* reset the last group for new glyph */
3248  
3249      for (ge = g->entries; ge != 0; ge = ge->next) {
3250          if(ge->type!=GE_LINE && ge->type!=GE_CURVE) {
3251              nextvsi=nexthsi= -2; /* next path is independent */
3252              continue;
3253          }
3254  
3255          if( gssentry(ge, hs, hpairs, nhs, vs, vpairs, nvs, s, egp, &nextvsi, &nexthsi) ) {
3256              WARNING_2 fprintf(stderr, "*** glyph %s requires over %d hint subroutines, ignored them\n",
3257                  g->name, NSTEMGRP);
3258              /* it's better to have no substituted hints at all than have only part */
3259              for (ge = g->entries; ge != 0; ge = ge->next)
3260                  ge->stemid= -1;
3261              g->nsg=0; /* just to be safe, already is 0 by initialization */
3262              return;
3263          }
3264  
3265          /*
3266           * handle the last vert/horiz line of the path specially,
3267           * correct the hint for the first entry of the path
3268           */
3269          if(ge->frwd != ge->next && (nextvsi != -2 || nexthsi != -2) ) {
3270              if( gssentry(ge->frwd, hs, hpairs, nhs, vs, vpairs, nvs, s, egp, &nextvsi, &nexthsi) ) {
3271                  WARNING_2 fprintf(stderr, "*** glyph %s requires over %d hint subroutines, ignored them\n",
3272                      g->name, NSTEMGRP);
3273                  /* it's better to have no substituted hints at all than have only part */
3274                  for (ge = g->entries; ge != 0; ge = ge->next)
3275                      ge->stemid= -1;
3276                  g->nsg=0; /* just to be safe, already is 0 by initialization */
3277                  return;
3278              }
3279          }
3280  
3281      }
3282  
3283      /* find the index of the first empty group - same as the number of groups */
3284      if(egp[0]>0) {
3285          for(i=1; i<NSTEMGRP && egp[i]!=egp[i-1]; i++)
3286              {}
3287          g->nsg=i;
3288      } else
3289          g->nsg=0;
3290  
3291      if(ISDBG(SUBSTEMS)) {
3292          fprintf(pfa_file, "%% %d substem groups (%d %d %d)\n", g->nsg,
3293              g->nsg>1 ? egp[g->nsg-2] : -1,
3294              g->nsg>0 ? egp[g->nsg-1] : -1,
3295              g->nsg<NSTEMGRP ? egp[g->nsg] : -1 );
3296          j=0;
3297          for(i=0; i<g->nsg; i++) {
3298              fprintf(pfa_file, "%% grp %3d:      ", i);
3299              for(; j<egp[i]; j++) {
3300                  fprintf(pfa_file, " %4d...%-4d %c  ", s[j].low, s[j].high,
3301                      s[j].isvert ? 'v' : 'h');
3302              }
3303              fprintf(pfa_file, "\n");
3304          }
3305      }
3306  
3307      if(g->nsg==1) { /* it would be the same as the main stems */
3308          /* so erase it */
3309          for (ge = g->entries; ge != 0; ge = ge->next)
3310              ge->stemid= -1;
3311          g->nsg=0;
3312      }
3313  
3314      if(g->nsg>0) {
3315          if( (g->nsbs=malloc(g->nsg * sizeof (egp[0]))) == 0 ) {
3316              fprintf(stderr, "**** not enough memory for substituted hints ****\n");
3317              exit(255);
3318          }
3319          memmove(g->nsbs, egp, g->nsg * sizeof(short));
3320          if( (g->sbstems=malloc(egp[g->nsg-1] * sizeof (s[0]))) == 0 ) {
3321              fprintf(stderr, "**** not enough memory for substituted hints ****\n");
3322              exit(255);
3323          }
3324          memmove(g->sbstems, s, egp[g->nsg-1] * sizeof(s[0]));
3325      }
3326  }
3327  
3328  void
3329  buildstems(
3330         GLYPH * g
3331  )
3332  {
3333      STEM            hs[MAX_STEMS], vs[MAX_STEMS];    /* temporary working
3334                               * storage */
3335      short    hs_pairs[MAX_STEMS], vs_pairs[MAX_STEMS]; /* best pairs for these stems */
3336      STEM           *sp;
3337      GENTRY         *ge, *nge, *pge;
3338      int             nx, ny;
3339      int ovalue;
3340      int totals, grp, lastgrp;
3341  
3342      assertisint(g, "buildstems int");
3343  
3344      g->nhs = g->nvs = 0;
3345      memset(hs, 0, sizeof hs);
3346      memset(vs, 0, sizeof vs);
3347  
3348      /* first search the whole character for possible stem points */
3349  
3350      for (ge = g->entries; ge != 0; ge = ge->next) {
3351          if (ge->type == GE_CURVE) {
3352  
3353              /*
3354               * SURPRISE! 
3355               * We consider the stems bound by the
3356               * H/V ends of the curves as flat ones.
3357               *
3358               * But we don't include the point on the
3359               * other end into the range.
3360               */
3361  
3362              /* first check the beginning of curve */
3363              /* if it is horizontal, add a hstem */
3364              if (ge->iy1 == ge->prev->iy3) {
3365                  hs[g->nhs].value = ge->iy1;
3366  
3367                  if (ge->ix1 < ge->prev->ix3)
3368                      hs[g->nhs].flags = ST_FLAT | ST_UP;
3369                  else
3370                      hs[g->nhs].flags = ST_FLAT;
3371  
3372                  hs[g->nhs].origin = ge->prev->ix3;
3373                  hs[g->nhs].ge = ge;
3374  
3375                  if (ge->ix1 < ge->prev->ix3) {
3376                      hs[g->nhs].from = ge->ix1+1;
3377                      hs[g->nhs].to = ge->prev->ix3;
3378                      if(hs[g->nhs].from > hs[g->nhs].to)
3379                          hs[g->nhs].from--;
3380                  } else {
3381                      hs[g->nhs].from = ge->prev->ix3;
3382                      hs[g->nhs].to = ge->ix1-1;
3383                      if(hs[g->nhs].from > hs[g->nhs].to)
3384                          hs[g->nhs].to++;
3385                  }
3386                  if (ge->ix1 != ge->prev->ix3)
3387                      g->nhs++;
3388              }
3389              /* if it is vertical, add a vstem */
3390              else if (ge->ix1 == ge->prev->ix3) {
3391                  vs[g->nvs].value = ge->ix1;
3392  
3393                  if (ge->iy1 > ge->prev->iy3)
3394                      vs[g->nvs].flags = ST_FLAT | ST_UP;
3395                  else
3396                      vs[g->nvs].flags = ST_FLAT;
3397  
3398                  vs[g->nvs].origin = ge->prev->iy3;
3399                  vs[g->nvs].ge = ge;
3400  
3401                  if (ge->iy1 < ge->prev->iy3) {
3402                      vs[g->nvs].from = ge->iy1+1;
3403                      vs[g->nvs].to = ge->prev->iy3;
3404                      if(vs[g->nvs].from > vs[g->nvs].to)
3405                          vs[g->nvs].from--;
3406                  } else {
3407                      vs[g->nvs].from = ge->prev->iy3;
3408                      vs[g->nvs].to = ge->iy1-1;
3409                      if(vs[g->nvs].from > vs[g->nvs].to)
3410                          vs[g->nvs].to++;
3411                  }
3412  
3413                  if (ge->iy1 != ge->prev->iy3)
3414                      g->nvs++;
3415              }
3416              /* then check the end of curve */
3417              /* if it is horizontal, add a hstem */
3418              if (ge->iy3 == ge->iy2) {
3419                  hs[g->nhs].value = ge->iy3;
3420  
3421                  if (ge->ix3 < ge->ix2)
3422                      hs[g->nhs].flags = ST_FLAT | ST_UP;
3423                  else
3424                      hs[g->nhs].flags = ST_FLAT;
3425  
3426                  hs[g->nhs].origin = ge->ix3;
3427                  hs[g->nhs].ge = ge->frwd;
3428  
3429                  if (ge->ix3 < ge->ix2) {
3430                      hs[g->nhs].from = ge->ix3;
3431                      hs[g->nhs].to = ge->ix2-1;
3432                      if( hs[g->nhs].from > hs[g->nhs].to )
3433                          hs[g->nhs].to++;
3434                  } else {
3435                      hs[g->nhs].from = ge->ix2+1;
3436                      hs[g->nhs].to = ge->ix3;
3437                      if( hs[g->nhs].from > hs[g->nhs].to )
3438                          hs[g->nhs].from--;
3439                  }
3440  
3441                  if (ge->ix3 != ge->ix2)
3442                      g->nhs++;
3443              }
3444              /* if it is vertical, add a vstem */
3445              else if (ge->ix3 == ge->ix2) {
3446                  vs[g->nvs].value = ge->ix3;
3447  
3448                  if (ge->iy3 > ge->iy2)
3449                      vs[g->nvs].flags = ST_FLAT | ST_UP;
3450                  else
3451                      vs[g->nvs].flags = ST_FLAT;
3452  
3453                  vs[g->nvs].origin = ge->iy3;
3454                  vs[g->nvs].ge = ge->frwd;
3455  
3456                  if (ge->iy3 < ge->iy2) {
3457                      vs[g->nvs].from = ge->iy3;
3458                      vs[g->nvs].to = ge->iy2-1;
3459                      if( vs[g->nvs].from > vs[g->nvs].to )
3460                          vs[g->nvs].to++;
3461                  } else {
3462                      vs[g->nvs].from = ge->iy2+1;
3463                      vs[g->nvs].to = ge->iy3;
3464                      if( vs[g->nvs].from > vs[g->nvs].to )
3465                          vs[g->nvs].from--;
3466                  }
3467  
3468                  if (ge->iy3 != ge->iy2)
3469                      g->nvs++;
3470              } else {
3471  
3472                  /*
3473                   * check the end of curve for a not smooth
3474                   * local extremum
3475                   */
3476                  nge = ge->frwd;
3477  
3478                  if (nge == 0)
3479                      continue;
3480                  else if (nge->type == GE_LINE) {
3481                      nx = nge->ix3;
3482                      ny = nge->iy3;
3483                  } else if (nge->type == GE_CURVE) {
3484                      nx = nge->ix1;
3485                      ny = nge->iy1;
3486                  } else
3487                      continue;
3488  
3489                  /* check for vertical extremums */
3490                  if (ge->iy3 > ge->iy2 && ge->iy3 > ny
3491                  || ge->iy3 < ge->iy2 && ge->iy3 < ny) {
3492                      hs[g->nhs].value = ge->iy3;
3493                      hs[g->nhs].from
3494                          = hs[g->nhs].to
3495                          = hs[g->nhs].origin = ge->ix3;
3496                      hs[g->nhs].ge = ge->frwd;
3497  
3498                      if (ge->ix3 < ge->ix2
3499                          || nx < ge->ix3)
3500                          hs[g->nhs].flags = ST_UP;
3501                      else
3502                          hs[g->nhs].flags = 0;
3503  
3504                      if (ge->ix3 != ge->ix2 || nx != ge->ix3)
3505                          g->nhs++;
3506                  }
3507                  /*
3508                   * the same point may be both horizontal and
3509                   * vertical extremum
3510                   */
3511                  /* check for horizontal extremums */
3512                  if (ge->ix3 > ge->ix2 && ge->ix3 > nx
3513                  || ge->ix3 < ge->ix2 && ge->ix3 < nx) {
3514                      vs[g->nvs].value = ge->ix3;
3515                      vs[g->nvs].from
3516                          = vs[g->nvs].to
3517                          = vs[g->nvs].origin = ge->iy3;
3518                      vs[g->nvs].ge = ge->frwd;
3519  
3520                      if (ge->iy3 > ge->iy2
3521                          || ny > ge->iy3)
3522                          vs[g->nvs].flags = ST_UP;
3523                      else
3524                          vs[g->nvs].flags = 0;
3525  
3526                      if (ge->iy3 != ge->iy2 || ny != ge->iy3)
3527                          g->nvs++;
3528                  }
3529              }
3530  
3531          } else if (ge->type == GE_LINE) {
3532              nge = ge->frwd;
3533  
3534              /* if it is horizontal, add a hstem */
3535              /* and the ends as vstems if they brace the line */
3536              if (ge->iy3 == ge->prev->iy3
3537              && ge->ix3 != ge->prev->ix3) {
3538                  hs[g->nhs].value = ge->iy3;
3539                  if (ge->ix3 < ge->prev->ix3) {
3540                      hs[g->nhs].flags = ST_FLAT | ST_UP;
3541                      hs[g->nhs].from = ge->ix3;
3542                      hs[g->nhs].to = ge->prev->ix3;
3543                  } else {
3544                      hs[g->nhs].flags = ST_FLAT;
3545                      hs[g->nhs].from = ge->prev->ix3;
3546                      hs[g->nhs].to = ge->ix3;
3547                  }
3548                  hs[g->nhs].origin = ge->ix3;
3549                  hs[g->nhs].ge = ge->frwd;
3550  
3551                  pge = ge->bkwd;
3552  
3553                  /* add beginning as vstem */
3554                  vs[g->nvs].value = pge->ix3;
3555                  vs[g->nvs].origin
3556                      = vs[g->nvs].from
3557                      = vs[g->nvs].to = pge->iy3;
3558                  vs[g->nvs].ge = ge;
3559  
3560                  if(pge->type==GE_CURVE)
3561                      ovalue=pge->iy2;
3562                  else
3563                      ovalue=pge->prev->iy3;
3564  
3565                  if (pge->iy3 > ovalue)
3566                      vs[g->nvs].flags = ST_UP | ST_END;
3567                  else if (pge->iy3 < ovalue)
3568                      vs[g->nvs].flags = ST_END;
3569                  else
3570                      vs[g->nvs].flags = 0;
3571  
3572                  if( vs[g->nvs].flags != 0 )
3573                      g->nvs++;
3574  
3575                  /* add end as vstem */
3576                  vs[g->nvs].value = ge->ix3;
3577                  vs[g->nvs].origin
3578                      = vs[g->nvs].from
3579                      = vs[g->nvs].to = ge->iy3;
3580                  vs[g->nvs].ge = ge->frwd;
3581  
3582                  if(nge->type==GE_CURVE)
3583                      ovalue=nge->iy1;
3584                  else
3585                      ovalue=nge->iy3;
3586  
3587                  if (ovalue > ge->iy3)
3588                      vs[g->nvs].flags = ST_UP | ST_END;
3589                  else if (ovalue < ge->iy3)
3590                      vs[g->nvs].flags = ST_END;
3591                  else
3592                      vs[g->nvs].flags = 0;
3593  
3594                  if( vs[g->nvs].flags != 0 )
3595                      g->nvs++;
3596  
3597                  g->nhs++;
3598              }
3599              /* if it is vertical, add a vstem */
3600              /* and the ends as hstems if they brace the line  */
3601              else if (ge->ix3 == ge->prev->ix3 
3602              && ge->iy3 != ge->prev->iy3) {
3603                  vs[g->nvs].value = ge->ix3;
3604                  if (ge->iy3 > ge->prev->iy3) {
3605                      vs[g->nvs].flags = ST_FLAT | ST_UP;
3606                      vs[g->nvs].from = ge->prev->iy3;
3607                      vs[g->nvs].to = ge->iy3;
3608                  } else {
3609                      vs[g->nvs].flags = ST_FLAT;
3610                      vs[g->nvs].from = ge->iy3;
3611                      vs[g->nvs].to = ge->prev->iy3;
3612                  }
3613                  vs[g->nvs].origin = ge->iy3;
3614                  vs[g->nvs].ge = ge->frwd;
3615  
3616                  pge = ge->bkwd;
3617  
3618                  /* add beginning as hstem */
3619                  hs[g->nhs].value = pge->iy3;
3620                  hs[g->nhs].origin
3621                      = hs[g->nhs].from
3622                      = hs[g->nhs].to = pge->ix3;
3623                  hs[g->nhs].ge = ge;
3624  
3625                  if(pge->type==GE_CURVE)
3626                      ovalue=pge->ix2;
3627                  else
3628                      ovalue=pge->prev->ix3;
3629  
3630                  if (pge->ix3 < ovalue)
3631                      hs[g->nhs].flags = ST_UP | ST_END;
3632                  else if (pge->ix3 > ovalue)
3633                      hs[g->nhs].flags = ST_END;
3634                  else
3635                      hs[g->nhs].flags = 0;
3636  
3637                  if( hs[g->nhs].flags != 0 )
3638                      g->nhs++;
3639  
3640                  /* add end as hstem */
3641                  hs[g->nhs].value = ge->iy3;
3642                  hs[g->nhs].origin
3643                      = hs[g->nhs].from
3644                      = hs[g->nhs].to = ge->ix3;
3645                  hs[g->nhs].ge = ge->frwd;
3646  
3647                  if(nge->type==GE_CURVE)
3648                      ovalue=nge->ix1;
3649                  else
3650                      ovalue=nge->ix3;
3651  
3652                  if (ovalue < ge->ix3)
3653                      hs[g->nhs].flags = ST_UP | ST_END;
3654                  else if (ovalue > ge->ix3)
3655                      hs[g->nhs].flags = ST_END;
3656                  else
3657                      hs[g->nhs].flags = 0;
3658  
3659                  if( hs[g->nhs].flags != 0 )
3660                      g->nhs++;
3661  
3662                  g->nvs++;
3663              }
3664              /*
3665               * check the end of line for a not smooth local
3666               * extremum
3667               */
3668              nge = ge->frwd;
3669  
3670              if (nge == 0)
3671                  continue;
3672              else if (nge->type == GE_LINE) {
3673                  nx = nge->ix3;
3674                  ny = nge->iy3;
3675              } else if (nge->type == GE_CURVE) {
3676                  nx = nge->ix1;
3677                  ny = nge->iy1;
3678              } else
3679                  continue;
3680  
3681              /* check for vertical extremums */
3682              if (ge->iy3 > ge->prev->iy3 && ge->iy3 > ny
3683              || ge->iy3 < ge->prev->iy3 && ge->iy3 < ny) {
3684                  hs[g->nhs].value = ge->iy3;
3685                  hs[g->nhs].from
3686                      = hs[g->nhs].to
3687                      = hs[g->nhs].origin = ge->ix3;
3688                  hs[g->nhs].ge = ge->frwd;
3689  
3690                  if (ge->ix3 < ge->prev->ix3
3691                      || nx < ge->ix3)
3692                      hs[g->nhs].flags = ST_UP;
3693                  else
3694                      hs[g->nhs].flags = 0;
3695  
3696                  if (ge->ix3 != ge->prev->ix3 || nx != ge->ix3)
3697                      g->nhs++;
3698              }
3699              /*
3700               * the same point may be both horizontal and vertical
3701               * extremum
3702               */
3703              /* check for horizontal extremums */
3704              if (ge->ix3 > ge->prev->ix3 && ge->ix3 > nx
3705              || ge->ix3 < ge->prev->ix3 && ge->ix3 < nx) {
3706                  vs[g->nvs].value = ge->ix3;
3707                  vs[g->nvs].from
3708                      = vs[g->nvs].to
3709                      = vs[g->nvs].origin = ge->iy3;
3710                  vs[g->nvs].ge = ge->frwd;
3711  
3712                  if (ge->iy3 > ge->prev->iy3
3713                      || ny > ge->iy3)
3714                      vs[g->nvs].flags = ST_UP;
3715                  else
3716                      vs[g->nvs].flags = 0;
3717  
3718                  if (ge->iy3 != ge->prev->iy3 || ny != ge->iy3)
3719                      g->nvs++;
3720              }
3721          }
3722      }
3723  
3724      g->nhs=addbluestems(hs, g->nhs);
3725      sortstems(hs, g->nhs);
3726      sortstems(vs, g->nvs);
3727  
3728      if (ISDBG(STEMS))
3729          debugstems(g->name, hs, g->nhs, vs, g->nvs);
3730  
3731      /* find the stems interacting with the Blue Zones */
3732      markbluestems(hs, g->nhs);
3733  
3734      if(subhints) {
3735          if (ISDBG(SUBSTEMS))
3736              fprintf(pfa_file, "%% %s: joining subst horizontal stems\n", g->name);
3737          joinsubstems(hs, hs_pairs, g->nhs, 1);
3738          uniformstems(hs, hs_pairs, g->nhs);
3739  
3740          if (ISDBG(SUBSTEMS))
3741              fprintf(pfa_file, "%% %s: joining subst vertical stems\n", g->name);
3742          joinsubstems(vs, vs_pairs, g->nvs, 0);
3743  
3744          groupsubstems(g, hs, hs_pairs, g->nhs, vs, vs_pairs, g->nvs);
3745      }
3746  
3747      if (ISDBG(MAINSTEMS))
3748          fprintf(pfa_file, "%% %s: joining main horizontal stems\n", g->name);
3749      g->nhs = joinmainstems(hs, g->nhs, 1);
3750      if (ISDBG(MAINSTEMS))
3751          fprintf(pfa_file, "%% %s: joining main vertical stems\n", g->name);
3752      g->nvs = joinmainstems(vs, g->nvs, 0);
3753  
3754      if (ISDBG(MAINSTEMS))
3755          debugstems(g->name, hs, g->nhs, vs, g->nvs);
3756  
3757      if(g->nhs > 0) {
3758          if ((sp = malloc(sizeof(STEM) * g->nhs)) == 0) {
3759              fprintf(stderr, "**** not enough memory for hints ****\n");
3760              exit(255);
3761          }
3762          g->hstems = sp;
3763          memcpy(sp, hs, sizeof(STEM) * g->nhs);
3764      } else
3765          g->hstems = 0;
3766  
3767      if(g->nvs > 0) {
3768          if ((sp = malloc(sizeof(STEM) * g->nvs)) == 0) {
3769              fprintf(stderr, "**** not enough memory for hints ****\n");
3770              exit(255);
3771          }
3772          g->vstems = sp;
3773          memcpy(sp, vs, sizeof(STEM) * g->nvs);
3774      } else
3775          g->vstems = 0;
3776  
3777      /* now check that the stems won't overflow the interpreter's stem stack:
3778       * some interpreters (like X11) push the stems on each change into
3779       * stack and pop them only after the whole glyphs is completed.
3780       */
3781  
3782      totals = (g->nhs+g->nvs) / 2; /* we count whole stems, not halves */
3783      lastgrp = -1;
3784  
3785      for (ge = g->entries; ge != 0; ge = ge->next) {
3786          grp=ge->stemid;
3787          if(grp >= 0 && grp != lastgrp)  {
3788              if(grp==0)
3789                  totals += g->nsbs[0];
3790              else
3791                  totals += g->nsbs[grp] - g->nsbs[grp-1];
3792  
3793              lastgrp = grp;
3794          }
3795      }
3796  
3797      /* be on the safe side, check for >= , not > */
3798      if(totals >= max_stemdepth) {  /* oops, too deep */
3799          WARNING_2 {
3800              fprintf(stderr, "Warning: glyph %s needs hint stack depth %d\n", g->name, totals);
3801              fprintf(stderr, "  (limit %d): removed the substituted hints from it\n", max_stemdepth);
3802          }
3803          if(g->nsg > 0) {
3804              for (ge = g->entries; ge != 0; ge = ge->next)
3805                  ge->stemid = -1;
3806              free(g->sbstems); g->sbstems = 0;
3807              free(g->nsbs); g->nsbs = 0;
3808              g->nsg = 0;
3809          }
3810      }
3811  
3812      /* now check if there are too many main stems */
3813      totals = (g->nhs+g->nvs) / 2; /* we count whole stems, not halves */
3814      if(totals >= max_stemdepth) { 
3815          /* even worse, too much of non-substituted stems */
3816          WARNING_2 {
3817              fprintf(stderr, "Warning: glyph %s has %d main hints\n", g->name, totals);
3818              fprintf(stderr, "  (limit %d): removed the hints from it\n", max_stemdepth);
3819          }
3820          if(g->vstems) {
3821              free(g->vstems); g->vstems = 0; g->nvs = 0;
3822          }
3823          if(g->hstems) {
3824              free(g->hstems); g->hstems = 0; g->nhs = 0;
3825          }
3826      }
3827  }
3828  
3829  /* convert weird curves that are close to lines into lines.
3830  */
3831  
3832  void
3833  fstraighten(
3834         GLYPH * g
3835  )
3836  {
3837      GENTRY         *ge, *pge, *nge, *ige;
3838      double          df;
3839      int             dir;
3840      double          iln, oln;
3841      int             svdir, i, o;
3842  
3843      for (ige = g->entries; ige != 0; ige = ige->next) {
3844          if (ige->type != GE_CURVE)
3845              continue;
3846  
3847          ge = ige;
3848          pge = ge->bkwd;
3849          nge = ge->frwd;
3850  
3851          df = 0.;
3852  
3853          /* look for vertical then horizontal */
3854          for(i=0; i<2; i++) {
3855              o = !i; /* other axis */
3856  
3857              iln = fabs(ge->fpoints[i][2] - pge->fpoints[i][2]);
3858              oln = fabs(ge->fpoints[o][2] - pge->fpoints[o][2]);
3859              /*
3860               * if current curve is almost a vertical line, and it
3861               * doesn't begin or end horizontally (and the prev/next
3862               * line doesn't join smoothly ?)
3863               */
3864              if( oln < 1.
3865              || ge->fpoints[o][2] == ge->fpoints[o][1] 
3866              || ge->fpoints[o][0] == pge->fpoints[o][2]
3867              || iln > 2.
3868              || iln > 1.  && iln/oln > 0.1 )
3869                  continue;
3870  
3871  
3872              if(ISDBG(STRAIGHTEN)) 
3873                  fprintf(stderr,"** straighten almost %s\n", (i? "horizontal":"vertical"));
3874  
3875              df = ge->fpoints[i][2] - pge->fpoints[i][2];
3876              dir = fsign(ge->fpoints[o][2] - pge->fpoints[o][2]);
3877              ge->type = GE_LINE;
3878  
3879              /*
3880               * suck in all the sequence of such almost lines
3881               * going in the same direction but not deviating
3882               * too far from vertical
3883               */
3884              iln = fabs(nge->fpoints[i][2] - ge->fpoints[i][2]);
3885              oln = nge->fpoints[o][2] - ge->fpoints[o][2];
3886  
3887              while (fabs(df) <= 5 && nge->type == GE_CURVE
3888              && dir == fsign(oln) /* that also gives oln != 0 */
3889              && iln <= 2.
3890              && ( iln <= 1.  || iln/fabs(oln) <= 0.1 ) ) {
3891                  ge->fx3 = nge->fx3;
3892                  ge->fy3 = nge->fy3;
3893  
3894                  if(ISDBG(STRAIGHTEN))
3895                      fprintf(stderr,"** straighten collapsing %s\n", (i? "horizontal":"vertical"));
3896                  freethisge(nge);
3897                  fixendpath(ge);
3898                  pge = ge->bkwd;
3899                  nge = ge->frwd;
3900  
3901                  df = ge->fpoints[i][2] - pge->fpoints[i][2];
3902  
3903                  iln = fabs(nge->fpoints[i][2] - ge->fpoints[i][2]);
3904                  oln = nge->fpoints[o][2] - ge->fpoints[o][2];
3905              }
3906  
3907              /* now check what do we have as previous/next line */
3908  
3909              if(ge != pge) { 
3910                  if( pge->type == GE_LINE && pge->fpoints[i][2] == pge->prev->fpoints[i][2]
3911                  && fabs(pge->fpoints[o][2] != pge->prev->fpoints[o][2]) ) {
3912                      if(ISDBG(STRAIGHTEN)) fprintf(stderr,"** straighten join with previous 0x%x 0x%x\n", pge, ge);
3913                      /* join the previous line with current */
3914                      pge->fx3 = ge->fx3;
3915                      pge->fy3 = ge->fy3;
3916  
3917                      ige = freethisge(ge)->prev; /* keep the iterator valid */
3918                      ge = pge;
3919                      fixendpath(ge);
3920                      pge = ge->bkwd;
3921                  }
3922              }
3923  
3924              if(ge != nge) { 
3925                  if (nge->type == GE_LINE && nge->fpoints[i][2] == ge->fpoints[i][2]
3926                  && fabs(nge->fpoints[o][2] != ge->fpoints[o][2]) ) {
3927                      if(ISDBG(STRAIGHTEN)) fprintf(stderr,"** straighten join with next 0x%x 0x%x\n", ge, nge);
3928                      /* join the next line with current */
3929                      ge->fx3 = nge->fx3;
3930                      ge->fy3 = nge->fy3;
3931  
3932                      freethisge(nge);
3933                      fixendpath(ge);
3934                      pge = ge->bkwd;
3935                      nge = ge->frwd;
3936  
3937                  }
3938              }
3939  
3940              if(ge != pge) { 
3941                  /* try to align the lines if neccessary */
3942                  if(df != 0.)
3943                      fclosegap(ge, ge, i, df, NULL);
3944              } else {
3945                  /* contour consists of only one line, get rid of it */
3946                  ige = freethisge(ge); /* keep the iterator valid */
3947                  if(ige == 0) /* this was the last contour */
3948                      return;
3949                  ige = ige->prev;
3950              }
3951  
3952              break; /* don't bother looking at the other axis */
3953          }
3954      }
3955  }
3956  
3957  /* solve a square equation,
3958   * returns the number of solutions found, the solutions
3959   * are stored in res which should point to array of two doubles.
3960   * min and max limit the area for solutions
3961   */
3962  
3963  static int
3964  fsqequation(
3965      double a,
3966      double b,
3967      double c,
3968      double *res,
3969      double min,
3970      double max
3971  )
3972  {
3973      double D;
3974      int n;
3975  
3976      if(ISDBG(SQEQ)) fprintf(stderr, "sqeq(%g,%g,%g) [%g;%g]\n", a, b, c, min, max);
3977  
3978      if(fabs(a) < 0.000001) { /* if a linear equation */
3979          n=0;
3980          if(fabs(b) < 0.000001) /* not an equation at all */
3981              return 0;
3982          res[0] = -c/b;
3983          if(ISDBG(SQEQ)) fprintf(stderr, "sqeq: linear t=%g\n", res[0]);
3984          if(res[0] >= min && res[0] <= max)
3985              n++;
3986          return n;
3987      }
3988  
3989      D = b*b - 4.0*a*c;
3990      if(ISDBG(SQEQ)) fprintf(stderr, "sqeq: D=%g\n", D);
3991      if(D<0)
3992          return 0;
3993  
3994      D = sqrt(D);
3995  
3996      n=0;
3997      res[0] = (-b+D) / (2*a);
3998      if(ISDBG(SQEQ)) fprintf(stderr, "sqeq: t1=%g\n", res[0]);
3999      if(res[0] >= min && res[0] <= max)
4000          n++;
4001  
4002      res[n] = (-b-D) / (2*a);
4003      if(ISDBG(SQEQ)) fprintf(stderr, "sqeq: t2=%g\n", res[n]);
4004      if(res[n] >= min && res[n] <= max)
4005          n++;
4006  
4007      /* return 2nd solution only if it's different enough */
4008      if(n==2 && fabs(res[0]-res[1])<0.000001)
4009          n=1;
4010  
4011      return n;
4012  }
4013  
4014  /* check that the curves don't cross quadrant boundary */
4015  /* (float) */
4016  
4017  /*
4018    Here we make sure that the curve does not continue past
4019    horizontal or vertical extremums. The horizontal points are
4020    explained, vertical points are by analogy.
4021  
4022    The horizontal points are where the derivative
4023    dy/dx is equal to 0. But the Bezier curves are defined by
4024    parametric formulas
4025     x=fx(t)
4026     y=fy(t)
4027    so finding this derivative is complicated.
4028    Also even if we find some point (x,y) splitting at this point
4029    is far not obvious. Fortunately we can use dy/dt = 0 instead,
4030    this gets to a rather simple square equation and splitting
4031    at a known value of t is simple.
4032  
4033    The formulas are:
4034  
4035    y = A*(1-t)^3 + 3*B*(1-t)^2*t + 3*C*(1-t)*t^2 + D*t^3
4036    y = (-A+3*B-3*C+D)*t^3 + (3*A-6*B+3*C)*t^2 + (-3*A+3*B)*t + A
4037    dy/dt = 3*(-A+3*B-3*C+D)*t^2 + 2*(3*A-6*B+3*C)*t + (-3*A+3*B)
4038   */
4039  
4040  void
4041  ffixquadrants(
4042      GLYPH *g
4043  )
4044  {
4045      GENTRY         *ge, *nge;
4046      int    i, j, np, oldnp;
4047      double    sp[5]; /* split points, last one empty */
4048      char dir[5]; /* for debugging, direction by which split happened */
4049      double a, b, *pts; /* points of a curve */
4050  
4051      for (ge = g->entries; ge != 0; ge = ge->next) {
4052          if (ge->type != GE_CURVE)
4053              continue;
4054          
4055      doagain:
4056          np = 0; /* no split points yet */
4057          if(ISDBG(QUAD)) {
4058              fprintf(stderr, "%s: trying 0x%x (%g %g) (%g %g) (%g %g) (%g %g)\n  ", g->name,
4059                  ge,  ge->prev->fx3, ge->prev->fy3, ge->fx1, ge->fy1, ge->fx2, ge->fy2,
4060                  ge->fx3, ge->fy3);
4061          }
4062          for(i=0; i<2; i++) { /* first for x then for y */
4063              /* find the cooridnates of control points */
4064              a = ge->prev->fpoints[i][2];
4065              pts = &ge->fpoints[i][0];
4066  
4067              oldnp = np;
4068              np += fsqequation(
4069                  3.0*(-a + 3.0*pts[0] - 3.0*pts[1] + pts[2]),
4070                  6.0*(a - 2.0*pts[0] + pts[1]),
4071                  3.0*(-a + pts[0]),
4072                  &sp[np],
4073                  0.0, 1.0); /* XXX range is [0;1] */
4074  
4075              if(np == oldnp)
4076                  continue;
4077  
4078              if(ISDBG(QUAD))
4079                  fprintf(stderr, "%s: 0x%x: %d pts(%c): ", 
4080                      g->name, ge, np-oldnp, i? 'y':'x');
4081  
4082              /* remove points that are too close to the ends 
4083               * because hor/vert ends are permitted, also
4084               * if the split point is VERY close to the ends
4085               * but not exactly then just flatten it and check again.
4086               */
4087              for(j = oldnp; j<np; j++) {
4088                  dir[j] = i;
4089                  if(ISDBG(QUAD))
4090                      fprintf(stderr, "%g ", sp[j]);
4091                  if(sp[j] < 0.03) { /* front end of curve */
4092                      if(ge->fpoints[i][0] != ge->prev->fpoints[i][2]) {
4093                          ge->fpoints[i][0] = ge->prev->fpoints[i][2];
4094                          if(ISDBG(QUAD)) fprintf(stderr, "flattened at front\n");
4095                          goto doagain;
4096                      }
4097                      if( ge->fpoints[i][1] != ge->fpoints[i][0]
4098                      && fsign(ge->fpoints[i][2] - ge->fpoints[i][1])
4099                              != fsign(ge->fpoints[i][1] - ge->fpoints[i][0]) ) {
4100                          ge->fpoints[i][1] = ge->fpoints[i][0];
4101                          if(ISDBG(QUAD)) fprintf(stderr, "flattened zigzag at front\n");
4102                          goto doagain;
4103                      }
4104                      sp[j] = sp[j+1]; np--; j--;
4105                      if(ISDBG(QUAD)) fprintf(stderr, "(front flat)  ");
4106                  } else if(sp[j] > 0.97) { /* rear end of curve */
4107                      if(ge->fpoints[i][1] != ge->fpoints[i][2]) {
4108                          ge->fpoints[i][1] = ge->fpoints[i][2];
4109                          if(ISDBG(QUAD)) fprintf(stderr, "flattened at rear\n");
4110                          goto doagain;
4111                      }
4112                      if( ge->fpoints[i][0] != ge->fpoints[i][1]
4113                      && fsign(ge->prev->fpoints[i][2] - ge->fpoints[i][0])
4114                              != fsign(ge->fpoints[i][0] - ge->fpoints[i][1]) ) {
4115                          ge->fpoints[i][0] = ge->fpoints[i][1];
4116                          if(ISDBG(QUAD)) fprintf(stderr, "flattened zigzag at rear\n");
4117                          goto doagain;
4118                      }
4119                      sp[j] = sp[j+1]; np--; j--;
4120                      if(ISDBG(QUAD)) fprintf(stderr, "(rear flat)  ");
4121                  } 
4122              }
4123              if(ISDBG(QUAD)) fprintf(stderr, "\n");
4124          }
4125  
4126          if(np==0) /* no split points, leave it alone */
4127              continue;
4128  
4129          if(ISDBG(QUAD)) {
4130              fprintf(stderr, "%s: splitting 0x%x (%g %g) (%g %g) (%g %g) (%g %g) at %d points\n  ", g->name,
4131                  ge,  ge->prev->fx3, ge->prev->fy3, ge->fx1, ge->fy1, ge->fx2, ge->fy2,
4132                  ge->fx3, ge->fy3, np);
4133              for(i=0; i<np; i++)
4134                  fprintf(stderr, "%g(%c) ", sp[i], dir[i] ? 'y':'x');
4135              fprintf(stderr, "\n");
4136          }
4137  
4138          /* sort the points ascending */
4139          for(i=0; i<np; i++)
4140              for(j=i+1; j<np; j++)
4141                  if(sp[i] > sp[j]) {
4142                      a = sp[i]; sp[i] = sp[j]; sp[j] = a;
4143                  }
4144  
4145          /* now finally do the split on each point */
4146          for(j=0; j<np; j++) {
4147              double k1, k2, c;
4148  
4149              k1 = sp[j];
4150              k2 = 1 - k1;
4151  
4152              if(ISDBG(QUAD)) fprintf(stderr, "   0x%x %g/%g\n", ge, k1, k2);
4153  
4154              nge = newgentry(GEF_FLOAT);
4155              (*nge) = (*ge);
4156  
4157  #define SPLIT(pt1, pt2)    ( (pt1) + k1*((pt2)-(pt1)) ) /* order is important! */
4158              for(i=0; i<2; i++) { /* for x and y */
4159                  a = ge->fpoints[i][0]; /* get the middle points */
4160                  b = ge->fpoints[i][1];
4161  
4162                  /* calculate new internal points */
4163                  c = SPLIT(a, b);
4164  
4165                  ge->fpoints[i][0] = SPLIT(ge->prev->fpoints[i][2], a);
4166                  ge->fpoints[i][1] = SPLIT(ge->fpoints[i][0], c);
4167  
4168                  nge->fpoints[i][1] = SPLIT(b, nge->fpoints[i][2]);
4169                  nge->fpoints[i][0] = SPLIT(c, nge->fpoints[i][1]);
4170  
4171                  ge->fpoints[i][2] = SPLIT(ge->fpoints[i][1],
4172                      + nge->fpoints[i][0]);
4173              }
4174  #undef SPLIT
4175  
4176              addgeafter(ge, nge);
4177  
4178              /* go to the next part, adjust remaining points */
4179              ge = nge;
4180              for(i=j+1; i<np; i++)
4181                  sp[i] = (sp[i]-k1) / k2;
4182          }
4183      }
4184  
4185  }
4186  
4187  /* check if a curve is a zigzag */
4188  
4189  static int
4190  iiszigzag(
4191      GENTRY *ge
4192  ) 
4193  {
4194      double          k, k1, k2;
4195      int             a, b;
4196  
4197      if (ge->type != GE_CURVE)
4198          return 0;
4199  
4200      a = ge->iy2 - ge->iy1;
4201      b = ge->ix2 - ge->ix1;
4202      if(a == 0) {
4203          if(b == 0) {
4204              return 0;
4205          } else
4206              k = FBIGVAL;
4207      } else
4208          k = fabs((double) b / (double) a);
4209  
4210      a = ge->iy1 - ge->prev->iy3;
4211      b = ge->ix1 - ge->prev->ix3;
4212      if(a == 0) {
4213          if(b == 0) {
4214              return 0;
4215          } else
4216              k1 = FBIGVAL;
4217      } else
4218          k1 = fabs((double) b / (double) a);
4219  
4220      a = ge->iy3 - ge->iy2;
4221      b = ge->ix3 - ge->ix2;
4222      if(a == 0) {
4223          if(b == 0) {
4224              return 0;
4225          } else
4226              k2 = FBIGVAL;
4227      } else
4228          k2 = fabs((double) b / (double) a);
4229  
4230      /* if the curve is not a zigzag */
4231      if (k1+0.0001 >= k && k2 <= k+0.0001 || k1 <= k+0.0001 && k2+0.0001 >= k)
4232          return 0;
4233      else
4234          return 1;
4235  }
4236  
4237  /* check if a curve is a zigzag - floating */
4238  
4239  static int
4240  fiszigzag(
4241      GENTRY *ge
4242  ) 
4243  {
4244      double          k, k1, k2;
4245      double          a, b;
4246  
4247      if (ge->type != GE_CURVE)
4248          return 0;
4249  
4250      a = fabs(ge->fy2 - ge->fy1);
4251      b = fabs(ge->fx2 - ge->fx1);
4252      if(a < FEPS) {
4253          if(b < FEPS) {
4254              return 0;
4255          } else
4256              k = FBIGVAL;
4257      } else
4258          k = b / a;
4259  
4260      a = fabs(ge->fy1 - ge->prev->fy3);
4261      b = fabs(ge->fx1 - ge->prev->fx3);
4262      if(a < FEPS) {
4263          if(b < FEPS) {
4264              return 0;
4265          } else
4266              k1 = FBIGVAL;
4267      } else
4268          k1 = b / a;
4269  
4270      a = fabs(ge->fy3 - ge->fy2);
4271      b = fabs(ge->fx3 - ge->fx2);
4272      if(a < FEPS) {
4273          if(b < FEPS) {
4274              return 0;
4275          } else
4276              k2 = FBIGVAL;
4277      } else
4278          k2 = b / a;
4279  
4280      /* if the curve is not a zigzag */
4281      if (k1+0.0001 >= k && k2 <= k+0.0001 || k1 <= k+0.0001 && k2+0.0001 >= k)
4282          return 0;
4283      else
4284          return 1;
4285  }
4286  
4287  /* split the zigzag-like curves into two parts */
4288  
4289  void
4290  fsplitzigzags(
4291           GLYPH * g
4292  )
4293  {
4294      GENTRY         *ge, *nge;
4295      double          a, b, c, d;
4296  
4297      assertisfloat(g, "splitting zigzags");
4298      for (ge = g->entries; ge != 0; ge = ge->next) {
4299          if (ge->type != GE_CURVE)
4300              continue;
4301  
4302          /* if the curve is not a zigzag */
4303          if ( !fiszigzag(ge) ) {
4304              continue;
4305          }
4306  
4307          if(ISDBG(FCONCISE)) {
4308              double maxsc1, maxsc2; 
4309              fprintf(stderr, "split a zigzag ");
4310              fnormalizege(ge);
4311              if( fcrossraysge(ge, ge, &maxsc1, &maxsc2, NULL) ) {
4312                  fprintf(stderr, "sc1=%g sc2=%g\n", maxsc1, maxsc2);
4313              } else {
4314                  fprintf(stderr, "(rays don't cross)\n");
4315              }
4316          }
4317          /* split the curve by t=0.5 */
4318          nge = newgentry(GEF_FLOAT);
4319          (*nge) = (*ge);
4320          nge->type = GE_CURVE;
4321  
4322          a = ge->prev->fx3;
4323          b = ge->fx1;
4324          c = ge->fx2;
4325          d = ge->fx3;
4326          nge->fx3 = d;
4327          nge->fx2 = (c + d) / 2.;
4328          nge->fx1 = (b + 2. * c + d) / 4.;
4329          ge->fx3 = (a + b * 3. + c * 3. + d) / 8.;
4330          ge->fx2 = (a + 2. * b + c) / 4.;
4331          ge->fx1 = (a + b) / 2.;
4332  
4333          a = ge->prev->fy3;
4334          b = ge->fy1;
4335          c = ge->fy2;
4336          d = ge->fy3;
4337          nge->fy3 = d;
4338          nge->fy2 = (c + d) / 2.;
4339          nge->fy1 = (b + 2. * c + d) / 4.;
4340          ge->fy3 = (a + b * 3. + c * 3. + d) / 8.;
4341          ge->fy2 = (a + 2. * b + c) / 4.;
4342          ge->fy1 = (a + b) / 2.;
4343  
4344          addgeafter(ge, nge);
4345  
4346          if(ISDBG(FCONCISE)) {
4347              dumppaths(g, ge, nge);
4348          }
4349      }
4350  }
4351  
4352  /* free this GENTRY, returns what was ge->next
4353   * (ge must be of type GE_LINE or GE_CURVE)
4354   * works on both float and int entries
4355   */
4356  
4357  static GENTRY *
4358  freethisge(
4359      GENTRY *ge
4360  )
4361  {
4362      GENTRY *xge;
4363  
4364      if (ge->bkwd != ge->prev) {
4365          /* at beginning of the contour */
4366  
4367          xge = ge->bkwd;
4368          if(xge == ge) { /* was the only line in contour */
4369              /* remove the contour completely */
4370              /* prev is GE_MOVE, next is GE_PATH, remove them all */
4371  
4372              /* may be the first contour, then ->bkwd points to ge->entries */
4373              if(ge->prev->prev == 0)
4374                  *(GENTRY **)(ge->prev->bkwd) = ge->next->next;
4375              else
4376                  ge->prev->prev->next = ge->next->next;
4377  
4378              if(ge->next->next) {
4379                  ge->next->next->prev = ge->prev->prev;
4380                  ge->next->next->bkwd = ge->prev->bkwd;
4381              }
4382  
4383              xge = ge->next->next;
4384              free(ge->prev); free(ge->next); free(ge);
4385              return xge;
4386          }
4387  
4388          /* move the start point of the contour */
4389          if(ge->flags & GEF_FLOAT) {
4390              ge->prev->fx3 = xge->fx3;
4391              ge->prev->fy3 = xge->fy3;
4392          } else {
4393              ge->prev->ix3 = xge->ix3;
4394              ge->prev->iy3 = xge->iy3;
4395          }
4396      } else if(ge->frwd != ge->next) {
4397          /* at end of the contour */
4398  
4399          xge = ge->frwd->prev;
4400          /* move the start point of the contour */
4401          if(ge->flags & GEF_FLOAT) {
4402              xge->fx3 = ge->bkwd->fx3;
4403              xge->fy3 = ge->bkwd->fy3;
4404          } else {
4405              xge->ix3 = ge->bkwd->ix3;
4406              xge->iy3 = ge->bkwd->iy3;
4407          }
4408      }
4409  
4410      ge->prev->next = ge->next;
4411      ge->next->prev = ge->prev;
4412      ge->bkwd->frwd = ge->frwd;
4413      ge->frwd->bkwd = ge->bkwd;
4414  
4415      xge = ge->next;
4416      free(ge);
4417      return xge;
4418  }
4419  
4420  /* inserts a new gentry (LINE or CURVE) after another (MOVE
4421   * or LINE or CURVE)
4422   * corrects the first GE_MOVE if neccessary
4423   */
4424  
4425  static void
4426  addgeafter(
4427      GENTRY *oge, /* after this */
4428      GENTRY *nge /* insert this */
4429  )
4430  {
4431      if(oge->type == GE_MOVE) {
4432          /* insert before next */
4433          if(oge->next->type == GE_PATH) {
4434              /* first and only GENTRY in path */
4435              nge->frwd = nge->bkwd = nge;
4436          } else {
4437              nge->frwd = oge->next;
4438              nge->bkwd = oge->next->bkwd;
4439              oge->next->bkwd->frwd = nge;
4440              oge->next->bkwd = nge;
4441          }
4442      } else {
4443          nge->frwd = oge->frwd;
4444          nge->bkwd = oge;
4445          oge->frwd->bkwd = nge;
4446          oge->frwd = nge;
4447      }
4448  
4449      nge->next = oge->next;
4450      nge->prev = oge;
4451      oge->next->prev = nge;
4452      oge->next = nge;
4453  
4454      if(nge->frwd->prev->type == GE_MOVE) {
4455          /* fix up the GE_MOVE entry */
4456          if(nge->flags & GEF_FLOAT) {
4457              nge->frwd->prev->fx3 = nge->fx3;
4458              nge->frwd->prev->fy3 = nge->fy3;
4459          } else {
4460              nge->frwd->prev->ix3 = nge->ix3;
4461              nge->frwd->prev->iy3 = nge->iy3;
4462          }
4463      }
4464  }
4465  
4466  /*
4467   * Check if this GENTRY happens to be at the end of path
4468   * and fix the first MOVETO accordingly
4469   * handles both int and float
4470   */
4471  
4472  static void
4473  fixendpath(
4474      GENTRY *ge
4475  )
4476  {
4477      GENTRY *mge;
4478  
4479      mge = ge->frwd->prev;
4480      if(mge->type == GE_MOVE) {
4481          if(ge->flags & GEF_FLOAT) {
4482              mge->fx3 = ge->fx3;
4483              mge->fy3 = ge->fy3;
4484          } else {
4485              mge->ix3 = ge->ix3;
4486              mge->iy3 = ge->iy3;
4487          }
4488      }
4489  }
4490  
4491  /*
4492   * This function adjusts the rest of path (the part from...to is NOT changed)
4493   * to cover the specified gap by the specified axis (0 - X, 1 - Y).
4494   * Gap is counted in direction (end_of_to - beginning_of_from).
4495   * Returns by how much the gap was not closed (0.0 if it was fully closed).
4496   * Ret contains by how much the first and last points of [from...to]
4497   * were moved to bring them in consistence to the rest of the path.
4498   * If ret==NULL then this info is not returned.
4499   */
4500  
4501  static double
4502  fclosegap(
4503      GENTRY *from,
4504      GENTRY *to,
4505      int axis,
4506      double gap,
4507      double *ret
4508  )
4509  {
4510  #define TIMESLARGER 10.    /* how many times larger must be a curve to not change too much */
4511      double rm[2];
4512      double oldpos[2];
4513      double times, limit, df, dx;
4514      int j, k;
4515      GENTRY *xge, *pge, *nge, *bge[2];
4516  
4517      /* remember the old points to calculate ret */
4518      oldpos[0] = from->prev->fpoints[axis][2];
4519      oldpos[1] = to->fpoints[axis][2];
4520  
4521      rm[0] = rm[1] = gap / 2. ;
4522  
4523      bge[0] = from; /* this is convenient for iterations */
4524      bge[1] = to;
4525  
4526      /* first try to modify large curves but if have none then settle for small */
4527      for(times = (TIMESLARGER-1); times > 0.1; times /= 2. ) {
4528  
4529          if(rm[0]+rm[1] == 0.)
4530              break;
4531  
4532          /* iterate in both directions, backwards then forwards */
4533          for(j = 0; j<2; j++) {
4534  
4535              if(rm[j] == 0.) /* if this direction is exhausted */
4536                  continue;
4537  
4538              limit = fabs(rm[j]) * (1.+times);
4539  
4540              for(xge = bge[j]->cntr[j]; xge != bge[!j]; xge = xge->cntr[j]) {
4541                  dx = xge->fpoints[axis][2] - xge->prev->fpoints[axis][2];
4542                  df = fabs(dx) - limit;
4543                  if( df <= FEPS ) /* curve is too small to change */
4544                      continue;
4545  
4546                  if( df >= fabs(rm[j]) )
4547                      df = rm[j];
4548                  else 
4549                      df *= fsign(rm[j]); /* we may cover this part of rm */
4550  
4551                  rm[j] -= df;
4552                  limit = fabs(rm[j]) * (1.+times);
4553  
4554                  if(xge->type == GE_CURVE) { /* correct internal points */
4555                      double scale = ((dx+df) / dx) - 1.;
4556                      double base;
4557  
4558                      if(j)
4559                          base = xge->fpoints[axis][2];
4560                      else
4561                          base = xge->prev->fpoints[axis][2];
4562  
4563                      for(k = 0; k<2; k++)
4564                          xge->fpoints[axis][k] += scale * 
4565                              (xge->fpoints[axis][k] - base);
4566                  }
4567  
4568                  /* move all the intermediate lines */
4569                  if(j) {
4570                      df = -df; /* absolute direction */
4571                      pge = bge[1]->bkwd;
4572                      nge = xge->bkwd;
4573                  } else {
4574                      xge->fpoints[axis][2] += df;
4575                      pge = bge[0];
4576                      nge = xge->frwd;
4577                  }
4578                  while(nge != pge) {
4579                      if(nge->type == GE_CURVE) {
4580                          nge->fpoints[axis][0] +=df;
4581                          nge->fpoints[axis][1] +=df;
4582                      }
4583                      nge->fpoints[axis][2] += df;
4584                      if(nge->next != nge->frwd) { /* last entry of contour */
4585                          nge->frwd->prev->fpoints[axis][2] += df;
4586                      }
4587                      nge = nge->cntr[!j];
4588                  }
4589  
4590                  if(rm[j] == 0.)
4591                      break;
4592              }
4593          }
4594      }
4595  
4596      /* find the difference */
4597      oldpos[0] -= from->prev->fpoints[axis][2];
4598      oldpos[1] -= to->fpoints[axis][2];
4599  
4600      if(ret) {
4601          ret[0] = oldpos[0] - from->prev->fpoints[axis][2];
4602          ret[1] = oldpos[1] - to->fpoints[axis][2];
4603      }
4604  
4605  #if 0
4606      if( rm[0]+rm[1] != gap - oldpos[1] + oldpos[0]) {
4607          fprintf(stderr, "** gap=%g rm[0]=%g rm[1]=%g o[0]=%g o[1]=%g rg=%g og=%g\n",
4608              gap, rm[0], rm[1], oldpos[0], oldpos[1], rm[0]+rm[1], 
4609              gap - oldpos[1] + oldpos[0]);
4610      }
4611  #endif
4612  
4613      return rm[0]+rm[1];
4614  #undef TIMESLARGER
4615  }
4616  
4617  /* remove the lines or curves smaller or equal to the size limit */
4618  
4619  static void
4620  fdelsmall(
4621      GLYPH *g,
4622      double minlen
4623  )
4624  {
4625      GENTRY  *ge, *nge, *pge, *xge, *next;
4626      int i, k;
4627      double dx, dy, d2, d2m;
4628      double minlen2;
4629  #define TIMESLARGER 10.    /* how much larger must be a curve to not change too much */
4630  
4631      minlen2 = minlen*minlen;
4632  
4633      for (ge = g->entries; ge != 0; ge = next) {
4634          next = ge->next;
4635  
4636          if (ge->type != GE_CURVE && ge->type != GE_LINE)
4637              continue;
4638  
4639          d2m = 0;
4640          for(i= (ge->type==GE_CURVE? 0: 2); i<3; i++) {
4641              dx = ge->fxn[i] - ge->prev->fx3;
4642              dy = ge->fyn[i] - ge->prev->fy3;
4643              d2 = dx*dx + dy*dy;
4644              if(d2m < d2)
4645                  d2m = d2;
4646          }
4647  
4648          if( d2m > minlen2 ) { /* line is not too small */
4649              /* XXX add more normalization here */
4650              continue;
4651          }
4652  
4653          /* if the line is too small */
4654  
4655          /* check forwards if we have a whole sequence of them */
4656          nge = ge;
4657          for(xge = ge->frwd; xge != ge; xge = xge->frwd) {
4658              d2m = 0;
4659              for(i= (xge->type==GE_CURVE? 0: 2); i<3; i++) {
4660                  dx = xge->fxn[i] - xge->prev->fx3;
4661                  dy = xge->fyn[i] - xge->prev->fy3;
4662                  d2 = dx*dx + dy*dy;
4663                  if(d2m < d2)
4664                      d2m = d2;
4665              }
4666              if( d2m > minlen2 ) /* line is not too small */
4667                  break;
4668              nge = xge;
4669              if(next == nge) /* move the next step past this sequence */
4670                  next = next->next;
4671          }
4672  
4673          /* check backwards if we have a whole sequence of them */
4674          pge = ge;
4675          for(xge = ge->bkwd; xge != ge; xge = xge->bkwd) {
4676              d2m = 0;
4677              for(i= (xge->type==GE_CURVE? 0: 2); i<3; i++) {
4678                  dx = xge->fxn[i] - xge->prev->fx3;
4679                  dy = xge->fyn[i] - xge->prev->fy3;
4680                  d2 = dx*dx + dy*dy;
4681                  if(d2m < d2)
4682                      d2m = d2;
4683              }
4684              if( d2m > minlen2 ) /* line is not too small */
4685                  break;
4686              pge = xge;
4687          }
4688  
4689          /* now we have a sequence of small fragments in pge...nge (inclusive) */
4690  
4691          if(ISDBG(FCONCISE))  {
4692              fprintf(stderr, "glyph %s has very small fragments(%x..%x..%x)\n", 
4693              g->name, pge, ge, nge);
4694              dumppaths(g, pge, nge);
4695          }
4696  
4697          /* reduce whole sequence to one part and remember the middle point */
4698          if(pge != nge) {
4699              while(1) {
4700                  xge = pge->frwd;
4701                  if(xge == nge) {
4702                      pge->fx1 = pge->fx2 = pge->fx3;
4703                      pge->fx3 = nge->fx3;
4704                      pge->fy1 = pge->fy2 = pge->fy3;
4705                      pge->fy3 = nge->fy3;
4706                      pge->type = GE_CURVE;
4707                      freethisge(nge);
4708                      break;
4709                  }
4710                  if(xge == nge->bkwd) {
4711                      pge->fx1 = pge->fx2 = (pge->fx3+xge->fx3)/2.;
4712                      pge->fx3 = nge->fx3;
4713                      pge->fy1 = pge->fy2 = (pge->fy3+xge->fy3)/2.;
4714                      pge->fy3 = nge->fy3;
4715                      pge->type = GE_CURVE;
4716                      freethisge(nge);
4717                      freethisge(xge);
4718                      break;
4719                  }
4720                  freethisge(pge); pge = xge;
4721                  xge = nge->bkwd; freethisge(nge); nge = xge;
4722              }
4723          }
4724          ge = pge;
4725  
4726          /* check if the whole sequence is small */
4727          dx = ge->fx3 - ge->prev->fx3;
4728          dy = ge->fy3 - ge->prev->fy3;
4729          d2 = dx*dx + dy*dy;
4730  
4731          if( d2 > minlen2 ) { /* no, it is not */
4732              double b, d;
4733  
4734              WARNING_3 fprintf(stderr, "glyph %s had a sequence of fragments < %g points each, reduced to one curve\n",
4735                  g->name, minlen);
4736  
4737              /* check that we did not create a monstrosity spanning quadrants */
4738              if(fsign(ge->fx1 - ge->prev->fx1) * fsign(ge->fx3 - ge->fx1) < 0
4739              || fsign(ge->fy1 - ge->prev->fy1) * fsign(ge->fy3 - ge->fy1) < 0 ) { 
4740                  /* yes, we did; are both parts of this thing big enough ? */
4741                  dx = ge->fx1 - ge->prev->fx3;
4742                  dy = ge->fy1 - ge->prev->fy3;
4743                  d2 = dx*dx + dy*dy;
4744  
4745                  dx = ge->fx3 - ge->fx1;
4746                  dy = ge->fy3 - ge->fy1;
4747                  d2m = dx*dx + dy*dy;
4748  
4749                  if(d2 > minlen2 && d2m > minlen2) { /* make two straights */
4750                      nge = newgentry(GEF_FLOAT);
4751                      *nge = *ge;
4752                      
4753                      for(i=0; i<2; i++) {
4754                          ge->fpoints[i][2] = ge->fpoints[i][0];
4755                          b = nge->fpoints[i][0];
4756                          d = nge->fpoints[i][2] - b;
4757                          nge->fpoints[i][0] = b + 0.1*d;
4758                          nge->fpoints[i][1] = b + 0.9*d;
4759                      }
4760                  }
4761                  for(i=0; i<2; i++) { /* make one straight or first of two straights */
4762                      b = ge->prev->fpoints[i][2];
4763                      d = ge->fpoints[i][2] - b;
4764                      ge->fpoints[i][0] = b + 0.1*d;
4765                      ge->fpoints[i][1] = b + 0.9*d;
4766                  }
4767              }
4768              continue; 
4769          }
4770  
4771          if(ge->frwd == ge) { /* points to itself, just remove the path completely */
4772              WARNING_3 fprintf(stderr, "glyph %s had a path made of fragments < %g points each, removed\n",
4773                  g->name, minlen);
4774  
4775              next = freethisge(ge);
4776              continue;
4777          } 
4778  
4779          /* now close the gap by x and y */
4780          for(i=0; i<2; i++) {
4781              double gap;
4782  
4783              gap = ge->fpoints[i][2] - ge->prev->fpoints[i][2];
4784              if( fclosegap(ge, ge, i, gap, NULL) != 0.0 ) {
4785                  double scale, base;
4786  
4787                  /* not good, as the last resort just scale the next line */
4788                  gap = ge->fpoints[i][2] - ge->prev->fpoints[i][2];
4789  
4790                  if(ISDBG(FCONCISE)) 
4791                      fprintf(stderr, "    last resort on %c: closing next by %g\n",
4792                      (i==0 ? 'x' : 'y'), gap);
4793  
4794                  nge = ge->frwd;
4795                  base = nge->fpoints[i][2];
4796                  dx = ge->fpoints[i][2] - base;
4797                  if(fabs(dx) < FEPS)
4798                      continue;
4799  
4800                  scale = ((dx-gap) / dx);
4801  
4802                  if(nge->type == GE_CURVE)
4803                      for(k = 0; k<2; k++)
4804                          nge->fpoints[i][k] = base + 
4805                              scale * (nge->fpoints[i][k] - base);
4806  
4807                  ge->fpoints[i][2] -= gap;
4808              }
4809          }
4810  
4811          /* OK, the gap is closed - remove this useless GENTRY */
4812          freethisge(ge);
4813      }
4814  #undef TIMESLARGER
4815  }
4816  
4817  /* find the point where two rays continuing vectors cross
4818   * returns 1 if they cross, 0 if they don't
4819   * If they cross optionally (if the pointers are not NULL) returns 
4820   * the maximal scales for both vectors and also optionally the point 
4821   * where the rays cross (twice).
4822   * Expects that the curves are normalized.
4823   *
4824   * For convenience there are 2 front-end functions taking
4825   * arguments in different formats
4826   */
4827  
4828  struct ray {
4829      double x1, y1, x2, y2;
4830      int isvert;
4831      double k, b; /* lines are represented as y = k*x + b */
4832      double *maxp;
4833  };
4834  static struct ray ray[3];
4835  
4836  /* the back-end doing the actual work
4837   * the rays are defined in the static array ray[]
4838   */
4839  
4840  static int
4841  fcrossraysxx(
4842      double crossdot[2][2]
4843  )
4844  {
4845      double x, y, max;
4846      int i;
4847  
4848      for(i=0; i<2; i++) {
4849          if(ray[i].x1 == ray[i].x2) 
4850              ray[i].isvert = 1;
4851          else {
4852              ray[i].isvert = 0;
4853              ray[i].k = (ray[i].y2 - ray[i].y1) / (ray[i].x2 - ray[i].x1);
4854              ray[i].b = ray[i].y2 - ray[i].k * ray[i].x2;
4855          }
4856      }
4857  
4858      if(ray[0].isvert && ray[1].isvert) {
4859          if(ISDBG(FCONCISE)) fprintf(stderr, "crossrays: both vertical\n");
4860          return 0; /* both vertical, don't cross */
4861      }
4862  
4863      if(ray[1].isvert) {
4864          ray[2] = ray[0]; /* exchange them */
4865          ray[0] = ray[1];
4866          ray[1] = ray[2];
4867      }
4868  
4869      if(ray[0].isvert) {
4870          x = ray[0].x1;
4871      } else {
4872          if( fabs(ray[0].k - ray[1].k) < FEPS) {
4873              if(ISDBG(FCONCISE)) fprintf(stderr, "crossrays: parallel lines, k = %g, %g\n",
4874                  ray[0].k, ray[1].k);
4875              return 0; /* parallel lines */
4876          }
4877          x = (ray[1].b - ray[0].b) / (ray[0].k - ray[1].k) ;
4878      }
4879      y = ray[1].k * x + ray[1].b;
4880  
4881      for(i=0; i<2; i++) {
4882          if(ray[i].isvert)
4883              max = (y - ray[i].y1) / (ray[i].y2 - ray[i].y1);
4884          else
4885              max = (x - ray[i].x1) / (ray[i].x2 - ray[i].x1);
4886          /* check if wrong sides of rays cross */
4887          if( max < 0 ) {
4888              if(ISDBG(FCONCISE)) fprintf(stderr, "crossrays: %c scale=%g @(%g,%g) (%g,%g)<-(%g,%g)\n",
4889                  (i?'Y':'X'), max, x, y, ray[i].x2, ray[i].y2, ray[i].x1, ray[i].y1);
4890              return 0;
4891          }
4892          if(ray[i].maxp)
4893              *ray[i].maxp = max;
4894      }
4895      if(crossdot != 0) {
4896          crossdot[0][0] = crossdot[1][0] = x;
4897          crossdot[0][1] = crossdot[1][1] = y;
4898      }
4899      return 1;
4900  }
4901  
4902  /* the front-end getting the arguments from 4 dots defining
4903   * a curve in the same format as for fapproxcurve():
4904   * rays are defined as beginning and end of the curve,
4905   * the crossdot is inserted as the two middle dots of the curve
4906   */
4907  
4908  int
4909  fcrossrayscv(
4910      double curve[4][2 /*X,Y*/],
4911      double *max1,
4912      double *max2
4913  )
4914  {
4915      ray[0].x1 = curve[0][X];
4916      ray[0].y1 = curve[0][Y];
4917      ray[0].x2 = curve[1][X];
4918      ray[0].y2 = curve[1][Y];
4919      ray[0].maxp = max1;
4920  
4921      ray[1].x1 = curve[2][X];
4922      ray[1].y1 = curve[2][Y];
4923      ray[1].x2 = curve[3][X];
4924      ray[1].y2 = curve[3][Y];
4925      ray[1].maxp = max2;
4926  
4927      return fcrossraysxx(&curve[1]);
4928  }
4929  
4930  /* the front-end getting the arguments from gentries:
4931   * rays are defined as beginning of curve1 and end of curve 2
4932   */
4933  
4934  int
4935  fcrossraysge(
4936      GENTRY *ge1,
4937      GENTRY *ge2,
4938      double *max1,
4939      double *max2,
4940      double crossdot[2][2]
4941  )
4942  {
4943      ray[0].x1 = ge1->prev->fx3;
4944      ray[0].y1 = ge1->prev->fy3;
4945      ray[0].x2 = ge1->fpoints[X][ge1->ftg];
4946      ray[0].y2 = ge1->fpoints[Y][ge1->ftg];
4947      ray[0].maxp = max1;
4948  
4949      ray[1].x1 = ge2->fx3;
4950      ray[1].y1 = ge2->fy3;
4951      if(ge2->rtg < 0) {
4952          ray[1].x2 = ge2->prev->fx3;
4953          ray[1].y2 = ge2->prev->fy3;
4954      } else {
4955          ray[1].x2 = ge2->fpoints[X][ge2->rtg];
4956          ray[1].y2 = ge2->fpoints[Y][ge2->rtg];
4957      }
4958      ray[1].maxp = max2;
4959  
4960      return fcrossraysxx(crossdot);
4961  }
4962  
4963  /* debugging printout functions */
4964  
4965  #if defined(DEBUG_DOTSEG) || defined(DEBUG_DOTCURVE) || defined(DEBUG_APPROXCV)
4966  
4967  /* for debugging */
4968  static
4969  printdot(
4970      double dot[2]
4971  )
4972  {
4973      fprintf(stderr, "(%g,%g)", dot[0], dot[1]);
4974  }
4975  
4976  static
4977  printseg(
4978      double seg[2][2]
4979  )
4980  {
4981      putc('[', stderr);
4982      printdot(seg[0]);
4983      putc(' ', stderr);
4984      printdot(seg[1]);
4985      putc(']', stderr);
4986  }
4987  
4988  #endif /* DEBUG_* */
4989  
4990  /*
4991   * Find squared distance from a dot to a line segment
4992   */
4993  
4994  double
4995  fdotsegdist2(
4996      double seg[2][2 /*X,Y*/],
4997      double dot[2 /*X,Y*/]
4998  )
4999  {
5000  #define x1    seg[0][X]
5001  #define y1    seg[0][Y]
5002  #define x2    seg[1][X]
5003  #define y2    seg[1][Y]
5004  #define xdot    dot[X]
5005  #define ydot    dot[Y]
5006  
5007      double dx, dy; /* segment dimensions */
5008      double kline, bline; /* segment line formula is y=k*x+b */
5009      double kperp, bperp; /* perpendicular from the dot to the line */
5010      double xcross, ycross; /* where the perpendicular crosses the segment */
5011  
5012  /* handle the situation where the nearest point of the segment is its end */
5013  #define HANDLE_LIMITS(less12, lesscr1, lesscr2)    \
5014      if( less12 ) { \
5015          if( lesscr1 ) { \
5016              xcross = x1; \
5017              ycross = y1; \
5018          } else if( !(lesscr2) ) { \
5019              xcross = x2; \
5020              ycross = y2; \
5021          } \
5022      } else { \
5023          if( !(lesscr1) ) { \
5024              xcross = x1; \
5025              ycross = y1; \
5026          } else if( lesscr2 ) { \
5027              xcross = x2; \
5028              ycross = y2; \
5029          } \
5030      } \
5031      /* end of macro */
5032  
5033  
5034      dx = x2 - x1;
5035      dy = y2 - y1;
5036  
5037      if(fabs(dx) < FEPS) {
5038          /* special case - vertical line */
5039  #ifdef DEBUG_DOTSEG
5040          printf("vertical line!\n");
5041  #endif
5042          xcross = x1;
5043          ycross = ydot;
5044          HANDLE_LIMITS( y1 < y2, ycross < y1, ycross < y2);
5045      } else if(fabs(dy) < FEPS) {
5046          /* special case - horizontal line */
5047  #ifdef DEBUG_DOTSEG
5048          printf("horizontal line!\n");
5049  #endif
5050          xcross = xdot;
5051          ycross = y1;
5052          HANDLE_LIMITS( x1 < x2, xcross < x1, xcross < x2)
5053      } else {
5054          kline = dy/dx;
5055          bline = y1 - x1*kline;
5056          kperp = -1./kline;
5057          bperp = ydot - xdot*kperp;
5058  
5059          xcross = (bline-bperp) / (kperp-kline);
5060          ycross = kline*xcross + bline;
5061  
5062          HANDLE_LIMITS( x1 < x2, xcross < x1, xcross < x2)
5063      }
5064  #ifdef DEBUG_DOTSEG
5065      printf("crossover at (%g,%g)\n", xcross, ycross);
5066  #endif
5067  
5068      dx = xdot-xcross;
5069      dy = ydot-ycross;
5070      return dx*dx+dy*dy;
5071  #undef x1
5072  #undef y1
5073  #undef x2
5074  #undef y2
5075  #undef xdot
5076  #undef ydot
5077  #undef HANDLE_LIMITS
5078  }
5079  
5080  /* find the weighted quadratic average for the distance of a set
5081   * of dots from the curve; also fills out the individual distances
5082   * for each dot; if maxp!=NULL then returns the maximal squared
5083   * distance in there
5084   */
5085  
5086  double
5087  fdotcurvdist2(
5088      double curve[4][2 /*X,Y*/ ],
5089      struct dot_dist *dots,
5090      int ndots, /* number of entries in dots */
5091      double *maxp
5092  )
5093  {
5094      /* a curve is approximated by this many straight segments */
5095  #define NAPSECT    16
5096      /* a curve is divided into this many sections with equal weight each */
5097  #define NWSECT    4
5098      /* table of coefficients for finding the dots on the curve */
5099      /* tt[0] is left unused */
5100      static double tt[NAPSECT][4];
5101      static int havett = 0; /* flag: tt is initialized */
5102      /* dots on the curve */
5103      double cvd[NAPSECT+1][2 /*X,Y*/];
5104      /* sums by sections */
5105      double sum[NWSECT];
5106      /* counts by sections */
5107      double count[NWSECT];
5108      int d, i, j;
5109      int id1, id2;
5110      double dist1, dist2, dist3, dx, dy, x, y;
5111      double max = 0.;
5112  
5113      if(!havett) {
5114          double t, nt, t2, nt2, step;
5115  
5116          havett++;
5117          step = 1. / NAPSECT;
5118          t = 0;
5119          for(i=1; i<NAPSECT; i++) {
5120              t += step;
5121              nt = 1 - t;
5122              t2 = t*t;
5123              nt2 = nt*nt;
5124              tt[i][0] = nt2*nt; /* (1-t)^3 */
5125              tt[i][1] = 3*nt2*t; /* 3*(1-t)^2*t */
5126              tt[i][2] = 3*nt*t2; /* 3*(1-t)*t^2 */
5127              tt[i][3] = t2*t; /* t^3 */
5128          }
5129      }
5130  
5131      for(i=0; i<NWSECT; i++) {
5132          sum[i] = 0.;
5133          count[i] = 0;
5134      }
5135  
5136      /* split the curve into segments */
5137      for(d=0; d<2; d++) { /* X and Y */
5138          cvd[0][d] = curve[0][d]; /* endpoints */
5139          cvd[NAPSECT][d] = curve[3][d];
5140          for(i=1; i<NAPSECT; i++) {
5141              cvd[i][d] = curve[0][d] * tt[i][0]
5142                  + curve[1][d] * tt[i][1]
5143                  + curve[2][d] * tt[i][2]
5144                  + curve[3][d] * tt[i][3];
5145          }
5146      }
5147  
5148      for(d=0; d<ndots; d++) {
5149  #ifdef DEBUG_DOTCURVE
5150          printf("dot %d ", d); printdot(dots[d].p); printf(":\n");
5151  
5152          /* for debugging */
5153          for(i=0; i< NAPSECT; i++) {
5154              dist1 = fdotsegdist2(&cvd[i], dots[d].p);
5155              printf("  seg %d ",i); printseg(&cvd[i]); printf(" dist=%g\n", sqrt(dist1));
5156          }
5157  #endif
5158  
5159          x = dots[d].p[X];
5160          y = dots[d].p[Y];
5161  
5162          /* find the nearest dot on the curve
5163           * there may be up to 2 local minimums - so we start from the
5164           * ends of curve and go to the center
5165           */
5166  
5167          id1 = 0;
5168          dx = x - cvd[0][X];
5169          dy = y - cvd[0][Y];
5170          dist1 = dx*dx + dy*dy;
5171  #ifdef DEBUG_DOTCURVE
5172          printf("  dot 0 "); printdot(cvd[id1]); printf(" dist=%g\n", sqrt(dist1));
5173  #endif
5174          for(i = 1; i<=NAPSECT; i++) {
5175              dx = x - cvd[i][X];
5176              dy = y - cvd[i][Y];
5177              dist3 = dx*dx + dy*dy;
5178  #ifdef DEBUG_DOTCURVE
5179              printf("  dot %d ",i); printdot(cvd[i]); printf(" dist=%g\n", sqrt(dist3));
5180  #endif
5181              if(dist3 < dist1) {
5182                  dist1 = dist3;
5183                  id1 = i;
5184              } else
5185                  break;
5186          }
5187  
5188          if(id1 < NAPSECT-1) {
5189              id2 = NAPSECT;
5190              dx = x - cvd[NAPSECT][X];
5191              dy = y - cvd[NAPSECT][Y];
5192              dist2 = dx*dx + dy*dy;
5193  #ifdef DEBUG_DOTCURVE
5194              printf("  +dot %d ", id2); printdot(cvd[id2]); printf(" dist=%g\n", sqrt(dist2));
5195  #endif
5196              for(i = NAPSECT-1; i>id1+1; i--) {
5197                  dx = x - cvd[i][X];
5198                  dy = y - cvd[i][Y];
5199                  dist3 = dx*dx + dy*dy;
5200  #ifdef DEBUG_DOTCURVE
5201                  printf("  dot %d ",i); printdot(cvd[i]); printf(" dist=%g\n", sqrt(dist3));
5202  #endif
5203                  if(dist3 < dist2) {
5204                      dist2 = dist3;
5205                      id2 = i;
5206                  } else
5207                      break;
5208              }
5209  
5210              /* now find which of the local minimums is smaller */
5211              if(dist2 < dist1) {
5212                  id1 = id2;
5213              }
5214          }
5215  
5216          /* the nearest segment must include the nearest dot */
5217          if(id1==0) {
5218              dots[d].seg = 0;
5219              dots[d].dist2 = fdotsegdist2(&cvd[0], dots[d].p);
5220          } else if(id1==NAPSECT) {
5221              dots[d].seg = NAPSECT-1;
5222              dots[d].dist2 = fdotsegdist2(&cvd[NAPSECT-1], dots[d].p);
5223          } else {
5224              dist1 = fdotsegdist2(&cvd[id1], dots[d].p);
5225              dist2 = fdotsegdist2(&cvd[id1-1], dots[d].p);
5226              if(dist2 < dist1) {
5227                  dots[d].seg = id1-1;
5228                  dots[d].dist2 = dist2;
5229              } else {
5230                  dots[d].seg = id1;
5231                  dots[d].dist2 = dist1;
5232              }
5233          }
5234  
5235          i = dots[d].seg % NWSECT;
5236          sum[i] += dots[d].dist2;
5237          if(dots[d].dist2 > max)
5238              max = dots[d].dist2;
5239          count[i]++;
5240  #ifdef DEBUG_DOTCURVE
5241          printf(" best seg %d sect %d dist=%g\n", dots[d].seg, i, sqrt(dots[d].dist2));
5242  #endif
5243      }
5244  
5245      /* calculate the weighted average */
5246      id1=0;
5247      dist1=0.;
5248      for(i=0; i<NWSECT; i++) {
5249          if(count[i]==0)
5250              continue;
5251          id1++;
5252          dist1 += sum[i]/count[i];
5253      }
5254      if(maxp)
5255          *maxp = max;
5256      if(id1==0) /* no dots, strange */
5257          return 0.;
5258      else 
5259          return dist1/id1; /* to get the average distance apply sqrt() */
5260  }
5261      
5262  /*
5263   * Approximate a curve matching the giving set of points and with
5264   * middle reference points going along the given segments (and no farther
5265   * than these segments).
5266   */
5267  
5268  void
5269  fapproxcurve(
5270      double cv[4][2 /*X,Y*/ ], /* points 0-3 are passed in, points 1,2 - out */
5271      struct dot_dist *dots, /* the dots to approximate - distances returned 
5272          * there may be invalid */
5273      int ndots
5274  )
5275  {
5276      /* b and c are the middle control points */
5277  #define    B    0
5278  #define    C    1
5279      /* maximal number of sections on each axis - used for the first step */
5280  #define MAXSECT    2
5281      /* number of sections used for the other steps */
5282  #define NORMSECT 2
5283      /* when the steps become less than this many points, it's time to stop */
5284  #define STEPEPS    1.
5285      double from[2 /*B,C*/], to[2 /*B,C*/];
5286      double middf[2 /*B,C*/][2 /*X,Y*/], df;
5287      double coef[2 /*B,C*/][MAXSECT]; 
5288      double res[MAXSECT][MAXSECT], thisres, bestres, goodres;
5289      int ncoef[2 /*B,C*/], best[2 /*B,C*/], good[2 /*B,C*/];
5290      int i, j, k, keepsym;
5291      char bc[]="BC";
5292      char xy[]="XY";
5293  
5294  #ifdef DEBUG_APPROXCV
5295      fprintf(stderr, "Curve points:");
5296      for(i=0; i<4; i++) {
5297          fprintf(stderr, " ");
5298          printdot(cv[i]); 
5299      }
5300      fprintf(stderr, "\nDots:");
5301      for(i=0; i<ndots; i++) {
5302          fprintf(stderr, " ");
5303          printdot(dots[i].p); 
5304      }
5305      fprintf(stderr, "\n");
5306  #endif
5307  
5308      /* load the endpoints and calculate differences */
5309      for(i=0; i<2; i++) {
5310          /* i is X, Y */
5311          middf[B][i] = cv[1][i]-cv[0][i];
5312          middf[C][i] = cv[2][i]-cv[3][i];
5313  
5314          /* i is B, C */
5315          from[i] = 0.;
5316          to[i] = 1.;
5317          ncoef[i] = MAXSECT;
5318      }
5319  
5320      while(ncoef[B] != 1 || ncoef[C] != 1) {
5321          /* prepare the values of coefficients */
5322          for(i=0; i<2; i++) { /*B,C*/
5323  #ifdef DEBUG_APPROXCV
5324              fprintf(stderr, "Coefficients by %c(%g,%g):", bc[i], from[i], to[i]);
5325  #endif
5326              df = (to[i]-from[i]) / (ncoef[i]*2);
5327              for(j=0; j<ncoef[i]; j++) {
5328                  coef[i][j] = from[i] + df*(2*j+1);
5329  #ifdef DEBUG_APPROXCV
5330                  fprintf(stderr, " %g", coef[i][j]);
5331  #endif
5332              }
5333  #ifdef DEBUG_APPROXCV
5334              fprintf(stderr, "\n");
5335  #endif
5336          }
5337          bestres = FBIGVAL;
5338          best[B] = best[C] = 0;
5339          /* i iterates by ncoef[B], j iterates by ncoef[C] */
5340          for(i=0; i<ncoef[B]; i++) {
5341              for(j=0; j<ncoef[C]; j++) {
5342                  for(k=0; k<2; k++) { /*X, Y*/
5343                      cv[1][k] = cv[0][k] + middf[B][k]*coef[B][i];
5344                      cv[2][k] = cv[3][k] + middf[C][k]*coef[C][j];
5345                  }
5346                  res[i][j] = thisres = fdotcurvdist2(cv, dots, ndots, NULL);
5347                  if(thisres < bestres) {
5348                      goodres = bestres;
5349                      good[B] = best[B];
5350                      good[C] = best[C];
5351                      bestres = thisres;
5352                      best[B] = i;
5353                      best[C] = j;
5354                  } else if(thisres < goodres) {
5355                      goodres = thisres;
5356                      good[B] = i;
5357                      good[C] = j;
5358                  }
5359  #ifdef DEBUG_APPROXCV
5360                  fprintf(stderr, " at (%g,%g) dist=%g %s\n", coef[B][i], coef[C][j], sqrt(thisres),
5361                      (best[B]==i && best[C]==j)? "(BEST)":"");
5362  #endif
5363              }
5364          }
5365  #ifdef DEBUG_APPROXCV
5366          fprintf(stderr, " best: at (%g, %g) dist=%g\n",
5367              coef[B][best[B]], coef[C][best[C]], sqrt(bestres));
5368          fprintf(stderr, " B:%d,%d C:%d,%d -- 2nd best: at (%g, %g) dist=%g\n",
5369              best[B], good[B], best[C], good[C], coef[B][good[B]], coef[C][good[C]], sqrt(goodres));
5370  #endif
5371  
5372          if(bestres < (0.1*0.1)) { /* consider it close enough */
5373              /* calculate the coordinates to return */
5374              for(k=0; k<2; k++) { /*X, Y*/
5375                  cv[1][k] = cv[0][k] + middf[B][k]*coef[B][best[B]];
5376                  cv[2][k] = cv[3][k] + middf[C][k]*coef[C][best[C]];
5377              }
5378  #ifdef DEBUG_APPROXCV
5379              fprintf(stderr, "quick approximated middle points "); printdot(cv[1]); 
5380              fprintf(stderr, " "); printdot(cv[2]); fprintf(stderr, "\n");
5381  #endif
5382              return;
5383          }
5384          keepsym = 0;
5385          if(best[B] != best[C] && best[B]-best[C] == good[C]-good[B]) {
5386              keepsym = 1;
5387  #ifdef DEBUG_APPROXCV
5388              fprintf(stderr, "keeping symmetry!\n");
5389  #endif
5390          }
5391          for(i=0; i<2; i++) { /*B,C*/
5392              if(ncoef[i]==1)
5393                  continue;
5394              if(keepsym) {
5395                  /* try to keep the symmetry */
5396                  if(best[i] < good[i]) {
5397                      from[i] = coef[i][best[i]];
5398                      to[i] = coef[i][good[i]];
5399                  } else {
5400                      from[i] = coef[i][good[i]];
5401                      to[i] = coef[i][best[i]];
5402                  }
5403              } else {
5404                  df = (to[i]-from[i]) / ncoef[i];
5405                  from[i] += df*best[i];
5406                  to[i] = from[i] + df;
5407              }
5408              if( fabs(df*middf[i][0]) < STEPEPS && fabs(df*middf[i][1]) < STEPEPS) {
5409                  /* this side has converged */
5410                  from[i] = to[i] = (from[i]+to[i]) / 2.;
5411                  ncoef[i] = 1;
5412              } else 
5413                  ncoef[i] = NORMSECT;
5414          }
5415  
5416      }
5417      /* calculate the coordinates to return */
5418      for(k=0; k<2; k++) { /*X, Y*/
5419          cv[1][k] = cv[0][k] + middf[B][k]*from[B];
5420          cv[2][k] = cv[3][k] + middf[C][k]*from[C];
5421      }
5422  #ifdef DEBUG_APPROXCV
5423      fprintf(stderr, "approximated middle points "); printdot(cv[1]); 
5424      fprintf(stderr, " "); printdot(cv[2]); fprintf(stderr, "\n");
5425  #endif
5426  #undef B
5427  #undef C
5428  #undef MAXSECT
5429  #undef NORMSECT
5430  #undef STEPEPS
5431  }
5432  
5433  /*
5434   * Find the squared value of the sinus of the angle between the
5435   * end of ge1 and the beginning of ge2
5436   * The curve must be normalized.
5437   */
5438  
5439  static double
5440  fjointsin2(
5441      GENTRY *ge1,
5442      GENTRY *ge2
5443  )
5444  {
5445      double d[3][2 /*X,Y*/];
5446      double scale1, scale2, len1, len2;
5447      int axis;
5448      
5449      if(ge1->rtg < 0) {
5450          d[1][X] = ge1->fx3 - ge1->prev->fx3;
5451          d[1][Y] = ge1->fy3 - ge1->prev->fy3;
5452      } else {
5453          d[1][X] = ge1->fx3 - ge1->fpoints[X][ge1->rtg];
5454          d[1][Y] = ge1->fy3 - ge1->fpoints[Y][ge1->rtg];
5455      }
5456      d[2][X] = ge2->fpoints[X][ge2->ftg] - ge2->prev->fx3;
5457      d[2][Y] = ge2->fpoints[Y][ge2->ftg] - ge2->prev->fy3;
5458  
5459      len1 = sqrt( d[1][X]*d[1][X] + d[1][Y]*d[1][Y] );
5460      len2 = sqrt( d[2][X]*d[2][X] + d[2][Y]*d[2][Y] );
5461      /* scale the 2nd segment to the length of 1
5462       * and to make sure that the 1st segment is longer scale it to
5463       * the length of 2 and extend to the same distance backwards
5464       */
5465      scale1 = 2./len1;
5466      scale2 = 1./len2;
5467  
5468      for(axis=0; axis <2; axis++) {
5469          d[0][axis] = -( d[1][axis] *= scale1 );
5470          d[2][axis] *= scale2;
5471      }
5472      return fdotsegdist2(d, d[2]);
5473  }
5474  
5475  #if 0
5476  /* find the area covered by the curve
5477   * (limited by the projections to the X axis)
5478   */
5479  
5480  static double
5481  fcvarea(
5482      GENTRY *ge
5483  )
5484  {
5485      double Ly, My, Ny, Py, Qx, Rx, Sx;
5486      double area;
5487  
5488      /* y = Ly*t^3 + My*t^2 + Ny*t + Py */
5489      Ly = -ge->prev->fy3 + 3*(ge->fy1 - ge->fy2) + ge->fy3;
5490      My = 3*ge->prev->fy3 - 6*ge->fy1 + 3*ge->fy2;
5491      Ny = 3*(-ge->prev->fy3 + ge->fy1);
5492      Py = ge->prev->fy3;
5493  
5494      /* dx/dt = Qx*t^2 + Rx*t + Sx */
5495      Qx = 3*(-ge->prev->fx3 + 3*(ge->fx1 - ge->fx2) + ge->fx3);
5496      Rx = 6*(ge->prev->fx3 - 2*ge->fx1 + ge->fx2);
5497      Sx = 3*(-ge->prev->fx3 + ge->fx1);
5498  
5499      /* area is integral[from 0 to 1]( y(t) * dx(t)/dt *dt) */
5500      area = 1./6.*(Ly*Qx) + 1./5.*(Ly*Rx + My*Qx) 
5501          + 1./4.*(Ly*Sx + My*Rx + Ny*Qx) + 1./3.*(My*Sx + Ny*Rx + Py*Qx)
5502          + 1./2.*(Ny*Sx + Py*Rx) + Py*Sx;
5503  
5504      return area;
5505  }
5506  #endif
5507  
5508  /* find the value of point on the curve at the given parameter t,
5509   * along the given axis (0 - X, 1 - Y).
5510   */
5511  
5512  static double
5513  fcvval(
5514      GENTRY *ge,
5515      int axis,
5516      double t
5517  )
5518  {
5519      double t2, mt, mt2;
5520  
5521      /* val = A*(1-t)^3 + 3*B*(1-t)^2*t + 3*C*(1-t)*t^2 + D*t^3 */
5522      t2 = t*t;
5523      mt = 1-t;
5524      mt2 = mt*mt;
5525      
5526      return ge->prev->fpoints[axis][2]*mt2*mt 
5527          + 3*(ge->fpoints[axis][0]*mt2*t + ge->fpoints[axis][1]*mt*t2)
5528          + ge->fpoints[axis][2]*t*t2;
5529  }
5530  
5531  /*
5532   * Find ndots equally spaced dots on a curve or line and fill 
5533   * their coordinates into the dots array
5534   */
5535  
5536  static void
5537  fsampledots(
5538      GENTRY *ge, 
5539      double dots[][2], /* the dots to fill */
5540      int ndots
5541  )
5542  {
5543      int i, axis;
5544      double t, nf, dx, d[2];
5545  
5546      nf = ndots+1;
5547      if(ge->type == GE_CURVE) {
5548          for(i=0; i<ndots; i++) {
5549              t = (i+1)/nf;
5550              for(axis=0; axis<2; axis++)
5551                  dots[i][axis] = fcvval(ge, axis, t);
5552          }
5553      } else { /* line */
5554          d[0] = ge->fx3 - ge->prev->fx3;
5555          d[1] = ge->fy3 - ge->prev->fy3;
5556          for(i=0; i<ndots; i++) {
5557              t = (i+1)/nf;
5558              for(axis=0; axis<2; axis++)
5559                  dots[i][axis] = ge->prev->fpoints[axis][2] 
5560                      + t*d[axis];
5561          }
5562      }
5563  }
5564  
5565  /*
5566   * Allocate a structure gex_con
5567   */
5568  
5569  static void
5570  alloc_gex_con(
5571      GENTRY *ge
5572  )
5573  {
5574      ge->ext = (void*)calloc(1, sizeof(GEX_CON));
5575      if(ge->ext == 0) {
5576          fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
5577          exit(255);
5578      }
5579  }
5580  
5581  /*
5582   * Normalize a gentry for fforceconcise() : find the points that
5583   * can be used to calculate the tangents.
5584   */
5585  
5586  static void
5587  fnormalizege(
5588      GENTRY *ge
5589  )
5590  {
5591      int midsame, frontsame, rearsame;
5592  
5593      if(ge->type == GE_LINE) {
5594          ge->ftg = 2;
5595          ge->rtg = -1;
5596      } else { /* assume it's a curve */
5597          midsame = (fabs(ge->fx1-ge->fx2)<FEPS && fabs(ge->fy1-ge->fy2)<FEPS);
5598          frontsame = (fabs(ge->fx1-ge->prev->fx3)<FEPS && fabs(ge->fy1-ge->prev->fy3)<FEPS);
5599          rearsame = (fabs(ge->fx3-ge->fx2)<FEPS && fabs(ge->fy3-ge->fy2)<FEPS);
5600  
5601          if(midsame && (frontsame || rearsame) ) {
5602              /* essentially a line */
5603              ge->ftg = 2;
5604              ge->rtg = -1;
5605          } else { 
5606              if(frontsame) {
5607                  ge->ftg = 1;
5608              } else {
5609                  ge->ftg = 0;
5610              }
5611              if(rearsame) {
5612                  ge->rtg = 0;
5613              } else {
5614                  ge->rtg = 1;
5615              }
5616          }
5617      }
5618  }
5619  
5620  /* various definition for the processing of outlines */
5621  
5622  /* maximal average quadratic distance from the original curve
5623   * (in dots) to consider the joined curve good
5624   */
5625  #define CVEPS    1.5
5626  #define CVEPS2    (CVEPS*CVEPS)
5627  /* squared sinus of the maximal angle that we consider a smooth joint */
5628  #define SMOOTHSIN2 0.25 /* 0.25==sin(30 degrees)^2 */
5629  /* squared line length that we consider small */
5630  #define SMALL_LINE2 (15.*15.)
5631  /* how many times a curve must be bigger than a line to join, squared */
5632  #define TIMES_LINE2 (3.*3.)
5633  
5634  /*
5635   * Normalize and analyse a gentry for fforceconcise() and fill out the gex_con
5636   * structure
5637   */
5638  
5639  static void
5640  fanalyzege(
5641      GENTRY *ge
5642  )
5643  {
5644      int i, ix, iy;
5645      double avsd2, dots[3][2 /*X,Y*/];
5646      GEX_CON *gex;
5647  
5648      gex = X_CON(ge);
5649      memset(gex, 0, sizeof *gex);
5650  
5651      gex->len2 = 0;
5652      for(i=0; i<2; i++) {
5653          avsd2 = gex->d[i] = ge->fpoints[i][2] - ge->prev->fpoints[i][2];
5654          gex->len2 += avsd2*avsd2;
5655      }
5656      gex->sin2 = fjointsin2(ge, ge->frwd);
5657      if(ge->type == GE_CURVE) {
5658          ge->dir = fgetcvdir(ge);
5659          for(i=0; i<2; i++) {
5660              dots[0][i] = ge->prev->fpoints[i][2];
5661              dots[1][i] = ge->fpoints[i][2];
5662              dots[2][i] = fcvval(ge, i, 0.5);
5663          }
5664          avsd2 = fdotsegdist2(dots, dots[2]);
5665          if(avsd2 <= CVEPS2) {
5666              gex->flags |= GEXF_FLAT;
5667          }
5668      } else {
5669          ge->dir = CVDIR_FEQUAL|CVDIR_REQUAL;
5670          gex->flags |= GEXF_FLAT;
5671      }
5672      if(gex->flags & GEXF_FLAT) {
5673          if( fabs(gex->d[X]) > FEPS && fabs(gex->d[Y]) < 5.
5674          && fabs(gex->d[Y] / gex->d[X]) < 0.2)
5675              gex->flags |= GEXF_HOR;
5676          else if( fabs(gex->d[Y]) > FEPS && fabs(gex->d[X]) < 5.
5677          && fabs(gex->d[X] / gex->d[Y]) < 0.2)
5678              gex->flags |= GEXF_VERT;
5679      }
5680      ix = gex->isd[X] = fsign(gex->d[X]);
5681      iy = gex->isd[Y] = fsign(gex->d[Y]);
5682      if(ix <= 0) {
5683          if(iy <= 0) 
5684              gex->flags |= GEXF_QDL;
5685          if(iy >= 0) 
5686              gex->flags |= GEXF_QUL;
5687          if(gex->flags & GEXF_HOR)
5688              gex->flags |= GEXF_IDQ_L;
5689      }
5690      if(ix >= 0) {
5691          if(iy <= 0) 
5692              gex->flags |= GEXF_QDR;
5693          if(iy >= 0) 
5694              gex->flags |= GEXF_QUR;
5695          if(gex->flags & GEXF_HOR)
5696              gex->flags |= GEXF_IDQ_R;
5697      }
5698      if(gex->flags & GEXF_VERT) {
5699          if(iy <= 0) {
5700              gex->flags |= GEXF_IDQ_U;
5701          } else { /* supposedly there is no 0-sized entry */
5702              gex->flags |= GEXF_IDQ_D;
5703          }
5704      }
5705  }
5706  
5707  /*
5708   * Analyse a joint between this and following gentry for fforceconcise() 
5709   * and fill out the corresponding parts of the gex_con structure
5710   * Bothe entries must be analyzed first.
5711   */
5712  
5713  static void
5714  fanalyzejoint(
5715      GENTRY *ge
5716  )
5717  {
5718      GENTRY *nge = ge->frwd;
5719      GENTRY tge;
5720      GEX_CON *gex, *ngex;
5721      double avsd2, dots[3][2 /*X,Y*/];
5722      int i;
5723  
5724      gex = X_CON(ge); ngex = X_CON(nge);
5725  
5726      /* look if they can be joined honestly */
5727  
5728      /* if any is flat, they should join smoothly */
5729      if( (gex->flags & GEXF_FLAT || ngex->flags & GEXF_FLAT)
5730      && gex->sin2 > SMOOTHSIN2)
5731          goto try_flatboth;
5732  
5733      if(ge->type == GE_LINE) {
5734          if(nge->type == GE_LINE) {
5735              if(gex->len2 > SMALL_LINE2 || ngex->len2 > SMALL_LINE2)
5736                  goto try_flatboth;
5737          } else {
5738              if(gex->len2*TIMES_LINE2 > ngex->len2)
5739                  goto try_flatboth;
5740          }
5741      } else if(nge->type == GE_LINE) {
5742          if(ngex->len2*TIMES_LINE2 > gex->len2)
5743              goto try_flatboth;
5744      }
5745  
5746      /* if curve changes direction */
5747      if( gex->isd[X]*ngex->isd[X]<0 || gex->isd[Y]*ngex->isd[Y]<0)
5748          goto try_idealone;
5749  
5750      /* if would create a zigzag */
5751      if( ((ge->dir&CVDIR_FRONT)-CVDIR_FEQUAL) * ((nge->dir&CVDIR_REAR)-CVDIR_REQUAL) < 0 )
5752          goto try_flatone;
5753  
5754      if( fcrossraysge(ge, nge, NULL, NULL, NULL) )
5755          gex->flags |= GEXF_JGOOD;
5756  
5757  try_flatone:
5758      /* look if they can be joined by flatting out one of the entries */
5759  
5760      /* at this point we know that the general direction of the
5761       * gentries is OK
5762       */
5763  
5764      if( gex->flags & GEXF_FLAT ) {
5765          tge = *ge;
5766          tge.fx1 = tge.fx3;
5767          tge.fy1 = tge.fy3;
5768          fnormalizege(&tge);
5769          if( fcrossraysge(&tge, nge, NULL, NULL, NULL) )
5770              gex->flags |= GEXF_JFLAT|GEXF_JFLAT1;
5771      }
5772      if( ngex->flags & GEXF_FLAT ) {
5773          tge = *nge;
5774          tge.fx2 = ge->fx3;
5775          tge.fy2 = ge->fy3;
5776          fnormalizege(&tge);
5777          if( fcrossraysge(ge, &tge, NULL, NULL, NULL) )
5778              gex->flags |= GEXF_JFLAT|GEXF_JFLAT2;
5779      }
5780  
5781  try_idealone:
5782      /* look if one of the entries can be brought to an idealized
5783       * horizontal or vertical position and then joined
5784       */
5785      if( gex->flags & GEXF_HOR && gex->isd[X]*ngex->isd[X]>=0 ) {
5786          tge = *ge;
5787          tge.fx1 = tge.fx3;
5788          tge.fy1 = ge->prev->fy3; /* force horizontal */
5789          fnormalizege(&tge);
5790          if( fcrossraysge(&tge, nge, NULL, NULL, NULL) )
5791              gex->flags |= GEXF_JID|GEXF_JID1;
5792      } else if( gex->flags & GEXF_VERT && gex->isd[Y]*ngex->isd[Y]>=0 ) {
5793          tge = *ge;
5794          tge.fx1 = ge->prev->fx3; /* force vertical */
5795          tge.fy1 = tge.fy3;
5796          fnormalizege(&tge);
5797          if( fcrossraysge(&tge, nge, NULL, NULL, NULL) )
5798              gex->flags |= GEXF_JID|GEXF_JID1;
5799      }
5800      if( ngex->flags & GEXF_HOR && gex->isd[X]*ngex->isd[X]>=0 ) {
5801          tge = *nge;
5802          tge.fx2 = ge->fx3;
5803          tge.fy2 = nge->fy3; /* force horizontal */
5804          fnormalizege(&tge);
5805          if( fcrossraysge(ge, &tge, NULL, NULL, NULL) )
5806              gex->flags |= GEXF_JID|GEXF_JID2;
5807      } else if( ngex->flags & GEXF_VERT && gex->isd[Y]*ngex->isd[Y]>=0 ) {
5808          tge = *nge;
5809          tge.fx2 = nge->fx3; /* force vertical */
5810          tge.fy2 = ge->fy3;
5811          fnormalizege(&tge);
5812          if( fcrossraysge(ge, &tge, NULL, NULL, NULL) )
5813              gex->flags |= GEXF_JID|GEXF_JID2;
5814      }
5815  
5816  try_flatboth:
5817      /* look if we can change them to one line */
5818      if(gex->flags & GEXF_FLAT && ngex->flags & GEXF_FLAT) {
5819          for(i=0; i<2; i++) {
5820              dots[0][i] = ge->prev->fpoints[i][2];
5821              dots[1][i] = nge->fpoints[i][2];
5822              dots[2][i] = ge->fpoints[i][2];
5823          }
5824          if( fdotsegdist2(dots, dots[2]) <= CVEPS2)
5825              gex->flags |= GEXF_JLINE;
5826      }
5827  }
5828  
5829  /*
5830   * Force conciseness of one contour in the glyph,
5831   * the contour is indicated by one entry from it.
5832   */
5833  
5834  static void
5835  fconcisecontour(
5836      GLYPH *g,
5837      GENTRY *startge
5838  )
5839  {
5840  /* initial maximal number of dots to be used as reference */
5841  #define MAXDOTS    ((NREFDOTS+1)*12)
5842  
5843      GENTRY *ge, *pge, *nge, *ige;
5844      GEX_CON *gex, *pgex, *ngex, *nngex;
5845      GENTRY tpge, tnge;
5846      int quad, qq, i, j, ndots, maxdots;
5847      int found[2];
5848      int joinmask, pflag, nflag;
5849      struct dot_dist *dots;
5850      double avsd2, maxd2, eps2;
5851      double apcv[4][2];
5852  
5853      if(startge == 0) {
5854          fprintf(stderr, "WARNING: assertion in %s line %d, please report it to the ttf2pt1 project\n",
5855              __FILE__, __LINE__);
5856          fprintf(stderr, "Strange contour in glyph %s\n", g->name);
5857          dumppaths(g, NULL, NULL);
5858          return;
5859      }
5860  
5861      if(startge->type != GE_CURVE && startge->type != GE_LINE)
5862          return; /* probably a degenerate contour */
5863  
5864      if(ISDBG(FCONCISE))
5865          fprintf(stderr, "processing contour 0x%p of glyph %s\n", startge, g->name);
5866  
5867      maxdots = MAXDOTS;
5868      dots = (struct dot_dist *)malloc(sizeof(*dots)*maxdots);
5869      if(dots == NULL) {
5870          fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
5871          exit(255);
5872      }
5873  
5874      ge = startge;
5875      joinmask = GEXF_JGOOD;
5876      while(1) {
5877      restart:
5878          gex = X_CON(ge);
5879          if((gex->flags & GEXF_JMASK) > ((joinmask<<1)-1)) {
5880              if(ISDBG(FCONCISE))
5881                  fprintf(stderr, "found higher flag (%x>%x) at 0x%p\n", 
5882                      gex->flags & GEXF_JMASK, ((joinmask<<1)-1), ge);
5883              joinmask <<= 1;
5884              startge = ge; /* have to redo the pass */
5885              continue;
5886          }
5887          if(( gex->flags & joinmask )==0)
5888              goto next;
5889  
5890          /* if we happen to be in the middle of a string of
5891           * joinable entries, find its beginning
5892           */
5893          if( gex->flags & (GEXF_JCVMASK^GEXF_JID) )
5894              quad = gex->flags & X_CON_F(ge->frwd) & GEXF_QMASK;
5895          else if( gex->flags & GEXF_JID2 )
5896              quad = gex->flags & GEXF_QFROM_IDEAL(X_CON_F(ge->frwd)) & GEXF_QMASK;
5897          else /* must be GEXF_JID1 */
5898              quad = GEXF_QFROM_IDEAL(gex->flags) & X_CON_F(ge->frwd) & GEXF_QMASK;
5899  
5900          pge = ge;
5901          pgex = X_CON(pge->bkwd);
5902  
5903          if(ISDBG(FCONCISE))
5904              fprintf(stderr, "ge %p prev -> 0x%p ", ge, pge);
5905  
5906          while(pgex->flags & GEXF_JCVMASK) {
5907              if( !(pgex->flags & ((GEXF_JCVMASK^GEXF_JID)|GEXF_JID2)) )
5908                  qq = GEXF_QFROM_IDEAL(pgex->flags);
5909              else 
5910                  qq = pgex->flags & GEXF_QMASK;
5911  
5912              if(ISDBG(FCONCISE))
5913                  fprintf(stderr, "(%x?%x)", quad, qq);
5914  
5915              if( !(quad & qq) ) {
5916                  if( !(X_CON_F(pge) & (GEXF_JCVMASK^GEXF_JID))
5917                  && pgex->flags & (GEXF_JCVMASK^GEXF_JID) ) {
5918                      /* the previos entry is definitely a better match */
5919                      if(pge == ge) {
5920                          if(ISDBG(FCONCISE))
5921                              fprintf(stderr, "\nprev is a better match at %p\n", pge);
5922                          startge = ge;
5923                          goto next;
5924                      } else
5925                          pge = pge->frwd;
5926                  }
5927                  break;
5928              }
5929  
5930              quad &= qq;
5931              pge = pge->bkwd;
5932              pgex = X_CON(pge->bkwd);
5933              if(ISDBG(FCONCISE))
5934                  fprintf(stderr, "0x%p ", pge);
5935          }
5936  
5937          /* collect as many entries for joining as possible */
5938          nge = ge->frwd;
5939          ngex = X_CON(nge); 
5940          nngex = X_CON(nge->frwd); 
5941  
5942          if(ISDBG(FCONCISE))
5943              fprintf(stderr, ": 0x%x\nnext -> 0x%p ", pge, nge);
5944  
5945          while(ngex->flags & GEXF_JCVMASK) {
5946              if( !(ngex->flags & ((GEXF_JCVMASK^GEXF_JID)|GEXF_JID1)) )
5947                  qq = GEXF_QFROM_IDEAL(nngex->flags);
5948              else 
5949                  qq = nngex->flags & GEXF_QMASK;
5950  
5951              if(ISDBG(FCONCISE))
5952                  fprintf(stderr, "(%x?%x)", quad, qq);
5953              if( !(quad & qq) ) {
5954                  if( !(X_CON_F(nge->bkwd) & (GEXF_JCVMASK^GEXF_JID))
5955                  && ngex->flags & (GEXF_JCVMASK^GEXF_JID) ) {
5956                      /* the next-next entry is definitely a better match */
5957                      if(nge == ge->frwd) {
5958                          if(ISDBG(FCONCISE))
5959                              fprintf(stderr, "\nnext %x is a better match than %x at %p (jmask %x)\n", 
5960                                  ngex->flags & GEXF_JCVMASK, gex->flags & GEXF_JCVMASK, nge, joinmask);
5961                          goto next;
5962                      } else
5963                          nge = nge->bkwd;
5964                  }
5965                  break;
5966              }
5967  
5968              quad &= qq;
5969              nge = nge->frwd;
5970              ngex = nngex; 
5971              nngex = X_CON(nge->frwd);
5972              if(ISDBG(FCONCISE))
5973                  fprintf(stderr, "0x%p ", nge);
5974          }
5975  
5976          if(ISDBG(FCONCISE))
5977              fprintf(stderr, ": 0x%x\n", nge);
5978  
5979          /* XXX add splitting of last entries if neccessary */
5980  
5981          /* make sure that all the reference dots are valid */
5982          for(ige = pge; ige != nge->frwd; ige = ige->frwd) {
5983              nngex = X_CON(ige);
5984              if( !(nngex->flags & GEXF_VDOTS) ) {
5985                  fsampledots(ige, nngex->dots, NREFDOTS);
5986                  nngex->flags |= GEXF_VDOTS;
5987              }
5988          }
5989  
5990          /* do the actual joining */
5991          while(1) {
5992              pgex = X_CON(pge);
5993              ngex = X_CON(nge->bkwd);
5994              /* now the segments to be joined are pge...nge */
5995  
5996              ndots = 0;
5997              for(ige = pge; ige != nge->frwd; ige = ige->frwd) {
5998                  if(maxdots < ndots+(NREFDOTS+1)) {
5999                      maxdots += MAXDOTS;
6000                      dots = (struct dot_dist *)realloc((void *)dots, sizeof(*dots)*maxdots);
6001                      if(dots == NULL) {
6002                          fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
6003                          exit(255);
6004                      }
6005                  }
6006                  nngex = X_CON(ige);
6007                  for(i=0; i<NREFDOTS; i++) {
6008                      for(j=0; j<2; j++)
6009                          dots[ndots].p[j] = nngex->dots[i][j];
6010                      ndots++;
6011                  }
6012                  for(j=0; j<2; j++)
6013                      dots[ndots].p[j] = ige->fpoints[j][2];
6014                  ndots++;
6015              }
6016              ndots--; /* the last point is not interesting */
6017  
6018              tpge = *pge;
6019              pflag = pgex->flags;
6020              if(pflag & (GEXF_JGOOD|GEXF_JFLAT2|GEXF_JID2)) {
6021                  /* nothing */
6022              } else if(pflag & GEXF_JFLAT) {
6023                  tpge.fx1 = tpge.fx3;
6024                  tpge.fy1 = tpge.fy3;
6025              } else if(pflag & GEXF_JID) {
6026                  if(pflag & GEXF_HOR)
6027                      tpge.fy1 = tpge.bkwd->fy3;
6028                  else
6029                      tpge.fx1 = tpge.bkwd->fx3;
6030              }
6031  
6032              tnge = *nge;
6033              nflag = ngex->flags;
6034              if(nflag & (GEXF_JGOOD|GEXF_JFLAT1|GEXF_JID)
6035              && !(nflag & GEXF_JID2)) {
6036                  /* nothing */
6037              } else if(nflag & GEXF_JFLAT) {
6038                  tnge.fx2 = tnge.bkwd->fx3;
6039                  tnge.fy2 = tnge.bkwd->fy3;
6040              } else if(nflag & GEXF_JID) {
6041                  if(X_CON_F(nge) & GEXF_HOR)
6042                      tnge.fy2 = tnge.fy3;
6043                  else
6044                      tnge.fx2 = tnge.fx3;
6045              }
6046  
6047              fnormalizege(&tpge);
6048              fnormalizege(&tnge);
6049              if( fcrossraysge(&tpge, &tnge, NULL, NULL, &apcv[1]) ) {
6050                  apcv[0][X] = tpge.bkwd->fx3;
6051                  apcv[0][Y] = tpge.bkwd->fy3;
6052                  /* apcv[1] and apcv[2] were filled by fcrossraysge() */
6053                  apcv[3][X] = tnge.fx3;
6054                  apcv[3][Y] = tnge.fy3;
6055  
6056                  /* calculate the precision depending on the smaller dimension of the curve */
6057                  maxd2 = apcv[3][X]-apcv[0][X];
6058                  maxd2 *= maxd2;
6059                  eps2 = apcv[3][Y]-apcv[0][Y];
6060                  eps2 *= eps2;
6061                  if(maxd2 < eps2)
6062                      eps2 = maxd2;
6063                  eps2 *= (CVEPS2*4.) / (400.*400.);
6064                  if(eps2 < CVEPS2)
6065                      eps2 = CVEPS2;
6066                  else if(eps2 > CVEPS2*4.)
6067                      eps2 = CVEPS2*4.;
6068  
6069                  fapproxcurve(apcv, dots, ndots);
6070  
6071                  avsd2 = fdotcurvdist2(apcv, dots, ndots, &maxd2); 
6072                  if(ISDBG(FCONCISE))
6073                      fprintf(stderr, "avsd = %g, maxd = %g, ", sqrt(avsd2), sqrt(maxd2));
6074                  if(avsd2 <= eps2 && maxd2 <= eps2*2.) {
6075                      /* we've guessed a curve that is close enough */
6076                      ggoodcv++; ggoodcvdots += ndots;
6077  
6078                      if(ISDBG(FCONCISE)) {
6079                          fprintf(stderr, "in %s joined %p-%p to ", g->name, pge, nge);
6080                          for(i=0; i<4; i++) {
6081                              fprintf(stderr, " (%g, %g)", apcv[i][X], apcv[i][Y]);
6082                          }
6083                          fprintf(stderr, " from\n");
6084                          dumppaths(g, pge, nge);
6085                      }
6086                      for(i=0; i<3; i++) {
6087                          pge->fxn[i] = apcv[i+1][X];
6088                          pge->fyn[i] = apcv[i+1][Y];
6089                      }
6090                      pge->type = GE_CURVE;
6091                      ge = pge;
6092                      for(ige = pge->frwd; ; ige = pge->frwd) {
6093                          if(ige == pge) {
6094                              fprintf(stderr, "WARNING: assertion in %s line %d, please report it to the ttf2pt1 project\n",
6095                                  __FILE__, __LINE__);
6096                              free(dots);
6097                              return;
6098                          }
6099                          if(startge == ige)
6100                              startge = pge;
6101                          free(ige->ext);
6102                          freethisge(ige);
6103                          if(ige == nge)
6104                              break;
6105                      }
6106                      fnormalizege(ge);
6107                      if(ISDBG(FCONCISE)) {
6108                          fprintf(stderr, "normalized ");
6109                          for(i=0; i<3; i++) {
6110                              fprintf(stderr, " (%g, %g)", ge->fpoints[X][i], ge->fpoints[Y][i]);
6111                          }
6112                          fprintf(stderr, "\n");
6113                      }
6114                      fanalyzege(ge);
6115                      fanalyzejoint(ge);
6116                      fanalyzege(ge->bkwd);
6117                      fanalyzejoint(ge->bkwd);
6118  
6119                      /* the results of this join will have to be reconsidered */
6120                      startge = ge = ge->frwd;
6121                      goto restart;
6122                  } else {
6123                      gbadcv++; gbadcvdots += ndots;
6124                  }
6125              }
6126  
6127              /* if we're down to 2 entries then the join has failed */
6128              if(pge->frwd == nge) {
6129                  pgex->flags &= ~joinmask;
6130                  if(ISDBG(FCONCISE))
6131                      fprintf(stderr, "no match\n");
6132                  goto next;
6133              }
6134  
6135              /* reduce the number of entries by dropping one at some end,
6136               * should never drop the original ge from the range
6137               */
6138  
6139              if(nge->bkwd == ge 
6140              || pge != ge && (pgex->flags & GEXF_JCVMASK) <= (ngex->flags & GEXF_JCVMASK) ) {
6141                  pge = pge->frwd;
6142              } else {
6143                  nge = nge->bkwd;
6144              }
6145              if(ISDBG(FCONCISE))
6146                  fprintf(stderr, "next try: %p to %p\n", pge, nge);
6147          }
6148  
6149  next:
6150          ge = ge->frwd;
6151          if(ge == startge) {
6152              joinmask = (joinmask >> 1) & GEXF_JCVMASK;
6153              if(joinmask == 0)
6154                  break;
6155          }
6156      }
6157  
6158      /* join flat segments into lines */
6159      /* here ge==startge */
6160      while(1) {
6161          gex = X_CON(ge);
6162          if( !(gex->flags & GEXF_JLINE) )
6163              goto next2;
6164  
6165          ndots = 0;
6166          dots[ndots].p[X] = ge->fx3;
6167          dots[ndots].p[Y] = ge->fy3;
6168          ndots++;
6169  
6170          pge = ge->bkwd;
6171          nge = ge->frwd;
6172  
6173          if(ISDBG(FCONCISE))
6174              fprintf(stderr, "joining LINE from %p-%p\n", ge, nge);
6175  
6176          while(pge!=nge) {
6177              pgex = X_CON(pge);
6178              ngex = X_CON(nge); 
6179              if(ISDBG(FCONCISE))
6180                  fprintf(stderr, "(p=%p/%x n=0x%x/%x) ", pge, pgex->flags & GEXF_JLINE, 
6181                      nge, ngex->flags & GEXF_JLINE);
6182              if( !((pgex->flags | ngex->flags) & GEXF_JLINE) ) {
6183                  if(ISDBG(FCONCISE))
6184                      fprintf(stderr, "(end p=%p n=%p) ", pge, nge);
6185                  break;
6186              }
6187  
6188              if(maxdots < ndots+2) {
6189                  maxdots += MAXDOTS;
6190                  dots = (struct dot_dist *)realloc((void *)dots, sizeof(*dots)*maxdots);
6191                  if(dots == NULL) {
6192                      fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
6193                      exit(255);
6194                  }
6195              }
6196              if( pgex->flags & GEXF_JLINE ) {
6197                  for(i=0; i<2; i++) {
6198                      apcv[0][i] = pge->bkwd->fpoints[i][2];
6199                      apcv[1][i] = nge->fpoints[i][2];
6200                      dots[ndots].p[i] = pge->fpoints[i][2];
6201                  }
6202                  ndots++;
6203                  for(i=0; i<ndots; i++) {
6204                      avsd2 = fdotsegdist2(apcv, dots[i].p);
6205                      if(avsd2 > CVEPS2)
6206                          break;
6207                  }
6208                  if(i<ndots) { /* failed to join */
6209                      if(ISDBG(FCONCISE))
6210                          fprintf(stderr, "failed to join prev %p ", pge);
6211                      ndots--;
6212                      pgex->flags &= ~GEXF_JLINE;
6213                  } else {
6214                      pge = pge->bkwd;
6215                      if(pge == nge) {
6216                          if(ISDBG(FCONCISE))
6217                              fprintf(stderr, "intersected at prev %p ", pge);
6218                          break; /* oops, tried to self-intersect */
6219                      }
6220                  }
6221              } else if(ISDBG(FCONCISE))
6222                  fprintf(stderr, "(p=%p) ", pge);
6223  
6224              if( ngex->flags & GEXF_JLINE ) {
6225                  for(i=0; i<2; i++) {
6226                      apcv[0][i] = pge->fpoints[i][2]; /* pge points before the 1st segment */
6227                      apcv[1][i] = nge->frwd->fpoints[i][2];
6228                      dots[ndots].p[i] = nge->fpoints[i][2];
6229                  }
6230                  ndots++;
6231                  for(i=0; i<ndots; i++) {
6232                      avsd2 = fdotsegdist2(apcv, dots[i].p);
6233                      if(avsd2 > CVEPS2)
6234                          break;
6235                  }
6236                  if(i<ndots) { /* failed to join */
6237                      if(ISDBG(FCONCISE))
6238                          fprintf(stderr, "failed to join next %p ", nge->frwd);
6239                      ndots--;
6240                      ngex->flags &= ~GEXF_JLINE;
6241                  } else {
6242                      nge = nge->frwd;
6243                  }
6244              } else if(ISDBG(FCONCISE))
6245                  fprintf(stderr, "(n=%p) ", nge);
6246          }
6247  
6248          pge = pge->frwd;  /* now the limits are pge...nge inclusive */
6249          if(pge == nge) /* a deeply perversive contour */
6250              break;
6251  
6252          if(ISDBG(FCONCISE)) {
6253              fprintf(stderr, "\nin %s joined LINE %p-%p from\n", g->name, pge, nge);
6254              dumppaths(g, pge, nge);
6255          }
6256          pge->type = GE_LINE;
6257          for(i=0; i<2; i++) {
6258              pge->fpoints[i][2] = nge->fpoints[i][2];
6259          }
6260          fnormalizege(pge);
6261          X_CON_F(pge) &= ~GEXF_JLINE;
6262  
6263          ge = pge;
6264          for(ige = pge->frwd; ; ige = pge->frwd) {
6265              if(ige == pge) {
6266                  fprintf(stderr, "WARNING: assertion in %s line %d, please report it to the ttf2pt1 project\n",
6267                      __FILE__, __LINE__);
6268                  free(dots);
6269                  return;
6270              }
6271              if(startge == ige)
6272                  startge = pge;
6273              free(ige->ext);
6274              freethisge(ige);
6275              if(ige == nge)
6276                  break;
6277          }
6278  next2:
6279          ge = ge->frwd;
6280          if(ge == startge)
6281              break;
6282      }
6283  
6284      free(dots);
6285  }
6286  
6287  /* force conciseness: substitute 2 or more curves going in the
6288  ** same quadrant with one curve
6289  ** in floating point
6290  */
6291  
6292  void
6293  fforceconcise(
6294           GLYPH * g
6295  )
6296  {
6297  
6298      GENTRY         *ge, *nge, *endge, *xge;
6299  
6300      assertisfloat(g, "enforcing conciseness");
6301  
6302      fdelsmall(g, 0.05);
6303      assertpath(g->entries, __FILE__, __LINE__, g->name);
6304  
6305      if(ISDBG(FCONCISE))
6306          dumppaths(g, NULL, NULL);
6307  
6308      /* collect more information about each gentry and their joints */
6309      for (ge = g->entries; ge != 0; ge = ge->next)
6310          if (ge->type == GE_CURVE || ge->type == GE_LINE)
6311              fnormalizege(ge);
6312  
6313      for (ge = g->entries; ge != 0; ge = ge->next)
6314          if (ge->type == GE_CURVE || ge->type == GE_LINE) {
6315              alloc_gex_con(ge);
6316              fanalyzege(ge);
6317          }
6318  
6319      /* see what we can do about joining */
6320      for (ge = g->entries; ge != 0; ge = ge->next)
6321          if (ge->type == GE_CURVE || ge->type == GE_LINE)
6322              fanalyzejoint(ge);
6323  
6324      /* now do the joining */
6325      for (ge = g->entries; ge != 0; ge = ge->next)
6326          if(ge->type == GE_MOVE)
6327              fconcisecontour(g, ge->next);
6328  
6329      for (ge = g->entries; ge != 0; ge = ge->next)
6330          if (ge->type == GE_CURVE || ge->type == GE_LINE)
6331              free(ge->ext);
6332  }
6333  
6334  void
6335  print_glyph(
6336         int glyphno
6337  )
6338  {
6339      GLYPH          *g;
6340      GENTRY         *ge;
6341      int             x = 0, y = 0;
6342      int             i;
6343      int             grp, lastgrp= -1;
6344  
6345      if(ISDBG(FCONCISE) && glyphno == 0) {
6346          fprintf(stderr, "Guessed curves: bad %d/%d good %d/%d\n",
6347              gbadcv, gbadcvdots, ggoodcv, ggoodcvdots);
6348      }
6349  
6350      g = &glyph_list[glyphno];
6351  
6352      fprintf(pfa_file, "/%s { \n", g->name);
6353  
6354      /* consider widths >MAXLEGALWIDTH as bugs */
6355      if( g->scaledwidth <= MAXLEGALWIDTH ) {
6356          fprintf(pfa_file, "0 %d hsbw\n", g->scaledwidth);
6357      } else {
6358          fprintf(pfa_file, "0 1000 hsbw\n");
6359          WARNING_2 fprintf(stderr, "glyph %s: width %d seems to be buggy, set to 1000\n",
6360              g->name, g->scaledwidth);
6361      }
6362  
6363  #if 0
6364      fprintf(pfa_file, "%% contours: ");
6365      for (i = 0; i < g->ncontours; i++)
6366          fprintf(pfa_file, "%s(%d,%d) ", (g->contours[i].direction == DIR_OUTER ? "out" : "in"),
6367              g->contours[i].xofmin, g->contours[i].ymin);
6368      fprintf(pfa_file, "\n");
6369  
6370      if (g->rymin < 5000)
6371          fprintf(pfa_file, "%d lower%s\n", g->rymin, (g->flatymin ? "flat" : "curve"));
6372      if (g->rymax > -5000)
6373          fprintf(pfa_file, "%d upper%s\n", g->rymax, (g->flatymax ? "flat" : "curve"));
6374  #endif
6375  
6376      if (g->hstems)
6377          for (i = 0; i < g->nhs; i += 2) {
6378              if (g->hstems[i].flags & ST_3) {
6379                  fprintf(pfa_file, "%d %d %d %d %d %d hstem3\n",
6380                      g->hstems[i].value,
6381                  g->hstems[i + 1].value - g->hstems[i].value,
6382                      g->hstems[i + 2].value,
6383                      g->hstems[i + 3].value - g->hstems[i + 2].value,
6384                      g->hstems[i + 4].value,
6385                      g->hstems[i + 5].value - g->hstems[i + 4].value
6386                      );
6387                  i += 4;
6388              } else {
6389                  fprintf(pfa_file, "%d %d hstem\n", g->hstems[i].value,
6390                  g->hstems[i + 1].value - g->hstems[i].value);
6391              }
6392          }
6393  
6394      if (g->vstems)
6395          for (i = 0; i < g->nvs; i += 2) {
6396              if (g->vstems[i].flags & ST_3) {
6397                  fprintf(pfa_file, "%d %d %d %d %d %d vstem3\n",
6398                      g->vstems[i].value,
6399                  g->vstems[i + 1].value - g->vstems[i].value,
6400                      g->vstems[i + 2].value,
6401                      g->vstems[i + 3].value - g->vstems[i + 2].value,
6402                      g->vstems[i + 4].value,
6403                      g->vstems[i + 5].value - g->vstems[i + 4].value
6404                      );
6405                  i += 4;
6406              } else {
6407                  fprintf(pfa_file, "%d %d vstem\n", g->vstems[i].value,
6408                  g->vstems[i + 1].value - g->vstems[i].value);
6409              }
6410          }
6411  
6412      for (ge = g->entries; ge != 0; ge = ge->next) {
6413          if(g->nsg>0) {
6414              grp=ge->stemid;
6415              if(grp >= 0 && grp != lastgrp)  {
6416                  fprintf(pfa_file, "%d 4 callsubr\n", grp+g->firstsubr);
6417                  lastgrp=grp;
6418              }
6419          }
6420  
6421          switch (ge->type) {
6422          case GE_MOVE:
6423              if (absolute)
6424                  fprintf(pfa_file, "%d %d amoveto\n", ge->ix3, ge->iy3);
6425              else
6426                  rmoveto(ge->ix3 - x, ge->iy3 - y);
6427              if (0)
6428                  fprintf(stderr, "Glyph %s: print moveto(%d, %d)\n",
6429                      g->name, ge->ix3, ge->iy3);
6430              x = ge->ix3;
6431              y = ge->iy3;
6432              break;
6433          case GE_LINE:
6434              if (absolute)
6435                  fprintf(pfa_file, "%d %d alineto\n", ge->ix3, ge->iy3);
6436              else
6437                  rlineto(ge->ix3 - x, ge->iy3 - y);
6438              x = ge->ix3;
6439              y = ge->iy3;
6440              break;
6441          case GE_CURVE:
6442              if (absolute)
6443                  fprintf(pfa_file, "%d %d %d %d %d %d arcurveto\n",
6444                      ge->ix1, ge->iy1, ge->ix2, ge->iy2, ge->ix3, ge->iy3);
6445              else
6446                  rrcurveto(ge->ix1 - x, ge->iy1 - y,
6447                        ge->ix2 - ge->ix1, ge->iy2 - ge->iy1,
6448                        ge->ix3 - ge->ix2, ge->iy3 - ge->iy2);
6449              x = ge->ix3;
6450              y = ge->iy3;
6451              break;
6452          case GE_PATH:
6453              closepath();
6454              break;
6455          default:
6456              WARNING_1 fprintf(stderr, "**** Glyph %s: unknown entry type '%c'\n",
6457                  g->name, ge->type);
6458              break;
6459          }
6460      }
6461  
6462      fprintf(pfa_file, "endchar } ND\n");
6463  }
6464  
6465  /* print the subroutines for this glyph, returns the number of them */
6466  int
6467  print_glyph_subs(
6468         int glyphno,
6469         int startid /* start numbering subroutines from this id */
6470  )
6471  {
6472      GLYPH *g;
6473      int i, grp;
6474  
6475      g = &glyph_list[glyphno];
6476  
6477      if(!hints || !subhints || g->nsg<1)
6478          return 0;
6479  
6480      g->firstsubr=startid;
6481  
6482  #if 0
6483      fprintf(pfa_file, "%% %s %d\n", g->name, g->nsg);
6484  #endif
6485      for(grp=0; grp<g->nsg; grp++) {
6486          fprintf(pfa_file, "dup %d {\n", startid++);
6487          for(i= (grp==0)? 0 : g->nsbs[grp-1]; i<g->nsbs[grp]; i++)
6488              fprintf(pfa_file, "\t%d %d %cstem\n", g->sbstems[i].low, 
6489                  g->sbstems[i].high-g->sbstems[i].low,
6490                  g->sbstems[i].isvert ? 'v' : 'h');
6491          fprintf(pfa_file, "\treturn\n\t} NP\n");
6492      }
6493  
6494      return g->nsg;
6495  }
6496  
6497  void
6498  print_glyph_metrics(
6499       FILE *afm_file,
6500         int code,
6501         int glyphno
6502  )
6503  {
6504      GLYPH *g;
6505  
6506      g = &glyph_list[glyphno];
6507  
6508      if(transform)
6509        fprintf(afm_file, "C %d ; WX %d ; N %s ; B %d %d %d %d ;\n",
6510            code, g->scaledwidth, g->name,
6511            iscale(g->xMin), iscale(g->yMin), iscale(g->xMax), iscale(g->yMax));
6512      else
6513        fprintf(afm_file, "C %d ; WX %d ; N %s ; B %d %d %d %d ;\n",
6514            code, g->scaledwidth, g->name,
6515            g->xMin, g->yMin, g->xMax, g->yMax);
6516  
6517  }
6518  
6519  void
6520  print_glyph_metrics_ufm(
6521       FILE *ufm_file,
6522         int code,
6523         int glyphno
6524  )
6525  {
6526      GLYPH *g;
6527  
6528      g = &glyph_list[glyphno];
6529  
6530    fprintf(ufm_file, "U %d ; WX %d ; N %s ; G %d ;\n",
6531        code, g->scaledwidth, g->name, glyphno);
6532  }
6533  /*
6534   SB:
6535   An important note about the BlueValues.
6536  
6537   The Adobe documentation says that the maximal width of a Blue zone
6538   is connected to the value of BlueScale, which is by default 0.039625.
6539   The BlueScale value defines, at which point size the overshoot
6540   suppression be disabled.
6541  
6542   The formula for it that is given in the manual is:
6543  
6544    BlueScale=point_size/240, for a 300dpi device
6545  
6546   that makes us wonder what is this 240 standing for. Incidentally
6547   240=72*1000/300, where 72 is the relation between inches and points,
6548   1000 is the size of the glyph matrix, and 300dpi is the resolution of
6549   the output device. Knowing that we can recalculate the formula for
6550   the font size in pixels rather than points:
6551  
6552    BlueScale=pixel_size/1000
6553  
6554   That looks a lot simpler than the original formula, does not it ?
6555   And the limitation about the maximal width of zone also looks
6556   a lot simpler after the transformation:
6557  
6558    max_width < 1000/pixel_size
6559  
6560   that ensures that even at the maximal pixel size when the overshoot
6561   suppression is disabled the zone width will be less than one pixel.
6562   This is important, failure to comply to this limit will result in
6563   really ugly fonts (been there, done that). But knowing the formula
6564   for the pixel width, we see that in fact we can use the maximal width
6565   of 24, not 23 as specified in the manual.
6566  
6567  */
6568  
6569  #define MAXBLUEWIDTH (24)
6570  
6571  /*
6572   * Find the indexes of the most frequent values
6573   * in the hystogram, sort them in ascending order, and save which one
6574   * was the best one (if asked).
6575   * Returns the number of values found (may be less than maximal because
6576   * we ignore the zero values)
6577   */
6578  
6579  #define MAXHYST    (2000)        /* size of the hystogram */
6580  #define HYSTBASE 500
6581  
6582  static int
6583  besthyst(
6584       int *hyst,        /* the hystogram */
6585       int base,        /* the base point of the hystogram */
6586       int *best,        /* the array for indexes of best values */
6587       int nbest,        /* its allocated size */
6588       int width,        /* minimal difference between indexes */
6589       int *bestindp        /* returned top point */
6590  )
6591  {
6592      unsigned char   hused[MAXHYST / 8 + 1];
6593      int             i, max, j, w, last = 0;
6594      int             nf = 0;
6595  
6596      width--;
6597  
6598      memset(hused, 0 , sizeof hused);
6599  
6600      max = 1;
6601      for (i = 0; i < nbest && max != 0; i++) {
6602          best[i] = 0;
6603          max = 0;
6604          for (j = 1; j < MAXHYST - 1; j++) {
6605              w = hyst[j];
6606  
6607              if (w > max && (hused[j>>3] & (1 << (j & 0x07))) == 0) {
6608                  best[i] = j;
6609                  max = w;
6610              }
6611          }
6612          if (max != 0) {
6613              if (max < last/2) {
6614                  /* do not pick the too low values */
6615                  break;
6616              }
6617              for (j = best[i] - width; j <= best[i] + width; j++) {
6618                  if (j >= 0 && j < MAXHYST)
6619                      hused[j >> 3] |= (1 << (j & 0x07));
6620              }
6621              last = max;
6622              best[i] -= base;
6623              nf = i + 1;
6624          }
6625      }
6626  
6627      if (bestindp)
6628          *bestindp = best[0];
6629  
6630      /* sort the indexes in ascending order */
6631      for (i = 0; i < nf; i++) {
6632          for (j = i + 1; j < nf; j++)
6633              if (best[j] < best[i]) {
6634                  w = best[i];
6635                  best[i] = best[j];
6636                  best[j] = w;
6637              }
6638      }
6639  
6640      return nf;
6641  }
6642  
6643  /*
6644   * Find the next best Blue zone in the hystogram.
6645   * Return the weight of the found zone.
6646   */
6647  
6648  static int
6649  bestblue(
6650       short *zhyst,        /* the zones hystogram */
6651       short *physt,        /* the points hystogram */
6652       short *ozhyst,        /* the other zones hystogram */
6653       int *bluetab        /* where to put the found zone */
6654  )
6655  {
6656      int             i, j, w, max, ind, first, last;
6657  
6658      /* find the highest point in the zones hystogram */
6659      /* if we have a plateau, take its center */
6660      /* if we have multiple peaks, take the first one */
6661  
6662      max = -1;
6663      first = last = -10;
6664      for (i = 0; i <= MAXHYST - MAXBLUEWIDTH; i++) {
6665          w = zhyst[i];
6666          if (w > max) {
6667              first = last = i;
6668              max = w;
6669          } else if (w == max) {
6670              if (last == i - 1)
6671                  last = i;
6672          }
6673      }
6674      ind = (first + last) / 2;
6675  
6676      if (max == 0)        /* no zones left */
6677          return 0;
6678  
6679      /* now we reuse `first' and `last' as inclusive borders of the zone */
6680      first = ind;
6681      last = ind + (MAXBLUEWIDTH - 1);
6682  
6683      /* our maximal width is far too big, so we try to make it narrower */
6684      w = max;
6685      j = (w & 1);        /* a pseudo-random bit */
6686      while (1) {
6687          while (physt[first] == 0)
6688              first++;
6689          while (physt[last] == 0)
6690              last--;
6691          if (last - first < (MAXBLUEWIDTH * 2 / 3) || (max - w) * 10 > max)
6692              break;
6693  
6694          if (physt[first] < physt[last]
6695              || physt[first] == physt[last] && j) {
6696              if (physt[first] * 20 > w)    /* if weight is >5%,
6697                               * stop */
6698                  break;
6699              w -= physt[first];
6700              first++;
6701              j = 0;
6702          } else {
6703              if (physt[last] * 20 > w)    /* if weight is >5%,
6704                               * stop */
6705                  break;
6706              w -= physt[last];
6707              last--;
6708              j = 1;
6709          }
6710      }
6711  
6712      /* save our zone */
6713      bluetab[0] = first - HYSTBASE;
6714      bluetab[1] = last - HYSTBASE;
6715  
6716      /* invalidate all the zones overlapping with this one */
6717      /* the constant of 2 is determined by the default value of BlueFuzz */
6718      for (i = first - (MAXBLUEWIDTH - 1) - 2; i <= last + 2; i++)
6719          if (i >= 0 && i < MAXHYST) {
6720              zhyst[i] = 0;
6721              ozhyst[i] = 0;
6722          }
6723      return w;
6724  }
6725  
6726  /*
6727   * Try to find the Blue Values, bounding box and italic angle
6728   */
6729  
6730  void
6731  findblues(void)
6732  {
6733      /* hystograms for upper and lower zones */
6734      short           hystl[MAXHYST];
6735      short           hystu[MAXHYST];
6736      short           zuhyst[MAXHYST];
6737      short           zlhyst[MAXHYST];
6738      int             nchars;
6739      int             i, j, k, w, max;
6740      GENTRY         *ge;
6741      GLYPH          *g;
6742      double          ang;
6743  
6744      /* find the lowest and highest points of glyphs */
6745      /* and by the way build the values for FontBBox */
6746      /* and build the hystogram for the ItalicAngle */
6747  
6748      /* re-use hystl for the hystogram of italic angle */
6749  
6750      bbox[0] = bbox[1] = 5000;
6751      bbox[2] = bbox[3] = -5000;
6752  
6753      for (i = 0; i < MAXHYST; i++)
6754          hystl[i] = 0;
6755  
6756      nchars = 0;
6757  
6758      for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
6759          if (g->flags & GF_USED) {
6760              nchars++;
6761  
6762              g->rymin = 5000;
6763              g->rymax = -5000;
6764              for (ge = g->entries; ge != 0; ge = ge->next) {
6765                  if (ge->type == GE_LINE) {
6766  
6767                      j = ge->iy3 - ge->prev->iy3;
6768                      k = ge->ix3 - ge->prev->ix3;
6769                      if (j > 0)
6770                          ang = atan2(-k, j) * 180.0 / M_PI;
6771                      else
6772                          ang = atan2(k, -j) * 180.0 / M_PI;
6773  
6774                      k /= 100;
6775                      j /= 100;
6776                      if (ang > -45.0 && ang < 45.0) {
6777                          /*
6778                           * be careful to not overflow
6779                           * the counter
6780                           */
6781                          hystl[HYSTBASE + (int) (ang * 10.0)] += (k * k + j * j) / 4;
6782                      }
6783                      if (ge->iy3 == ge->prev->iy3) {
6784                          if (ge->iy3 <= g->rymin) {
6785                              g->rymin = ge->iy3;
6786                              g->flatymin = 1;
6787                          }
6788                          if (ge->iy3 >= g->rymax) {
6789                              g->rymax = ge->iy3;
6790                              g->flatymax = 1;
6791                          }
6792                      } else {
6793                          if (ge->iy3 < g->rymin) {
6794                              g->rymin = ge->iy3;
6795                              g->flatymin = 0;
6796                          }
6797                          if (ge->iy3 > g->rymax) {
6798                              g->rymax = ge->iy3;
6799                              g->flatymax = 0;
6800                          }
6801                      }
6802                  } else if (ge->type == GE_CURVE) {
6803                      if (ge->iy3 < g->rymin) {
6804                          g->rymin = ge->iy3;
6805                          g->flatymin = 0;
6806                      }
6807                      if (ge->iy3 > g->rymax) {
6808                          g->rymax = ge->iy3;
6809                          g->flatymax = 0;
6810                      }
6811                  }
6812                  if (ge->type == GE_LINE || ge->type == GE_CURVE) {
6813                      if (ge->ix3 < bbox[0])
6814                          bbox[0] = ge->ix3;
6815                      if (ge->ix3 > bbox[2])
6816                          bbox[2] = ge->ix3;
6817                      if (ge->iy3 < bbox[1])
6818                          bbox[1] = ge->iy3;
6819                      if (ge->iy3 > bbox[3])
6820                          bbox[3] = ge->iy3;
6821                  }
6822              }
6823          }
6824      }
6825  
6826      /* get the most popular angle */
6827      max = 0;
6828      w = 0;
6829      for (i = 0; i < MAXHYST; i++) {
6830          if (hystl[i] > w) {
6831              w = hystl[i];
6832              max = i;
6833          }
6834      }
6835      ang = (double) (max - HYSTBASE) / 10.0;
6836      WARNING_2 fprintf(stderr, "Guessed italic angle: %f\n", ang);
6837      if (italic_angle == 0.0)
6838          italic_angle = ang;
6839  
6840      /* build the hystogram of the lower points */
6841      for (i = 0; i < MAXHYST; i++)
6842          hystl[i] = 0;
6843  
6844      for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
6845          if ((g->flags & GF_USED)
6846              && g->rymin + HYSTBASE >= 0 && g->rymin < MAXHYST - HYSTBASE) {
6847              hystl[g->rymin + HYSTBASE]++;
6848          }
6849      }
6850  
6851      /* build the hystogram of the upper points */
6852      for (i = 0; i < MAXHYST; i++)
6853          hystu[i] = 0;
6854  
6855      for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
6856          if ((g->flags & GF_USED)
6857              && g->rymax + HYSTBASE >= 0 && g->rymax < MAXHYST - HYSTBASE) {
6858              hystu[g->rymax + HYSTBASE]++;
6859          }
6860      }
6861  
6862      /* build the hystogram of all the possible lower zones with max width */
6863      for (i = 0; i < MAXHYST; i++)
6864          zlhyst[i] = 0;
6865  
6866      for (i = 0; i <= MAXHYST - MAXBLUEWIDTH; i++) {
6867          for (j = 0; j < MAXBLUEWIDTH; j++)
6868              zlhyst[i] += hystl[i + j];
6869      }
6870  
6871      /* build the hystogram of all the possible upper zones with max width */
6872      for (i = 0; i < MAXHYST; i++)
6873          zuhyst[i] = 0;
6874  
6875      for (i = 0; i <= MAXHYST - MAXBLUEWIDTH; i++) {
6876          for (j = 0; j < MAXBLUEWIDTH; j++)
6877              zuhyst[i] += hystu[i + j];
6878      }
6879  
6880      /* find the baseline */
6881      w = bestblue(zlhyst, hystl, zuhyst, &bluevalues[0]);
6882      if (0)
6883          fprintf(stderr, "BaselineBlue zone %d%% %d...%d\n", w * 100 / nchars,
6884                  bluevalues[0], bluevalues[1]);
6885  
6886      if (w == 0)        /* no baseline, something weird */
6887          return;
6888  
6889      /* find the upper zones */
6890      for (nblues = 2; nblues < 14; nblues += 2) {
6891          w = bestblue(zuhyst, hystu, zlhyst, &bluevalues[nblues]);
6892  
6893          if (0)
6894              fprintf(stderr, "Blue zone %d%% %d...%d\n", w * 100 / nchars, 
6895                  bluevalues[nblues], bluevalues[nblues+1]);
6896  
6897          if (w * 20 < nchars)
6898              break;    /* don't save this zone */
6899      }
6900  
6901      /* find the lower zones */
6902      for (notherb = 0; notherb < 10; notherb += 2) {
6903          w = bestblue(zlhyst, hystl, zuhyst, &otherblues[notherb]);
6904  
6905          if (0)
6906              fprintf(stderr, "OtherBlue zone %d%% %d...%d\n", w * 100 / nchars,
6907                  otherblues[notherb], otherblues[notherb+1]);
6908  
6909  
6910          if (w * 20 < nchars)
6911              break;    /* don't save this zone */
6912      }
6913  
6914  }
6915  
6916  /*
6917   * Find the actual width of the glyph and modify the
6918   * description to reflect it. Not guaranteed to do
6919   * any good, may make character spacing too wide.
6920   */
6921  
6922  void
6923  docorrectwidth(void)
6924  {
6925      int             i;
6926      GENTRY         *ge;
6927      GLYPH          *g;
6928      int             xmin, xmax;
6929      int             maxwidth, minsp;
6930  
6931      /* enforce this minimal spacing,
6932       * we limit the amount of the enforced spacing to avoid
6933       * spacing the bold wonts too widely
6934       */
6935      minsp = (stdhw>60 || stdhw<10)? 60 : stdhw;
6936  
6937      for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
6938          g->oldwidth=g->scaledwidth; /* save the old width, will need for AFM */
6939  
6940          if (correctwidth && g->flags & GF_USED) {
6941              xmin = 5000;
6942              xmax = -5000;
6943              for (ge = g->entries; ge != 0; ge = ge->next) {
6944                  if (ge->type != GE_LINE && ge->type != GE_CURVE) 
6945                      continue;
6946  
6947                  if (ge->ix3 <= xmin) {
6948                      xmin = ge->ix3;
6949                  }
6950                  if (ge->ix3 >= xmax) {
6951                      xmax = ge->ix3;
6952                  }
6953              }
6954  
6955              maxwidth=xmax+minsp;
6956              if( g->scaledwidth < maxwidth ) {
6957                  g->scaledwidth = maxwidth;
6958                  WARNING_3 fprintf(stderr, "glyph %s: extended from %d to %d\n",
6959                      g->name, g->oldwidth, g->scaledwidth );
6960              }
6961          }
6962      }
6963  
6964  }
6965  
6966  /*
6967   * Try to find the typical stem widths
6968   */
6969  
6970  void
6971  stemstatistics(void)
6972  {
6973  #define MINDIST    10 /* minimal distance between the widths */
6974      int             hyst[MAXHYST+MINDIST*2];
6975      int             best[12];
6976      int             i, j, k, w;
6977      int             nchars;
6978      int             ns;
6979      STEM           *s;
6980      GLYPH          *g;
6981  
6982      /* start with typical stem width */
6983  
6984      nchars=0;
6985  
6986      /* build the hystogram of horizontal stem widths */
6987      memset(hyst, 0, sizeof hyst);
6988  
6989      for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
6990          if (g->flags & GF_USED) {
6991              nchars++;
6992              s = g->hstems;
6993              for (j = 0; j < g->nhs; j += 2) {
6994                  if ((s[j].flags | s[j + 1].flags) & ST_END)
6995                      continue;
6996                  w = s[j + 1].value - s[j].value+1;
6997                  if(w==20) /* split stems should not be counted */
6998                      continue;
6999                  if (w > 0 && w < MAXHYST - 1) {
7000                      /*
7001                       * handle some fuzz present in
7002                       * converted fonts
7003                       */
7004                      hyst[w+MINDIST] += MINDIST-1;
7005                      for(k=1; k<MINDIST-1; k++) {
7006                          hyst[w+MINDIST + k] += MINDIST-1-k;
7007                          hyst[w+MINDIST - k] += MINDIST-1-k;
7008                      }
7009                  }
7010              }
7011          }
7012      }
7013  
7014      /* find 12 most frequent values */
7015      ns = besthyst(hyst+MINDIST, 0, best, 12, MINDIST, &stdhw);
7016  
7017      /* store data in stemsnaph */
7018      for (i = 0; i < ns; i++)
7019          stemsnaph[i] = best[i];
7020      if (ns < 12)
7021          stemsnaph[ns] = 0;
7022  
7023      /* build the hystogram of vertical stem widths */
7024      memset(hyst, 0, sizeof hyst);
7025  
7026      for (i = 0, g = glyph_list; i < numglyphs; i++, g++) {
7027          if (g->flags & GF_USED) {
7028              s = g->vstems;
7029              for (j = 0; j < g->nvs; j += 2) {
7030                  if ((s[j].flags | s[j + 1].flags) & ST_END)
7031                      continue;
7032                  w = s[j + 1].value - s[j].value+1;
7033                  if (w > 0 && w < MAXHYST - 1) {
7034                      /*
7035                       * handle some fuzz present in
7036                       * converted fonts
7037                       */
7038                      hyst[w+MINDIST] += MINDIST-1;
7039                      for(k=1; k<MINDIST-1; k++) {
7040                          hyst[w+MINDIST + k] += MINDIST-1-k;
7041                          hyst[w+MINDIST - k] += MINDIST-1-k;
7042                      }
7043                  }
7044              }
7045          }
7046      }
7047  
7048      /* find 12 most frequent values */
7049      ns = besthyst(hyst+MINDIST, 0, best, 12, MINDIST, &stdvw);
7050  
7051      /* store data in stemsnaph */
7052      for (i = 0; i < ns; i++)
7053          stemsnapv[i] = best[i];
7054      if (ns < 12)
7055          stemsnapv[ns] = 0;
7056  
7057  #undef MINDIST
7058  }
7059  
7060  /*
7061   * SB
7062   * A funny thing: TTF paths are going in reverse direction compared
7063   * to Type1. So after all (because the rest of logic uses TTF
7064   * path directions) we have to reverse the paths.
7065   *
7066   * It was a big headache to discover that.
7067   */
7068  
7069  /* works on both int and float paths */
7070  
7071  void
7072  reversepathsfromto(
7073             GENTRY * from,
7074             GENTRY * to
7075  )
7076  {
7077      GENTRY         *ge, *nge, *pge;
7078      GENTRY         *cur, *next;
7079      int i, n, ilast[2];
7080      double flast[2], f;
7081  
7082      for (ge = from; ge != 0 && ge != to; ge = ge->next) {
7083          if(ge->type == GE_LINE || ge->type == GE_CURVE) {
7084              if (ISDBG(REVERSAL))
7085                  fprintf(stderr, "reverse path 0x%x <- 0x%x, 0x%x\n", ge, ge->prev, ge->bkwd);
7086  
7087              /* cut out the path itself */
7088              pge = ge->prev; /* GE_MOVE */
7089              if (pge == 0) {
7090                  fprintf(stderr, "**! No MOVE before line !!! Fatal. ****\n");
7091                  exit(1);
7092              }
7093              nge = ge->bkwd->next; /* GE_PATH */
7094              pge->next = nge;
7095              nge->prev = pge;
7096              ge->bkwd->next = 0; /* mark end of chain */
7097  
7098              /* remember the starting point */
7099              if(ge->flags & GEF_FLOAT) {
7100                  flast[0] = pge->fx3;
7101                  flast[1] = pge->fy3;
7102              } else {
7103                  ilast[0] = pge->ix3;
7104                  ilast[1] = pge->iy3;
7105              }
7106  
7107              /* then reinsert them in backwards order */
7108              for(cur = ge; cur != 0; cur = next ) {
7109                  next = cur->next; /* or addgeafter() will screw it up */
7110                  if(cur->flags & GEF_FLOAT) {
7111                      for(i=0; i<2; i++) {
7112                          /* reverse the direction of path element */
7113                          f = cur->fpoints[i][0];
7114                          cur->fpoints[i][0] = cur->fpoints[i][1];
7115                          cur->fpoints[i][1] = f;
7116                          f = flast[i];
7117                          flast[i] = cur->fpoints[i][2];
7118                          cur->fpoints[i][2] = f;
7119                      }
7120                  } else {
7121                      for(i=0; i<2; i++) {
7122                          /* reverse the direction of path element */
7123                          n = cur->ipoints[i][0];
7124                          cur->ipoints[i][0] = cur->ipoints[i][1];
7125                          cur->ipoints[i][1] = n;
7126                          n = ilast[i];
7127                          ilast[i] = cur->ipoints[i][2];
7128                          cur->ipoints[i][2] = n;
7129                      }
7130                  }
7131                  addgeafter(pge, cur);
7132              }
7133  
7134              /* restore the starting point */
7135              if(ge->flags & GEF_FLOAT) {
7136                  pge->fx3 = flast[0];
7137                  pge->fy3 = flast[1];
7138              } else {
7139                  pge->ix3 = ilast[0];
7140                  pge->iy3 = ilast[1];
7141              }
7142  
7143              ge = nge;
7144          }
7145  
7146      }
7147  }
7148  
7149  void
7150  reversepaths(
7151           GLYPH * g
7152  )
7153  {
7154      reversepathsfromto(g->entries, NULL);
7155  }
7156  
7157  /* add a kerning pair information, scales the value */
7158  
7159  void
7160  addkernpair(
7161      unsigned id1,
7162      unsigned id2,
7163      int unscval
7164  )
7165  {
7166      static unsigned char *bits = 0;
7167      static int lastid;
7168      GLYPH *g = &glyph_list[id1];
7169      int i, n;
7170      struct kern *p;
7171  
7172      if(unscval == 0 || id1 >= numglyphs || id2 >= numglyphs)
7173          return;
7174  
7175      if( (glyph_list[id1].flags & GF_USED)==0
7176      || (glyph_list[id2].flags & GF_USED)==0 )
7177          return;
7178  
7179      if(bits == 0) {
7180          bits = calloc( BITMAP_BYTES(numglyphs), 1);
7181          if (bits == NULL) {
7182              fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__);
7183              exit(255);
7184          }
7185          lastid = id1;
7186      }
7187  
7188      if(lastid != id1) {
7189          /* refill the bitmap cache */
7190          memset(bits, 0,BITMAP_BYTES(numglyphs));
7191          p = g->kern;
7192          for(i=g->kerncount; i>0; i--) {
7193              n = (p++)->id;
7194              SET_BITMAP(bits, n);
7195          }
7196          lastid = id1;
7197      }
7198  
7199      if(IS_BITMAP(bits, id2))
7200          return; /* duplicate */
7201  
7202      if(g->kerncount <= g->kernalloc) {
7203          g->kernalloc += 8;
7204          p = realloc(g->kern, sizeof(struct kern) * g->kernalloc);
7205          if(p == 0) {
7206              fprintf (stderr, "** realloc failed, kerning data will be incomplete\n");
7207          }
7208          g->kern = p;
7209      }
7210  
7211      SET_BITMAP(bits, id2);
7212      p = &g->kern[g->kerncount];
7213      p->id = id2;
7214      p->val = iscale(unscval) - (g->scaledwidth - g->oldwidth);
7215      g->kerncount++;
7216      kerning_pairs++;
7217  }
7218  
7219  /* print out the kerning information */
7220  
7221  void
7222  print_kerning(
7223      FILE *afm_file
7224  )
7225  {
7226      int    i, j, n;
7227      GLYPH *g;
7228      struct kern *p;
7229  
7230      if( kerning_pairs == 0 ) 
7231          return;
7232  
7233      fprintf(afm_file, "StartKernData\n");
7234      fprintf(afm_file, "StartKernPairs %hd\n", kerning_pairs);
7235  
7236      for(i=0; i<numglyphs; i++)  {
7237          g = &glyph_list[i];
7238          if( (g->flags & GF_USED) ==0)
7239              continue;
7240          p = g->kern;
7241          for(j=g->kerncount; j>0; j--, p++) {
7242              fprintf(afm_file, "KPX %s %s %d\n", g->name, 
7243                  glyph_list[ p->id ].name, p->val );
7244          }
7245      }
7246  
7247      fprintf(afm_file, "EndKernPairs\n");
7248      fprintf(afm_file, "EndKernData\n");
7249  }
7250  
7251  
7252  #if 0
7253  
7254  /*
7255  ** This function is commented out because the information
7256  ** collected by it is not used anywhere else yet. Now
7257  ** it only collects the directions of contours. And the
7258  ** direction of contours gets fixed already in draw_glyf().
7259  **
7260  ***********************************************
7261  **
7262  ** Here we expect that the paths are already closed.
7263  ** We also expect that the contours do not intersect
7264  ** and that curves doesn't cross any border of quadrant.
7265  **
7266  ** Find which contours go inside which and what is
7267  ** their proper direction. Then fix the direction
7268  ** to make it right.
7269  **
7270  */
7271  
7272  #define MAXCONT    1000
7273  
7274  void
7275  fixcontours(
7276          GLYPH * g
7277  )
7278  {
7279      CONTOUR         cont[MAXCONT];
7280      short           ymax[MAXCONT];    /* the highest point */
7281      short           xofmax[MAXCONT];    /* X-coordinate of any point
7282                           * at ymax */
7283      short           ymin[MAXCONT];    /* the lowest point */
7284      short           xofmin[MAXCONT];    /* X-coordinate of any point
7285                           * at ymin */
7286      short           count[MAXCONT];    /* count of lines */
7287      char            dir[MAXCONT];    /* in which direction they must go */
7288      GENTRY         *start[MAXCONT], *minptr[MAXCONT], *maxptr[MAXCONT];
7289      int             ncont;
7290      int             i;
7291      int             dx1, dy1, dx2, dy2;
7292      GENTRY         *ge, *nge;
7293  
7294      /* find the contours and their most upper/lower points */
7295      ncont = 0;
7296      ymax[0] = -5000;
7297      ymin[0] = 5000;
7298      for (ge = g->entries; ge != 0; ge = ge->next) {
7299          if (ge->type == GE_LINE || ge->type == GE_CURVE) {
7300              if (ge->iy3 > ymax[ncont]) {
7301                  ymax[ncont] = ge->iy3;
7302                  xofmax[ncont] = ge->ix3;
7303                  maxptr[ncont] = ge;
7304              }
7305              if (ge->iy3 < ymin[ncont]) {
7306                  ymin[ncont] = ge->iy3;
7307                  xofmin[ncont] = ge->ix3;
7308                  minptr[ncont] = ge;
7309              }
7310          }
7311          if (ge->frwd != ge->next) {
7312              start[ncont++] = ge->frwd;
7313              ymax[ncont] = -5000;
7314              ymin[ncont] = 5000;
7315          }
7316      }
7317  
7318      /* determine the directions of contours */
7319      for (i = 0; i < ncont; i++) {
7320          ge = minptr[i];
7321          nge = ge->frwd;
7322  
7323          if (ge->type == GE_CURVE) {
7324              dx1 = ge->ix3 - ge->ix2;
7325              dy1 = ge->iy3 - ge->iy2;
7326  
7327              if (dx1 == 0 && dy1 == 0) {    /* a pathological case */
7328                  dx1 = ge->ix3 - ge->ix1;
7329                  dy1 = ge->iy3 - ge->iy1;
7330              }
7331              if (dx1 == 0 && dy1 == 0) {    /* a more pathological
7332                               * case */
7333                  dx1 = ge->ix3 - ge->prev->ix3;
7334                  dy1 = ge->iy3 - ge->prev->iy3;
7335              }
7336          } else {
7337              dx1 = ge->ix3 - ge->prev->ix3;
7338              dy1 = ge->iy3 - ge->prev->iy3;
7339          }
7340          if (nge->type == GE_CURVE) {
7341              dx2 = ge->ix3 - nge->ix1;
7342              dy2 = ge->iy3 - nge->iy1;
7343              if (dx1 == 0 && dy1 == 0) {    /* a pathological case */
7344                  dx2 = ge->ix3 - nge->ix2;
7345                  dy2 = ge->iy3 - nge->iy2;
7346              }
7347              if (dx1 == 0 && dy1 == 0) {    /* a more pathological
7348                               * case */
7349                  dx2 = ge->ix3 - nge->ix3;
7350                  dy2 = ge->iy3 - nge->iy3;
7351              }
7352          } else {
7353              dx2 = ge->ix3 - nge->ix3;
7354              dy2 = ge->iy3 - nge->iy3;
7355          }
7356  
7357          /* compare angles */
7358          cont[i].direction = DIR_INNER;
7359          if (dy1 == 0) {
7360              if (dx1 < 0)
7361                  cont[i].direction = DIR_OUTER;
7362          } else if (dy2 == 0) {
7363              if (dx2 > 0)
7364                  cont[i].direction = DIR_OUTER;
7365          } else if (dx2 * dy1 < dx1 * dy2)
7366              cont[i].direction = DIR_OUTER;
7367  
7368          cont[i].ymin = ymin[i];
7369          cont[i].xofmin = xofmin[i];
7370      }
7371  
7372      /* save the information that may be needed further */
7373      g->ncontours = ncont;
7374      if (ncont > 0) {
7375          g->contours = malloc(sizeof(CONTOUR) * ncont);
7376          if (g->contours == 0) {
7377              fprintf(stderr, "***** Memory allocation error *****\n");
7378              exit(255);
7379          }
7380          memcpy(g->contours, cont, sizeof(CONTOUR) * ncont);
7381      }
7382  }
7383  
7384  #endif
7385  
7386  /*
7387   *
7388   */
7389  


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1