home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / prog / c / post17s.lha / postfont.c < prev    next >
C/C++ Source or Header  |  1992-03-07  |  54KB  |  1,622 lines

  1. /* PostScript interpreter file "postfont.c" - type 1 font routines
  2.  * (C) Adrian Aylward 1989, 1992
  3.  * V1.6 First source release
  4.  * V1.7 Rewrite hinting to interpolate between stems
  5.  * V1.7 Allow real values of blueshift and bluefuzz
  6.  */
  7.  
  8. # include "post.h"
  9.  
  10. /* # define FONTDEBUG Enable font debugging (make file does this) */
  11.  
  12. /* Character string execution data */
  13.  
  14. # define charmaxdepth    10
  15. # define charstacksize   24
  16.  
  17. static int charnest, charargn, charend, charaflag;
  18.  
  19. static float charstack[charstacksize], charargs[charstacksize];
  20.  
  21. static int charsbwlength, chardotsection, charflexn;
  22.  
  23. static float charsbw[4], charfptx[7], charfpty[7];
  24. static float charssx, charssy, charsdx, charsdy, charadx, charady;
  25. static float charcpx, charcpy;
  26.  
  27. static struct point lastpoint;
  28.  
  29. /* Default overshoot suppression */
  30.  
  31. # define defbluescale  0.05
  32.  
  33. /* Blues and Stems */
  34.  
  35. # define maxstem         20
  36.  
  37. struct stem
  38. {   int type;
  39.     float s1, s2;
  40.     float z1, z2;
  41. };
  42.  
  43. struct stform
  44. {   int flag;
  45.     float scale;
  46.     int stemc;
  47.     struct stem stemv[maxstem];
  48. };
  49.  
  50. static struct stform hstform, vstform;
  51.  
  52. # define maxblue         12
  53.  
  54. static int bluec;
  55. static struct stem bluev[maxblue];
  56.  
  57. static float bluescale, blueshift, bluefuzz;
  58.  
  59. /* Routines */
  60.  
  61. extern void buildachar(int schar);
  62. extern void charstring(struct object *token1, int depth);
  63. extern void charpoint(struct point *ppoint);
  64. extern void hintpoint(struct point *cpoint, struct point *ppoint);
  65. extern void hintadjust(float *ps, float *pz, struct stform *pstform);
  66. extern void setstems(struct stform *pstform, int num);
  67. extern void setblues(void);
  68. extern void charfill(void);
  69. extern void charline(struct point *ppoint);
  70. extern void setxbuf(int size);
  71.  
  72.  
  73. /* Debugging procedures */
  74.  
  75. # ifdef FONTDEBUG
  76. # define FDEBUGN(s, n) fdebugn(depth, s, n)
  77. # else
  78. # define FDEBUGN(s, n)
  79. # endif
  80.  
  81. # ifdef FONTDEBUG
  82.  
  83. /* On the Amiga we can't redirect stderr, so use stdout instead */
  84.  
  85. # ifdef AMIGA
  86. # ifdef stderr
  87. # undef stderr
  88. # endif
  89. # define stderr stdout
  90. # endif
  91.  
  92. /* Debug mode values (bits)
  93.  *    1  Trace charstring commands
  94.  *    2  Trace path points
  95.  *    4  Trace hints
  96.  *    8  Display blues
  97.  */
  98.  
  99. int fontdebug;
  100.  
  101. /* setfontdebug */
  102.  
  103. void opsetfontdebug(void)
  104. {   struct object *token1;
  105.     if (opernest < 1) error(errstackunderflow);
  106.     token1 = &operstack[opernest - 1];
  107.     if (token1->type != typeint) error(errtypecheck);
  108.     fontdebug = token1->value.ival;
  109.     opernest--;
  110. }
  111.  
  112. /* Operator trace */
  113.  
  114. void fdebugn(int depth, char *sptr, int n)
  115. {   int i;
  116.     if (fontdebug & 1)
  117.     {   if (depth == 0)
  118.             fprintf(stderr, ">>");
  119.         else
  120.             fprintf(stderr, "%d>", depth);
  121.         fprintf(stderr, " (%4.0f,%4.0f) %2d %-13s ",
  122.                 charcpx, charcpy, charnest, sptr);
  123.         for (i = 0; i < n; i++)
  124.             fprintf(stderr, " %4.4g", charstack[i]);
  125.         fprintf(stderr, "\n");
  126.     }
  127. }
  128. # endif
  129.  
  130. /* Initialise type 1 fonts */
  131.  
  132. void initfont(void)
  133. {   xbsize = 0;
  134. # ifdef FONTDEBUG
  135.     systemop(opsetfontdebug,     "setfontdebug");
  136. # endif
  137. }
  138.  
  139. /* Initialise type 1 font build data */
  140.  
  141. void initbuild(vmref fdref)
  142. {   struct object token, *aptr;
  143.     struct stem blue;
  144.     int i;
  145.  
  146.     /* Extract the build data */
  147.  
  148.     fontmetrics = NULL;
  149.     if (dictget(fdref, &charname[charmetrics], &token, 0))
  150.     {   if (token.type != typedict) error(errinvalidfont);
  151.         fontmetrics = token.value.vref;
  152.     }
  153.     if (!dictget(fdref, &charname[charpainttype], &token, 0) ||
  154.         token.type != typeint ||
  155.         (token.value.ival != 0 && token.value.ival != 2))
  156.         error(errinvalidfont);
  157.     fontpainttype = token.value.ival;
  158.     if (fontpainttype != 0)
  159.     {   if (!dictget(fdref, &charname[charstrokewidth], &token, 0))
  160.             error(errinvalidfont);
  161.         if      (token.type == typeint)
  162.             fontstrokewidth = token.value.ival;
  163.         else if (token.type == typereal)
  164.             fontstrokewidth = token.value.rval;
  165.         else
  166.             error(errinvalidfont);
  167.     }
  168.     if (!dictget(fdref, &charname[charcharstrings], &token, 0) ||
  169.         token.type != typedict)
  170.         error(errinvalidfont);
  171.     fontcharstrings = token.value.vref;
  172.     if (!dictget(fdref, &charname[charprivate], &token, 0) ||
  173.         token.type != typedict)
  174.         error(errinvalidfont);
  175.     fontprivate = token.value.vref;
  176.     if (dictget(fontprivate, &charname[charsubrs], &fontsubrs, 0))
  177.     {   if (fontsubrs.type != typearray) error(errinvalidfont);
  178.     }
  179.     else
  180.         fontsubrs.length = 0;
  181.     if (dictget(fontprivate, &charname[charleniv], &token, 0))
  182.     {   if (token.type != typeint || token.value.ival < 0)
  183.             error(errinvalidfont);
  184.         fontleniv = token.value.ival;
  185.     }
  186.     else
  187.         fontleniv = 4;
  188.  
  189.     /* Extract the blues */
  190.  
  191.     bluec = 0;
  192.     if (dictget(fontprivate, &charname[charbluevalues], &token, 0))
  193.     {   if (token.type != typearray ||
  194.             token.length > maxblue + 2 || (token.length & 1))
  195.             error(errinvalidfont);
  196.         i = token.length >> 1;
  197.         aptr = vmaptr(token.value.vref);
  198.         blue.type = -1;
  199.         while (i--)
  200.         {   token = *aptr++;
  201.             if (token.type != typeint) error(errinvalidfont);
  202.             blue.s1 = token.value.ival;
  203.             token = *aptr++;
  204.             if (token.type != typeint) error(errinvalidfont);
  205.             blue.s2 = token.value.ival;
  206.             bluev[bluec++] = blue;
  207.             blue.type = 1;
  208.         }
  209.     }
  210.     if (dictget(fontprivate, &charname[charotherblues], &token, 0))
  211.     {   if (token.type != typearray ||
  212.             token.length > maxblue - 2 || (token.length & 1))
  213.             error(errinvalidfont);
  214.         i = token.length >> 1;
  215.         aptr = vmaptr(token.value.vref);
  216.         blue.type = -1;
  217.         while (i--)
  218.         {   token = *aptr++;
  219.             if (token.type != typeint) error(errinvalidfont);
  220.             blue.s1 = token.value.ival;
  221.             token = *aptr++;
  222.             if (token.type != typeint) error(errinvalidfont);
  223.             blue.s2 = token.value.ival;
  224.             bluev[bluec++] = blue;
  225.         }
  226.     }
  227.     bluescale = defbluescale;
  228.     if (dictget(fontprivate, &charname[charbluescale], &token, 0))
  229.     {   if      (token.type == typeint)
  230.             bluescale = token.value.ival;
  231.         else if (token.type == typereal)
  232.             bluescale = token.value.rval;
  233.         else
  234.             error(errinvalidfont);
  235.     }
  236.     blueshift = 7.0;
  237.     if (dictget(fontprivate, &charname[charblueshift], &token, 0))
  238.     {   if      (token.type == typeint)
  239.             blueshift = token.value.ival;
  240.         else if (token.type == typereal)
  241.             blueshift = token.value.rval;
  242.         else
  243.             error(errinvalidfont);
  244.     }
  245.     bluefuzz = 1.0;
  246.     if (dictget(fontprivate, &charname[charbluefuzz], &token, 0))
  247.     {   if      (token.type == typeint)
  248.             bluefuzz = token.value.ival;
  249.         else if (token.type == typereal)
  250.             bluefuzz = token.value.rval;
  251.         else
  252.             error(errinvalidfont);
  253.     }
  254. # ifdef FONTDEBUG
  255.     if (fontdebug & 8)
  256.         fprintf(stderr, "-> BlueScale %6.4f BlueShift %6.4f BlueFuzz %6.4f\n",
  257.                 bluescale, blueshift, bluefuzz);
  258. # endif
  259. }
  260.  
  261. /* Build a character */
  262.  
  263. void buildchar(int schar)
  264. {   struct object token1, token, *aptr;
  265.     struct point width, ll, ur, *ppoint;
  266.     float fdx, fdy;
  267.     int i;
  268.  
  269.     /* If the matrix is not rotated we can apply the hints */
  270.  
  271.     for (i = 0; i < 4; i++)
  272.         if (fabs(gstate.ctm[i]) < .0001) gstate.ctm[i] = 0.0;
  273.     hstform.flag = 0;
  274.     if      (gstate.ctm[0] != 0.0 && gstate.ctm[2] == 0.0)
  275.     {   hstform.flag = -1;
  276.         hstform.scale = gstate.ctm[0];
  277.     }
  278.     else if (gstate.ctm[1] != 0.0 && gstate.ctm[3] == 0.0)
  279.     {   hstform.flag =  1;
  280.         hstform.scale = gstate.ctm[1];
  281.     }
  282.     vstform.flag = 0;
  283.     if      (gstate.ctm[0] == 0.0 && gstate.ctm[2] != 0.0)
  284.     {   vstform.flag = -1;
  285.         vstform.scale = gstate.ctm[2];
  286.     }
  287.     else if (gstate.ctm[1] == 0.0 && gstate.ctm[3] != 0.0)
  288.     {   vstform.flag =  1;
  289.         vstform.scale = gstate.ctm[3];
  290.     }
  291.     setblues();
  292.  
  293.     /* Look up the name in the encoding vector */
  294.  
  295.     if (schar < fontencodlen)
  296.     {   token1 = vmaptr(fontencoding)[schar];
  297.         if (token1.type != typename) error(errinvalidfont);
  298.     }
  299.     else
  300.         token1 = charname[charnotdef];
  301.  
  302.     /* See if there is a metrics entry for this character */
  303.  
  304.     charsbwlength = 0;
  305.     charsbw[0] = charsbw[1] = charsbw[2] = charsbw[3] = 0.0;
  306.     if (fontmetrics != NULL && dictget(fontmetrics, &token1, &token, 0))
  307.     {   if (token.type == typearray)
  308.         {   if (token.length != 2 && token.length != 4)
  309.                 error(errinvalidfont);
  310.             i = token.length;
  311.             aptr = vmaptr(token.value.vref);
  312.         }
  313.         else
  314.         {   i = 1;
  315.             aptr = &token;
  316.         }
  317.         charsbwlength = i;
  318.         for (i = 0; i < charsbwlength; i++)
  319.         {   token = *aptr++;
  320.             if      (token.type == typeint)
  321.                 charsbw[i] = token.value.ival;
  322.             else if (token.type == typereal)
  323.                 charsbw[i] = token.value.rval;
  324.             else
  325.                 error(errinvalidfont);
  326.         }
  327.         if      (charsbwlength == 1)
  328.         {   charsbw[2] = charsbw[0];
  329.             charsbw[0] = 0.0;
  330.         }
  331.         else if (charsbwlength == 2)
  332.         {   charsbw[2] = charsbw[1];
  333.             charsbw[1] = 0.0;
  334.         }
  335.     }
  336.  
  337.     /* Execute the character string */
  338.  
  339.     charnest = charargn = 0;
  340.     charend = charaflag = chardotsection = 0;
  341.     charsdx = charsdy = 0.0;
  342.     charssx = charcpx = 0.0;
  343.     charssy = charcpy = 0.0;
  344.     fdx = gstate.ctm[4];
  345.     fdy = gstate.ctm[5];
  346.     gstate.ctm[4] = 0.0;
  347.     gstate.ctm[5] = 0.0;
  348.     charflexn = -1;
  349.     lastpoint.type = 0;
  350.     hstform.stemc = vstform.stemc = 0;
  351. # ifdef FONTDEBUG
  352.     if (fontdebug & 1)
  353.         fprintf(stderr, "/>%.*s\n",
  354.             vmnptr(token1.value.vref)->length,
  355.             vmnptr(token1.value.vref)->string);
  356. # endif
  357.     if (dictget(fontcharstrings, &token1,               &token, 0) ||
  358.         dictget(fontcharstrings, &charname[charnotdef], &token, 0))
  359.         charstring(&token, 0);
  360.  
  361.     /* Set the character width */
  362.  
  363.     width.type = 0;
  364.     width.x = charsbw[2];
  365.     width.y = charsbw[3];
  366.     dtransform(&width, gstate.ctm);
  367.     istate.pfcrec->width = width;
  368.  
  369.     /* For outlined fonts find the stroke path */
  370.  
  371.     gstate.flatness = 0.2;
  372.     if (fontpainttype != 0)
  373.     {   gstate.linewidth = fontstrokewidth;
  374.         if (istate.type == 1 ||
  375.             istate.type == 2 && gstate.cacheflag ||
  376.             istate.type == 3)
  377.         {   flattenpath();
  378.             strokepath(0);
  379.         }
  380.     }
  381.  
  382.     /* Calculate the bounding box and see if we can use the cache */
  383.  
  384.     if (istate.type >= 2)
  385.     {   i = gstate.pathend - gstate.pathbeg;
  386.         ppoint = &patharray[gstate.pathbeg];
  387.         if (i != 0)
  388.         {   ll = ur = *ppoint;
  389.             while (--i)
  390.             {   ppoint++;
  391.                 if (ppoint->x < ll.x) ll.x = ppoint->x;
  392.                 if (ppoint->x > ur.x) ur.x = ppoint->x;
  393.                 if (ppoint->y < ll.y) ll.y = ppoint->y;
  394.                 if (ppoint->y > ur.y) ur.y = ppoint->y;
  395.             }
  396.         }
  397.         else
  398.         {   ll.type = 0;
  399.             ll.x = 0.0;
  400.             ll.y = 0.0;
  401.             ur = ll;
  402.         }
  403.         setcachedevice(&ll, &ur, 1);
  404.         if (gstate.cacheflag)
  405.         {   fdx = gstate.ctm[4];
  406.             fdy = gstate.ctm[5];
  407.         }
  408.     }
  409.  
  410.     /* Adjust all the path coordinates */
  411.  
  412.     i = gstate.pathend - gstate.pathbeg;
  413.     ppoint = &patharray[gstate.pathbeg];
  414.     while (i--)
  415.     {   ppoint->x += fdx;
  416.         ppoint->y += fdy;
  417.         ppoint++;
  418.     }
  419.  
  420.     /* Fill the path */
  421.  
  422.     if      (istate.type < 2)
  423.         charpath();
  424.     else if (istate.type == 2 && !gstate.cacheflag)
  425.         gstate.pathend = gstate.pathbeg;
  426.     else
  427.     {   closepath(ptclosei);
  428.         if (fontpainttype == 0) flattenpath();
  429.         if (gstate.cacheflag)
  430.             charfill();
  431.         else
  432.         {   setupfill();
  433.             fill(gstate.pathbeg, gstate.pathend, -1);
  434.         }
  435.         gstate.pathend = gstate.pathbeg;
  436.     }
  437. }
  438.  
  439. /* Build an accent or character */
  440.  
  441. void buildachar(int schar)
  442. {   struct object token1, token;
  443.  
  444.     /* Look up the name in the standard encoding vector */
  445.  
  446.     token1 = stdencoding[schar];
  447.     if (token1.type != typename) error(errinvalidfont);
  448.  
  449.     /* Execute the character string */
  450.  
  451.     charnest = 0;
  452.     charend = 0;
  453.     chardotsection = 0;
  454.     charssx = charcpx;
  455.     charssy = charcpy;
  456.     lastpoint.type = 0;
  457.     hstform.stemc = vstform.stemc = 0;
  458. # ifdef FONTDEBUG
  459.     if (fontdebug & 1)
  460.         fprintf(stderr, "/>%.*s\n",
  461.             vmnptr(token1.value.vref)->length,
  462.             vmnptr(token1.value.vref)->string);
  463. # endif
  464.     if (dictget(fontcharstrings, &token1, &token, 0)) charstring(&token, 0);
  465. }
  466.  
  467. /* Interpret a character string */
  468.  
  469. void charstring(struct object *token1, int depth)
  470. {   struct object token;
  471.     struct point point;
  472.     char *sptr;
  473.     float dx1, dy1, dx2, dy2, dx3, dy3, dmin;
  474.     int length, erand, cx, ch, num, i;
  475.     int achar, bchar;
  476.  
  477.     if (token1->type != typestring) error(errinvalidfont);
  478.     length = token1->length;
  479.     if (length == 0) return;
  480.     sptr = vmsptr(token1->value.vref);
  481.  
  482.     /* Skip leading random bytes */
  483.  
  484.     i = fontleniv;
  485.     if (length < i) error(errinvalidfont);
  486.     length -= i;
  487.     erand = einitchar;
  488.     while (i--)
  489.     {   cx = *((unsigned char *) (sptr++));
  490.         erand = ((erand + cx) * ec1 + ec2) & emask;
  491.     }
  492.  
  493.     /* Interpret */
  494.  
  495.     while (length--)
  496.     {   cx = *((unsigned char *) (sptr++));
  497.         ch = cx ^ (erand >> eshift);
  498.         erand = ((erand + cx) * ec1 + ec2) & emask;
  499.  
  500.         /* Operator */
  501.  
  502.         if      (ch < 32)
  503.         {   switch (ch)
  504.             {   case 21:    /* rmoveto */
  505.                     FDEBUGN("rmoveto", 2);
  506.                     if (charnest < 2) error(errinvalidfont);
  507.                     dx1 = charstack[0];
  508.                     dy1 = charstack[1];
  509. rmoveto:            point.type = ptmove;
  510. movline:            point.x = charcpx = charcpx + dx1;
  511.                     point.y = charcpy = charcpy + dy1;
  512.                     if (charflexn < 0) charpoint(&point);
  513.                     charnest = 0;
  514.                     break;
  515.  
  516.                 case 22:    /* hmoveto */
  517.                     FDEBUGN("hmoveto", 1);
  518.                     if (charnest < 1) error(errinvalidfont);
  519.                     dx1 = charstack[0];
  520.                     dy1 = 0.0;
  521.                     goto rmoveto;
  522.  
  523.                 case  4:    /* vmoveto */
  524.                     FDEBUGN("vmoveto", 1);
  525.                     if (charnest < 1) error(errinvalidfont);
  526.                     dx1 = 0.0;
  527.                     dy1 = charstack[0];
  528.                     goto rmoveto;
  529.  
  530.                 case  5:    /* rlineto */
  531.                     FDEBUGN("rlineto", 2);
  532.                     if (charnest < 2) error(errinvalidfont);
  533.                     dx1 = charstack[0];
  534.                     dy1 = charstack[1];
  535. rlineto:            point.type = ptline;
  536.                     if (gstate.pathbeg == gstate.pathend)
  537.                         error(errinvalidfont);
  538.                     goto movline;
  539.  
  540.                 case  6:    /* hlineto */
  541.                     FDEBUGN("hlineto", 1);
  542.                     if (charnest < 1) error(errinvalidfont);
  543.                     dx1 = charstack[0];
  544.                     dy1 = 0.0;
  545.                     goto rlineto;
  546.  
  547.                 case  7:    /* vlineto */
  548.                     FDEBUGN("vlineto", 1);
  549.                     if (charnest < 1) error(errinvalidfont);
  550.                     dx1 = 0.0;
  551.                     dy1 = charstack[0];
  552.                     goto rlineto;
  553.  
  554.                 case  8:    /* rrcurveto */
  555.                     FDEBUGN("rrcurveto", 6);
  556.                     if (charnest < 6) error(errinvalidfont);
  557.                     dx1 = charstack[0];
  558.                     dy1 = charstack[1];
  559.                     dx2 = charstack[2];
  560.                     dy2 = charstack[3];
  561.                     dx3 = charstack[4];
  562.                     dy3 = charstack[5];
  563. rrcurveto:          point.type = ptcurve;
  564.                     if (gstate.pathbeg == gstate.pathend)
  565.                         error(errinvalidfont);
  566.                     point.x = charcpx + dx1;
  567.                     point.y = charcpy + dy1;
  568.                     charpoint(&point);
  569.                     point.x += dx2;
  570.                     point.y += dy2;
  571.                     charpoint(&point);
  572.                     charcpx = point.x = point.x + dx3;
  573.                     charcpy = point.y = point.y + dy3;
  574.                     charpoint(&point);
  575.                     charnest = 0;
  576.                     break;
  577.  
  578.                 case 30:    /* vhcurveto */
  579.                     FDEBUGN("vhcurveto", 4);
  580.                     if (charnest < 4) error(errinvalidfont);
  581.                     dx1 = 0.0;
  582.                     dy1 = charstack[0];
  583.                     dx2 = charstack[1];
  584.                     dy2 = charstack[2];
  585.                     dx3 = charstack[3];
  586.                     dy3 = 0.0;
  587.                     goto rrcurveto;
  588.  
  589.                 case 31:    /* hvcurveto */
  590.                     FDEBUGN("hvcurveto", 4);
  591.                     if (charnest < 4) error(errinvalidfont);
  592.                     dx1 = charstack[0];
  593.                     dy1 = 0.0;
  594.                     dx2 = charstack[1];
  595.                     dy2 = charstack[2];
  596.                     dx3 = 0.0;
  597.                     dy3 = charstack[3];
  598.                     goto rrcurveto;
  599.  
  600.                 case  9:    /* closepath */
  601.                     FDEBUGN("closepath", 0);
  602.                     closepath(ptclosex);
  603.                     charnest = 0;
  604.                     break;
  605.  
  606.                 case 10:    /* callsubr */
  607.                     FDEBUGN("callsubr", charnest);
  608.                     if (charnest < 1) error(errinvalidfont);
  609.                     i = itrunc(charstack[charnest - 1]);
  610.                     if (i < 0 || i > fontsubrs.length) error(errinvalidfont);
  611.                     charnest--;
  612.                     token = vmaptr(fontsubrs.value.vref)[i];
  613.                     if (depth + 1 == charmaxdepth) error(errinvalidfont);
  614.                     charstring(&token, depth + 1);
  615.                     break;
  616.  
  617.                 case 11:    /* return */
  618.                     FDEBUGN("return", 0);
  619.                     if (depth == 0) error(errinvalidfont);
  620.                     return;
  621.  
  622.                 case 14:    /* endchar */
  623.                     FDEBUGN("endchar", 0);
  624.                     charnest = 0;
  625.                     charend = 1;
  626.                     break;
  627.  
  628.                 case 13:    /* hsbw */
  629.                     FDEBUGN("hsbw", 2);
  630.                     if (charnest < 2) error(errinvalidfont);
  631.                     dx1 = charstack[0];
  632.                     dy1 = 0.0;
  633.                     dx2 = charstack[1];
  634.                     dy2 = 0.0;
  635. sbw:                if      (charaflag == 1)
  636.                     {   charcpx = dx1 + charsdx;
  637.                         charcpy = dy1 + charsdy;
  638.                         charadx += charcpx;
  639.                         charady += charcpy;
  640.                     }
  641.                     else if (charaflag == 2)
  642.                     {   charcpx = charadx;
  643.                         charcpy = charady;
  644.                     }
  645.                     else
  646.                     {   if      (charsbwlength == 0)
  647.                         {   charsbw[0] = dx1;
  648.                             charsbw[1] = dy1;
  649.                             charsbw[2] = dx2;
  650.                             charsbw[3] = dy2;
  651.                         }
  652.                         else if (charsbwlength == 1)
  653.                         {   charsbw[0] = dx1;
  654.                             charsbw[1] = dy1;
  655.                         }
  656.                         charcpx = charsbw[0];
  657.                         charcpy = charsbw[1];
  658.                         charsdx = charcpx - dx1;
  659.                         charsdy = charcpy - dy1;
  660.                     }
  661.                     charssx = charcpx;
  662.                     charssy = charcpy;
  663.                     charnest = 0;
  664.                     break;
  665.  
  666.                 case  1:    /* hstem */
  667.                     FDEBUGN("hstem", 2);
  668.                     if (charnest < 2) error(errinvalidfont);
  669.                     dy1 = charssy + charstack[0];
  670.                     dy2 = dy1 + charstack[1];
  671.                     if (dy1 > dy2)
  672.                     {   dy3 = dy1;
  673.                         dy1 = dy2;
  674.                         dy2 = dy3;
  675.                     }
  676.                     if (vstform.stemc < maxstem)
  677.                     {   vstform.stemv[vstform.stemc].s1 = dy1;
  678.                         vstform.stemv[vstform.stemc].s2 = dy2;
  679.                         setstems(&vstform, 1);
  680.                     }
  681.                     charnest = 0;
  682.                     break;
  683.  
  684.                 case  3:    /* vstem */
  685.                     FDEBUGN("vstem", 2);
  686.                     if (charnest < 2) error(errinvalidfont);
  687.                     dx1 = charssx + charstack[0];
  688.                     dx2 = dx1 + charstack[1];
  689.                     if (dx1 > dx2)
  690.                     {   dx3 = dx1;
  691.                         dx1 = dx2;
  692.                         dx2 = dx3;
  693.                     }
  694.                     if (hstform.stemc < maxstem)
  695.                     {   hstform.stemv[hstform.stemc].s1 = dx1;
  696.                         hstform.stemv[hstform.stemc].s2 = dx2;
  697.                         setstems(&hstform, 1);
  698.                     }
  699.                     charnest = 0;
  700.                     break;
  701.  
  702.                 case 15:    /* moveto  +++ UNDOCUMENTED, OBSOLETE +++ */
  703.                     FDEBUGN("MOVETO", 2);
  704.                     if (charnest < 2) error(errinvalidfont);
  705.                     dx1 = charstack[0] + charssx - charcpx;
  706.                     dy1 = charstack[1] + charssy - charcpy;
  707.                     goto rmoveto;
  708.  
  709.                 case 16:    /* lineto  +++ UNDOCUMENTED, OBSOLETE +++ */
  710.                     FDEBUGN("LINETO", 2);
  711.                     if (charnest < 2) error(errinvalidfont);
  712.                     dx1 = charstack[0] + charssx - charcpx;
  713.                     dy1 = charstack[1] + charssy - charcpy;
  714.                     goto rlineto;
  715.  
  716.                 case 17:    /* curveto +++ UNDOCUMENTED, OBSOLETE +++ */
  717.                     FDEBUGN("CURVETO", 6);
  718.                     if (charnest < 6) error(errinvalidfont);
  719.                     dx1 = charstack[0] + charssx - charcpx;
  720.                     dy1 = charstack[1] + charssy - charcpy;
  721.                     dx2 = charstack[2] + charssx - charcpx;
  722.                     dy2 = charstack[3] + charssy - charcpy;
  723.                     dx3 = charstack[4] + charssx - charcpx;
  724.                     dy3 = charstack[5] + charssy - charcpy;
  725.                     goto rrcurveto;
  726.  
  727.                 case 12:    /* ... */
  728.                     if (length == 0) error(errinvalidfont);
  729.                     length--;
  730.                     cx = *((unsigned char *) (sptr++));
  731.                     ch = cx ^ (erand >> eshift);
  732.                     erand = ((erand + cx) * ec1 + ec2) & emask;
  733.                     switch (ch)
  734.                     {   case  0:    /* dotsection */
  735.                             FDEBUGN("dotsection", 0);
  736.                             chardotsection = !chardotsection;
  737.                             charnest = 0;
  738.                             break;
  739.  
  740.                         case  1:    /* vstem3 */
  741.                             FDEBUGN("vstem3", 6);
  742.                             if (charnest < 6) error(errinvalidfont);
  743.                             hstform.stemc = 0;
  744.                             hstform.stemv[0].s1 =
  745.                                 charssx + charstack[0];
  746.                             hstform.stemv[0].s2 =
  747.                                 charssx + charstack[0] + charstack[1];
  748.                             hstform.stemv[1].s1 =
  749.                                 charssx + charstack[2];
  750.                             hstform.stemv[1].s2 =
  751.                                 charssx + charstack[2] + charstack[3];
  752.                             hstform.stemv[2].s1 =
  753.                                 charssx + charstack[4];
  754.                             hstform.stemv[2].s2 =
  755.                                 charssx + charstack[4] + charstack[5];
  756.                             setstems(&hstform, 3);
  757.                             charnest = 0;
  758.                             break;
  759.  
  760.                         case  2:    /* hstem3 */
  761.                             FDEBUGN("hstem3", 6);
  762.                             if (charnest < 6) error(errinvalidfont);
  763.                             vstform.stemc = 0;
  764.                             vstform.stemv[0].s1 =
  765.                                 charssy + charstack[0];
  766.                             vstform.stemv[0].s2 =
  767.                                 charssy + charstack[0] + charstack[1];
  768.                             vstform.stemv[1].s1 =
  769.                                 charssy + charstack[2];
  770.                             vstform.stemv[1].s2 =
  771.                                 charssy + charstack[2] + charstack[3];
  772.                             vstform.stemv[2].s1 =
  773.                                 charssy + charstack[4];
  774.                             vstform.stemv[2].s2 =
  775.                                 charssy + charstack[4] + charstack[5];
  776.                             setstems(&vstform, 3);
  777.                             charnest = 0;
  778.                             break;
  779.  
  780.                         case  6:    /* seac */
  781.                             FDEBUGN("seac", 5);
  782.                             if (charnest < 5) error(errinvalidfont);
  783.                             bchar = itrunc(charstack[3]);
  784.                             achar = itrunc(charstack[4]);
  785.                             if (charaflag) error(errinvalidfont);
  786.                             charadx = charstack[1];
  787.                             charady = charstack[2];
  788.                             charaflag = 1;
  789.                             charcpx = 0.0;
  790.                             charcpy = 0.0;
  791.                             buildachar(bchar);
  792.                             charaflag = 2;
  793.                             charcpx = charadx;
  794.                             charcpy = charady;
  795.                             buildachar(achar);
  796.                             charnest = 0;
  797.                             charend = 1;
  798.                             break;
  799.  
  800.                         case  7:    /* sbw */
  801.                             FDEBUGN("sbw", 4);
  802.                             if (charnest < 4) error(errinvalidfont);
  803.                             dx1 = charstack[0];
  804.                             dy1 = charstack[1];
  805.                             dx2 = charstack[2];
  806.                             dy2 = charstack[3];
  807.                             goto sbw;
  808.  
  809.                         case 12:    /* div */
  810.                             FDEBUGN("div", charnest);
  811.                             if (charnest < 2) error(errinvalidfont);
  812.                             charstack[charnest - 2] /=
  813.                                     charstack[charnest - 1];
  814.                             charnest--;
  815.                             break;
  816.  
  817.                         case 16:    /* callothersubr */
  818.                             FDEBUGN("callothersubr", charnest);
  819.                             if (charnest < 2) error(errinvalidfont);
  820.                             i = itrunc(charstack[charnest - 1]);
  821.                             num = itrunc(charstack[charnest - 2]);
  822.                             charnest -= 2;
  823.                             if (num < 0 || num > charnest)
  824.                                 error(errinvalidfont);
  825.                             charargn = 0;
  826.                             while (num--)
  827.                                 charargs[charargn++] = charstack[--charnest];
  828.                             switch (i)
  829.                             {   case 0: /* Flex */
  830.                                     if (charargn != 3)
  831.                                         error(errinvalidfont);
  832.                                     dmin = fabs(charargs[2]) / 100.0;
  833.                                     charargn--;
  834.                                     if (charflexn != 7)
  835.                                         error(errinvalidfont);
  836.                                     charflexn = -1;
  837.                                     point.x = charfptx[3] - charfptx[0];
  838.                                     point.y = charfpty[3] - charfpty[0];
  839.                                     if
  840.                             (fabs(charfptx[3] - charcpx) > 20.0 &&
  841.                              fabs(charfpty[3] - charcpy) > 20.0)
  842.                                         goto flexc;
  843.                                     if
  844.                             (fabs(charfptx[3] - charfptx[6]) > 20.0 &&
  845.                              fabs(charfpty[3] - charfpty[6]) > 20.0)
  846.                                         goto flexc;
  847.                                     dtransform(&point, gstate.ctm);
  848.                                     point.x = fabs(point.x);
  849.                                     point.y = fabs(point.y);
  850.                                     if ((point.x < .01 && point.y < dmin) ||
  851.                                         (point.y < .01 && point.x < dmin))
  852.                                     {   point.type = ptline;
  853.                                         point.x = charfptx[6];
  854.                                         point.y = charfpty[6];
  855.                                         charpoint(&point);
  856.                                         break;
  857.                                     }
  858. flexc:                              point.type = ptcurve;
  859.                                     for (i = 1; i < 7; i++)
  860.                                     {   point.x = charfptx[i];
  861.                                         point.y = charfpty[i];
  862.                                         charpoint(&point);
  863.                                     }
  864.                                     break;
  865.  
  866.                                 case 1: /* Flex */
  867.                                     if (charargn != 0)
  868.                                         error(errinvalidfont);
  869.                                     if (charflexn >= 0)
  870.                                         error(errinvalidfont);
  871.                                     charflexn = 0;
  872.                                     break;
  873.  
  874.                                 case 2: /* Flex */
  875.                                     if (charargn != 0)
  876.                                         error(errinvalidfont);
  877.                                     if (charflexn > 6)
  878.                                         error(errinvalidfont);
  879.                                     charfptx[charflexn] = charcpx;
  880.                                     charfpty[charflexn] = charcpy;
  881.                                     charflexn++;
  882.                                     break;
  883.  
  884.                                 case 3: /* Hint replacement */
  885.                                     hstform.stemc = vstform.stemc = 0;
  886.                                     break;
  887.                             }
  888.                             break;
  889.  
  890.                         case 17:    /* pop */
  891.                             FDEBUGN("pop", 0);
  892.                             if (charnest == charstacksize || charargn == 0)
  893.                                 error(errinvalidfont);
  894.                             charstack[charnest++] = charargs[--charargn];
  895.                             break;
  896.  
  897.                         case 32:    /* pushcurrentpoint */
  898.                                     /*     +++ UNDOCUMENTED, OBSOLETE +++ */
  899.                             FDEBUGN("PUSHCURRENTPOINT", 0);
  900.                             if (charnest + 2 > charstacksize)
  901.                                 error(errinvalidfont);
  902.                             charstack[charnest++] = charcpx;
  903.                             charstack[charnest++] = charcpy;
  904.                             break;
  905.  
  906.                         case 33:    /* setcurrentpoint */
  907.                             FDEBUGN("setcurrentpoint", 2);
  908.                             if (charnest < 2) error(errinvalidfont);
  909.                             charcpx = charstack[0];
  910.                             charcpy = charstack[1];
  911.                             charnest = 0;
  912.                             break;
  913.  
  914.                         default:
  915.                             error(errinvalidfont);
  916.                     }
  917.                     break;
  918.  
  919.                 default:
  920.                     error(errinvalidfont);
  921.  
  922.             }
  923.             if (charend) return;
  924.         }
  925.  
  926.         /* Number */
  927.  
  928.         else
  929.         {   if      (ch < 247)
  930.                 num = ch - 139;
  931.             else if (ch == 255)
  932.             {   if (length < 4) error(errinvalidfont);
  933.                 length -= 4;
  934.                 num = 0;
  935.                 i = 4;
  936.                 while (i--)
  937.                 {   cx = *((unsigned char *) (sptr++));
  938.                     ch = cx ^ (erand >> eshift);
  939.                     erand = ((erand + cx) * ec1 + ec2) & emask;
  940.                     num = (num << 8) | ch;
  941.                 }
  942.             }
  943.             else
  944.             {   if (length == 0) error(errinvalidfont);
  945.                 length--;
  946.                 num = ch;
  947.                 cx = *((unsigned char *) (sptr++));
  948.                 ch = cx ^ (erand >> eshift);
  949.                 erand = ((erand + cx) * ec1 + ec2) & emask;
  950.                 if (num < 251)
  951.                     num =   (num - 247) * 256 + ch + 108;
  952.                 else
  953.                     num = -((num - 251) * 256 + ch + 108);
  954.             }
  955.             if (charnest == charstacksize) error(errinvalidfont);
  956.             charstack[charnest++] = num;
  957.         }
  958.     }
  959. }
  960.  
  961. /* Add a point to the character path */
  962.  
  963. void charpoint(struct point *ppoint)
  964. {   struct point point;
  965.  
  966.     /* Transform to device space, rounding to multiples of 1/16 */
  967.  
  968.     point = *ppoint;
  969.     dtransform(&point, gstate.ctm);
  970.     point.x = floor(point.x * 16.0 + 0.5) / 16.0;
  971.     point.y = floor(point.y * 16.0 + 0.5) / 16.0;
  972.  
  973. # ifdef FONTDEBUG
  974.     if (fontdebug & 2)
  975.         fprintf(stderr, ".> (%4.0f,%4.0f) [%7.2f,%7.2f]\n",
  976.                 ppoint->x, ppoint->y, point.x, point.y);
  977. # endif
  978.  
  979.     /* For moves, the hinting is deferred, in case the hints have changed */
  980.  
  981.     if (lastpoint.type == ptmove)
  982.         hintpoint(&lastpoint, &patharray[gstate.pathend - 1]);
  983.     lastpoint = *ppoint;
  984.  
  985.     /* Add the point to the path */
  986.  
  987.     if (point.type == ptmove)
  988.     {   closepath(ptclosei);
  989.         if (gstate.pathbeg != gstate.pathend &&
  990.             patharray[gstate.pathend - 1].type == ptmove)
  991.             gstate.pathend--;
  992.     }
  993.     checkpathsize(gstate.pathend + 1);
  994.     patharray[gstate.pathend++] = point;
  995.  
  996.     /* For points other than a move, the hinting is done immediately */
  997.  
  998.     if (lastpoint.type != ptmove)
  999.         hintpoint(&lastpoint, &patharray[gstate.pathend - 1]);
  1000. }
  1001.  
  1002. /* Adjust the coordinates of a point according to the hints */
  1003.  
  1004. void hintpoint(struct point *cpoint, struct point *ppoint)
  1005. {   if      (hstform.flag < 0)
  1006.         hintadjust(&cpoint->x, &ppoint->x, &hstform);
  1007.     else if (hstform.flag > 0)
  1008.         hintadjust(&cpoint->x, &ppoint->y, &hstform);
  1009.     if      (vstform.flag < 0)
  1010.         hintadjust(&cpoint->y, &ppoint->x, &vstform);
  1011.     else if (vstform.flag > 0)
  1012.         hintadjust(&cpoint->y, &ppoint->y, &vstform);
  1013. }
  1014.  
  1015. /* Adjust a single coordinate according to the hints */
  1016.  
  1017. void hintadjust(float *ps, float *pz, struct stform *pstform)
  1018. {   struct stem *stem1, *stem2, *pstem, *pblue;
  1019.     float ss, zz, f, d;
  1020.     int i;
  1021.  
  1022.     if (chardotsection) return;
  1023.  
  1024.     /* Locate it relative to the stems.  Loop to find the highest stem not
  1025.      * above us and the lowest not below us.  Then we can work out where
  1026.      * we are */
  1027.  
  1028.     stem1 = stem2 = NULL;
  1029.     ss = *ps;
  1030.     pstem = &pstform->stemv[0];
  1031.     i = pstform->stemc;
  1032.  
  1033.     while (i--)
  1034.     {   if (pstem->s1 <= ss)
  1035.             if (stem1 == NULL || pstem->s1 > stem1->s1) stem1 = pstem;
  1036.         if (pstem->s2 >= ss)
  1037.             if (stem2 == NULL || pstem->s2 < stem2->s2) stem2 = pstem;
  1038.         pstem++;
  1039.     }
  1040.  
  1041.     /* If it is not within a stem, see if it is within an alignment zone */
  1042.  
  1043.     if (stem1 == NULL || stem2 == NULL)
  1044.         if (pstform == &vstform)
  1045.         {   pblue = bluev;
  1046.             i = bluec;
  1047.             while (i--)
  1048.                 if (ss >= pblue->s1 - bluefuzz && ss <= pblue->s2 + bluefuzz)
  1049.                 {   f = fabs(pstform->scale);
  1050.                     if (pblue->type < 0)
  1051.                     {   d = pblue->s2 - ss;
  1052.                         zz = pblue->z2;
  1053.                     }
  1054.                     else
  1055.                     {   d = ss - pblue->s1;
  1056.                         zz = pblue->z1;
  1057.                     }
  1058.                     if (f < bluescale || (d < blueshift && d * f < 0.5))
  1059.                         goto hint;
  1060.                 }
  1061.         }
  1062.  
  1063.     /* No stems */
  1064.  
  1065.     if (stem1 == NULL && stem2 == NULL) return;
  1066.  
  1067.     /* Above all stems */
  1068.  
  1069.     if (stem1 == NULL)
  1070.     {   zz = stem2->z2 + (ss - stem2->s2) * pstform->scale;
  1071.         goto hint;
  1072.     }
  1073.  
  1074.     /* Below all stems */
  1075.  
  1076.     if (stem2 == NULL)
  1077.     {   zz = stem1->z1 + (ss - stem1->s1) * pstform->scale;
  1078.         goto hint;
  1079.     }
  1080.  
  1081.     /* In case we have averlapping stems */
  1082.  
  1083.     if (stem2->s1 == stem1->s2) return;
  1084.  
  1085.     /* Between two stems */
  1086.  
  1087.     if (stem1 != stem2)
  1088.     {   zz = stem1->z2 +
  1089.                  (ss - stem1->s2) *
  1090.                  (stem2->z1 - stem1->z2) /
  1091.                  (stem2->s1 - stem1->s2);
  1092.         goto hint;
  1093.     }
  1094.  
  1095.     /* At the bottom of a stem */
  1096.  
  1097.     if (stem1->s1 == ss)
  1098.     {   zz = stem1->z1;
  1099.         goto hint;
  1100.     }
  1101.  
  1102.     /* At the top of a stem */
  1103.  
  1104.     if (stem1->s2 == ss)
  1105.     {   zz = stem1->z2;
  1106.         goto hint;
  1107.     }
  1108.  
  1109.     /* Within a stem */
  1110.  
  1111.     zz = stem1->z1 +
  1112.              (ss - stem1->s1) *
  1113.              (stem1->z2 - stem1->z1) /
  1114.              (stem1->s2 - stem1->s1);
  1115.  
  1116. hint:
  1117.     zz = floor(zz * 16.0 + 0.5) / 16.0;
  1118.  
  1119. # ifdef FONTDEBUG
  1120.     if (fontdebug & 4)
  1121.         fprintf(stderr, "=> Hint %c  %6.2f -> %6.2f\n",
  1122.                 (pstform == &hstform ? 'X' : 'Y'), *pz, zz);
  1123. # endif
  1124.  
  1125.     *pz = zz;
  1126. }
  1127.  
  1128. /* Set the coordinates of the stems */
  1129.  
  1130. void setstems(struct stform *pstform, int num)
  1131. {   struct stem *pstem, *pblue;
  1132.     float scale, w1, w2, z1, z2, zz, w, f, d;
  1133.     int iw, i;
  1134.  
  1135.     if (pstform->flag == 0) return;
  1136.  
  1137.     scale = pstform->scale;
  1138.     pstem = &pstform->stemv[pstform->stemc];
  1139.     pstform->stemc += num;
  1140.  
  1141.     while (num--)
  1142.     {
  1143.  
  1144.         /* Regularise the width.  Don't adjust very small widths */
  1145.  
  1146.         z1 = pstem->s1 * scale;
  1147.         z2 = pstem->s2 * scale;
  1148.         w1 = fabs(z2 - z1);
  1149.         if (w1 < 0.5)
  1150.         {  w2 = 0.75;
  1151.            iw = 1;
  1152.         }
  1153.         else
  1154.         {  w2 = floor(w1 + 0.5);
  1155.            iw = w2;
  1156.            w2 -= 0.25;
  1157.         }
  1158.         if (z1 < z2)
  1159.             w =  w2;
  1160.         else
  1161.             w = -w2;
  1162.  
  1163.         /* If a stem is not subject to alignment, odd widths are centred
  1164.          * on 0.4375 pixels, even widths on 0.9365 pixels. */
  1165.  
  1166.         if (w2 > 0.5)
  1167.         {   zz = (z1 + z2) / 2.0;
  1168.             if (iw & 1)
  1169.                 zz = floor(zz + 0.0625) + 0.4375;
  1170.             else
  1171.                 zz = floor(zz + 0.5625) - 0.0625;
  1172.             z1 = zz - w / 2.0;
  1173.             z2 = zz + w / 2.0;
  1174.         }
  1175.  
  1176.         /* See if the stem is within an alignment zone.  If it is within
  1177.          * bluefuzz of exact alignment then align it.  If it is within the
  1178.          * alignment zone than align it if our scale is less than bluescale
  1179.          * or the distance is less than blueshift and less than half a pixel;
  1180.          * otherwise position relative to the alignment.  If the stem is
  1181.          * outside the alignment zone make sure it remains so
  1182.          */
  1183.  
  1184.         if (pstform == &vstform)
  1185.         {   pblue = bluev;
  1186.             i = bluec;
  1187.             while (i--)
  1188.             {   if (pblue->type < 0)
  1189.                 {   if (fabs(pstem->s1 - pblue->s2) <= bluefuzz)
  1190.                     {   z1 = pblue->z2;
  1191.                         z2 = z1 + w;
  1192.                         break;
  1193.                     }
  1194.                     if (pstem->s1 < pblue->s2 &&
  1195.                         pstem->s1 >= pblue->s1 - bluefuzz)
  1196.                     {   z1 = pblue->z2;
  1197.                         f = fabs(scale);
  1198.                         d = pblue->s2 - pstem->s1;
  1199.                         if (!(f < bluescale ||
  1200.                               (d < blueshift && d * f < 0.5)))
  1201.                             z1 -= floor(d * scale * 16.0 + 0.5) / 16.0;
  1202.                         z2 = z1 + w;
  1203.                         break;
  1204.                     }
  1205.                     if (pstem->s1 > pblue->s2)
  1206.                         if (scale < 0 ? (z1 > pblue->z2) : (z1 < pblue->z2))
  1207.                         {   z1 = pblue->z2;
  1208.                             z2 = z1 + w;
  1209.                         }
  1210.                 }
  1211.                 else
  1212.                 {   if (fabs(pstem->s2 - pblue->s1) <= bluefuzz)
  1213.                     {   z2 = pblue->z1;
  1214.                         z1 = z2 - w;
  1215.                         break;
  1216.                     }
  1217.                     if (pstem->s2 > pblue->s1 &&
  1218.                         pstem->s2 <= pblue->s2 + bluefuzz)
  1219.                     {   z2 = pblue->z1;
  1220.                         f = fabs(scale);
  1221.                         d = pstem->s2 - pblue->s1;
  1222.                         if (!(f < bluescale ||
  1223.                               (d < blueshift && d * f < 0.5)))
  1224.                             z2 += floor(d * scale * 16.0 + 0.5) / 16.0;
  1225.                         z1 = z2 - w;
  1226.                         break;
  1227.                     }
  1228.                     if (pstem->s2 < pblue->s1)
  1229.                         if (scale < 0 ? (z2 < pblue->z1) : (z2 > pblue->z1))
  1230.                         {   z2 = pblue->z1;
  1231.                             z1 = z2 - w;
  1232.                         }
  1233.                 }
  1234.                 pblue++;
  1235.             }
  1236.         }
  1237.  
  1238.         pstem->z1 = z1;
  1239.         pstem->z2 = z2;
  1240.  
  1241. # ifdef FONTDEBUG
  1242.         if (fontdebug & 4)
  1243.             fprintf(stderr, "=> Stem %c [%7.2f, %7.2f] -> [%6.2f, %6.2f]\n",
  1244.                     (pstform == &vstform ? 'H' : 'V'),
  1245.                     pstem->s1, pstem->s2, z1, z2);
  1246. # endif
  1247.  
  1248.         pstem++;
  1249.     }
  1250. }
  1251.  
  1252. /* Set the coordinates of the blues */
  1253.  
  1254. void setblues(void)
  1255. {   struct stem *pblue;
  1256.     float zz;
  1257.     int i;
  1258.  
  1259.     if (vstform.flag == 0) return;
  1260.  
  1261.     pblue = bluev;
  1262.     i = bluec;
  1263.     while (i--)
  1264.     {
  1265.         /* Bottom zones are aligned at 0.0625, top zones at 0.9375 */
  1266.  
  1267.         if (pblue->type < 0)
  1268.         {   zz = pblue->s2 * vstform.scale;
  1269.             if (vstform.scale < 0.0)
  1270.                 zz = floor(zz - 0.4375) + 0.9375;
  1271.             else
  1272.                 zz = floor(zz + 0.4375) + 0.0625;
  1273.         }
  1274.         else
  1275.         {   zz = pblue->s1 * vstform.scale;
  1276.             if (vstform.scale < 0.0)
  1277.                 zz = floor(zz + 0.4375) + 0.0625;
  1278.             else
  1279.                 zz = floor(zz - 0.4375) + 0.9375;
  1280.         }
  1281.  
  1282.         pblue->z1 = pblue->z2 = zz;
  1283.  
  1284. # ifdef FONTDEBUG
  1285.         if (fontdebug & 8)
  1286.             fprintf(stderr, "=> Blue %c [%7.2f, %7.2f] -> %6.2f\n",
  1287.                     (pblue->type < 0 ? '-' : '+'),
  1288.                     pblue->s1, pblue->s2, zz);
  1289. # endif
  1290.  
  1291.         pblue++;
  1292.     }
  1293. }
  1294.  
  1295. /* Bit packing tables to compress to one bit per pixel without dropouts */
  1296.  
  1297. static unsigned char ctbl[256] = /* Bit(s) in center (not edges) */
  1298. {   0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 00 */
  1299.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 10 */
  1300.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 20 */
  1301.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 30 */
  1302.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 40 */
  1303.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 50 */
  1304.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 60 */
  1305.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 70 */
  1306.     0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 */
  1307.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 */
  1308.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a0 */
  1309.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b0 */
  1310.     0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* c0 */
  1311.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* d0 */
  1312.     0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* e0 */
  1313.     0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1  /* f0 */
  1314. };
  1315.  
  1316. static unsigned char ltbl[256] = /* Number of bits at left */
  1317. {   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */
  1318.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */
  1319.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 */
  1320.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 30 */
  1321.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 40 */
  1322.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 50 */
  1323.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 60 */
  1324.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 70 */
  1325.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80 */
  1326.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 90 */
  1327.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* a0 */
  1328.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* b0 */
  1329.     2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* c0 */
  1330.     0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* d0 */
  1331.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* e0 */
  1332.     4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8  /* f0 */
  1333. };
  1334.  
  1335. static unsigned char rtbl[256] = /* Number of bits at right */
  1336. {   0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 00 */
  1337.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 10 */
  1338.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 20 */
  1339.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, /* 30 */
  1340.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 40 */
  1341.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 50 */
  1342.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 60 */
  1343.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, /* 70 */
  1344.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* 80 */
  1345.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* 90 */
  1346.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* a0 */
  1347.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, /* b0 */
  1348.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* c0 */
  1349.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, /* d0 */
  1350.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, /* e0 */
  1351.     0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 8  /* f0 */
  1352. };
  1353.  
  1354. /* Fill a character path, no clipping needed */
  1355.  
  1356. void charfill(void)
  1357. {   struct point *ppoint;
  1358.     struct line *pline, **ppline;
  1359.     char *pptr, *pptr1;         /* device buffer pointers */
  1360.     char *xptr1, *xptr2;        /* x buffer pointers */
  1361.     int count;                  /* counter */
  1362.     int active, discard, sort;  /* lines active, to be discarded, sorted */
  1363.     int yy;                     /* current y coordinate */
  1364.     int x1, x2, xp, xx;         /* current, previous x position range */
  1365.     int fdir;                   /* fill direction counter */
  1366.     int mask1, mask2;           /* bit masks for first and last bytes */
  1367.     int s0, s1, s2;             /* segment to draw */
  1368.  
  1369.     /* Set up the fill lines and y buckets.  Set up the x buffer */
  1370.  
  1371.     lineend = 0;
  1372.     count = gstate.pathend - gstate.pathbeg;
  1373.     ppoint = &patharray[gstate.pathbeg];
  1374.     while (count--)
  1375.     {   if (ppoint->type != ptmove) charline(ppoint - 1);
  1376.         ppoint++;
  1377.     }
  1378.     setybucket(0, gstate.dev.ysize * 8);
  1379.     setxbuf(gstate.dev.xsize);
  1380.     memset((char *) xshf, 0, gstate.dev.xsize * sizeof (int));
  1381.  
  1382.     /* Fill the area.  Start at the lowest scan line in the path and loop
  1383.      * until we reach the highest, rendering 8 bits per pixel in each
  1384.      * direction.  Eight bits per pixel horizontally */
  1385.  
  1386.     active = discard = sort = 0;
  1387.     yy = 0;
  1388.     pptr = gstate.dev.buf[0];
  1389.  
  1390.     while (yy < gstate.dev.ysize * 8 + 8)
  1391.     {   memset(xbuf, 0, gstate.dev.xsize);
  1392.  
  1393. if (yy >= gstate.dev.ysize * 8) goto lll;
  1394.  
  1395.         /* Add all the new lines */
  1396.  
  1397.         pline = ybucket[yy];
  1398.         ybucket[yy] = NULL;
  1399.         while (pline)
  1400.         {   lineptr[active++] = pline;
  1401.             pline = pline->chain;
  1402.             sort++;
  1403.         }
  1404.  
  1405.         /* If we have any lines out of order sort them */
  1406.  
  1407.         sort += discard;
  1408.         if (sort != 0)
  1409.         {   count = active;
  1410.             for (;;)
  1411.             {   count = count / 3 + 1;
  1412.                 for (x1 = count; x1 < active; x1++)
  1413.                     for (x2 = x1 - count;
  1414.                          x2 >= 0 &&
  1415.                              lineptr[x2]->xx > lineptr[x2 + count]->xx;
  1416.                          x2 -= count)
  1417.                     {   pline = lineptr[x2];
  1418.                         lineptr[x2] = lineptr[x2 + count];
  1419.                         lineptr[x2 + count] = pline;
  1420.                     }
  1421.                 if (count == 1) break;
  1422.             }
  1423.             active -= discard;
  1424.             discard = sort = 0;
  1425.         }
  1426.  
  1427.         /* Scan convert the scan line */
  1428.  
  1429.         count = active;
  1430.         fdir = 0;
  1431.         ppline = &lineptr[0];
  1432.         xp = -32767;
  1433.  
  1434.         while (count--)
  1435.         {   pline = *ppline++;
  1436.             x1 = pline->xx >> 16;
  1437.  
  1438.             /* At the end of the line draw only its width */
  1439.  
  1440.             if (yy == pline->y2)
  1441.             {   pline->xx += pline->d2;
  1442.                 x2 = pline->xx >> 16;
  1443.                 pline->xx = 0x7fffffff;
  1444.                 discard++;
  1445.                 if (x2 < x1)
  1446.                 {   xx = x1;
  1447.                     x1 = x2;
  1448.                     x2 = xx;
  1449.                 }
  1450.                 if (fdir == 0)
  1451.                 {   s1 = x1;
  1452.                     s2 = x2;
  1453.                 }
  1454.                 else
  1455.                 {   if (x1 < s1) s1 = x1;
  1456.                     if (x2 > s2) s2 = x2;
  1457.                     continue;
  1458.                 }
  1459.             }
  1460.  
  1461.             /* Otherwise draw both the widths and the area enclosed */
  1462.  
  1463.             else
  1464.             {   if      (yy == pline->y1)
  1465.                     pline->xx += pline->d1;  /* Beginning */
  1466.                 else
  1467.                     pline->xx += pline->dx;  /* Middle */
  1468.                 x2 = pline->xx >> 16;
  1469.                 if (x2 < xp) sort++;
  1470.                     xp = x2;
  1471.                 if (x2 < x1)
  1472.                 {   xx = x1;
  1473.                     x1 = x2;
  1474.                     x2 = xx;
  1475.                 }
  1476.                 if      (fdir == 0)          /* Left edge */
  1477.                 {   fdir += pline->fdir;
  1478.                     s1 = x1;
  1479.                     s2 = x2;
  1480.                     continue;
  1481.                 }
  1482.                 if (x1 < s1) s1 = x1;        /* Right edge, or ...  */
  1483.                 if (x2 > s2) s2 = x2;
  1484.                 fdir += pline->fdir;
  1485.                 if      (fdir != 0)          /* Interior */
  1486.                     continue;
  1487.             }
  1488.  
  1489.             /* Draw from s1 to s2 in the x buffer, 8 bits per pixel */
  1490.  
  1491.             xptr1 = xbuf + (s1 >> 3);
  1492.             xptr2 = xbuf + (s2 >> 3);
  1493.             mask1 =  0xff >> (s1 & 7);
  1494.             mask2 = ~0xff >> ((s2 & 7) + 1);
  1495.             if (xptr1 == xptr2)
  1496.                 *xptr1 |= (mask1 & mask2);
  1497.             else
  1498.             {   *xptr1++ |= mask1;
  1499.                 while (xptr1 != xptr2) *xptr1++ = 0xff;
  1500.                 *xptr1 |= mask2;
  1501.             }
  1502.         }
  1503.  
  1504.         /* Pack the x buffer horizontally, 8 bits per pixel */
  1505.  
  1506. lll:
  1507.         xptr1 = xbuf;
  1508.         count = gstate.dev.xsize;
  1509.         s1 = 0;
  1510.         s2 = *((unsigned char *) (xptr1++));
  1511.         while (count--)
  1512.         {   s0 = s1;
  1513.             s1 = s2;
  1514.             s2 = *((unsigned char *) (xptr1++));
  1515.             xshf[count] <<= 1;
  1516.             if (ctbl[s1] ||
  1517.                 ltbl[s1] > rtbl[s0] ||
  1518.                 rtbl[s1] != 0 && rtbl[s1] >= ltbl[s2])
  1519.                 xshf[count] |= 1;
  1520.         }
  1521.  
  1522.         /* After every 8 lines, pack bits vertically onto the page */
  1523.  
  1524.         if (yy > 7 && (yy & 7) == 7)
  1525.         {   pptr1 = pptr;
  1526.             mask1 = 0x80;
  1527.             count = gstate.dev.xsize;
  1528.             while (count--)
  1529.             {   s2 = xshf[count];
  1530.                 s0 = (s2 >> 16) & 0xff;
  1531.                 s1 = (s2 >>  8) & 0xff;
  1532.                 s2 = s2 & 0xff;
  1533.                 if (ctbl[s1] ||
  1534.                     ltbl[s1] > rtbl[s0] ||
  1535.                     rtbl[s1] != 0 && rtbl[s1] >= ltbl[s2])
  1536.                     *pptr1 |= mask1;
  1537.                 if ((mask1 >>= 1) == 0)
  1538.                 {   mask1 = 0x80;
  1539.                     pptr1++;
  1540.                 }
  1541.             }
  1542.             pptr += gstate.dev.xbytes;
  1543.         }
  1544.  
  1545.         yy++;
  1546.  
  1547.     }
  1548.  
  1549.     ybflag = 0;
  1550. }
  1551.  
  1552. /* Scale a line ready for filling */
  1553.  
  1554. void charline(struct point *ppoint)
  1555. {   struct line line;
  1556.     double x1, x2, y1, y2, yy;
  1557.     int fdir;
  1558.  
  1559.     /* We convert the coordinates to fixed point, with a scale factor of
  1560.      * 256, rendering 8 bits per pixel */
  1561.  
  1562.     x1 = floor(ppoint[0].x * 2048.0 + 0.5);
  1563.     x2 = floor(ppoint[1].x * 2048.0 + 0.5);
  1564.     y1 = floor(ppoint[0].y * 2048.0 + 0.5);
  1565.     y2 = floor(ppoint[1].y * 2048.0 + 0.5);
  1566.     
  1567.     /* Make y1 <= y2 */
  1568.  
  1569.     fdir = 1;
  1570.     if (y2 < y1)
  1571.     {   fdir = -1;
  1572.         yy = x1; x1 = x2; x2 = yy;
  1573.         yy = y1; y1 = y2; y2 = yy;
  1574.     }
  1575.  
  1576.     /* Construct the line.  If it is not horizontal calculate the gradient
  1577.      * and the special values of the x displacement for the first and last
  1578.      * lines.  The x coordinates are on a scale of 65536  */
  1579.  
  1580.     line.cdir = 0;
  1581.     line.fdir = fdir;
  1582.     line.xx = x1 * 256.0;
  1583.     line.y1 = ((int) y1) / 256;
  1584.     line.y2 = ((int) y2) / 256;
  1585.     if (line.y2 == line.y1)
  1586.     {   line.dx = 0;
  1587.         line.d1 = 0;
  1588.         line.d2 = (x2 - x1) * 256.0;
  1589.     }
  1590.     else
  1591.     {   yy = (x2 - x1) / (y2 - y1) * 256.0;
  1592.         line.dx = yy * 256.0;
  1593.         line.d1 = ((line.y1 + 1) * 256.0 - y1) * yy;
  1594.         line.d2 = (y2 - line.y2 * 256.0) * yy;
  1595.     }
  1596.  
  1597.     /* Store the line in the line array */
  1598.  
  1599.     checklinesize(lineend + 1);
  1600.     linearray[lineend++] = line;
  1601. }
  1602.  
  1603. /* Set up the x buffers */
  1604.  
  1605. void setxbuf(int size)
  1606. {   int len;
  1607.     if (size > xbsize)
  1608.     {   len = size * (sizeof (int) + sizeof (char)) + 1;
  1609.         xbsize = 0;
  1610.         memfree(memxbeg, memxlen);
  1611.         memxlen = 0;
  1612.         memxbeg = memalloc(len);
  1613.         if (memxbeg == NULL) error(errmemoryallocation);
  1614.         memxlen = len;
  1615.         xshf = memxbeg;
  1616.         xbsize = size;
  1617.     }
  1618.     xbuf = (char *) (xshf + size);
  1619. }
  1620.  
  1621. /* End of file "postfont.c" */
  1622.