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

  1. /* PostScript interpreter file "postchar.c" - character routines
  2.  * (C) Adrian Aylward 1989, 1992
  3.  * V1.6 First source release
  4.  * V1.7 Fix stroking lines of zero length
  5.  * V1.7 Fix image and kshow procs not observing stack discipline
  6.  */
  7.  
  8. # include "post.h"
  9.  
  10. /* Routines */
  11.  
  12. extern void cachefast(struct fcrec *pfcrec,
  13.                       int xpos1, int ypos1, int y1, int y2);
  14. extern void cacheslow(struct fcrec *pfcrec,
  15.                       int xpos1, int ypos1, int y1, int y2);
  16.  
  17. /* Initialise the character routines */
  18.  
  19. void initchar(void)
  20. {   struct object token, *aptr;
  21.     char *s;
  22.     int i;
  23.  
  24.     /* Create various names for character operations */
  25.  
  26.     for (i = 0; i < charmax; i++)
  27.         nametoken(&charname[i], chartable[i], -1, 0);
  28.  
  29.     /* Create the standard encoding vector */
  30.  
  31.     token.type = typearray;
  32.     token.flags = 0;
  33.     token.length = 256;
  34.     token.value.vref = arrayalloc(256);
  35.     aptr = vmaptr(token.value.vref);
  36.     for (i = 0; i < 256; i++)
  37.     {   s = ((i & 0x60) == 0) ? NULL :
  38.                                 stdentable[i - ((i < 0x80) ? 0x20 : 0x40)];
  39.         if (s)
  40.             nametoken(&aptr[i], s, -1, 0);
  41.         else
  42.             aptr[i] = charname[charnotdef];
  43.     }
  44.     dictput(dictstack[0].value.vref, &charname[charstdencoding], &token);
  45.     stdencoding = aptr;
  46.  
  47.     /* Create the font directorary */
  48.  
  49.     dicttoken(&fontdir, fontdictsize);
  50.     dictput(dictstack[0].value.vref, &charname[charfontdirectory], &fontdir);
  51.  
  52.     /* Initialise the font cache */
  53.  
  54.     fmcount = 0;
  55.     fmcache = vmallocv(sizeof (struct fmrec) * fmsize);
  56.     fccache = vmallocv(sizeof (struct fcrec *) * fcsize);
  57.     fcptr = fcbeg = memfbeg;
  58.     fcend = (struct fcrec *) ((char *) memfbeg + memflen);
  59.     fclen = memflen;
  60.     if (fclen < sizeof (struct fcrec))
  61.         fclen = 0;
  62.     else
  63.     {   fcbeg->reclen = fclen;
  64.         fcbeg->count = 0;
  65.     }
  66.     istate.fclim = fclen;
  67.     fclimit = fclen / 40;
  68.  
  69.     /* Initialise the current font */
  70.  
  71.     token.type = 0;
  72.     token.flags = 0;
  73.     token.length = 0;
  74.     token.value.ival = 0;
  75.     gstate.font = token; 
  76.  
  77.     /* Initialise type 1 fonts */
  78.  
  79.     initfont();
  80. }
  81.  
  82. /* Restore the font cache */
  83.  
  84. void vmrestfont(struct vmframe *vmframe)
  85. {   struct fmrec *pfmrec;
  86.     struct fcrec *pfcrec, *pfcnxt, **ppfcrec;
  87.     int i;
  88.  
  89.     /* Scan the make cache to purge entries more recent than the vm save */
  90.  
  91.     pfmrec = &fmcache[0];
  92.     i = fmsize;
  93.     while (i--)
  94.     {   if (pfmrec->id != 0)
  95.             if (vmscheck(vmframe, pfmrec->dref)) pfmrec->id = 0;
  96.         pfmrec++;
  97.     }
  98.  
  99.     /* Scan the character cache, purging entries from the hash chains */
  100.  
  101.     if (fclen == 0) return;
  102.  
  103.     for (i = 0; i < fcsize; i++)
  104.     {   ppfcrec = &fccache[i];
  105.         for (;;)
  106.         {   pfcrec = *ppfcrec;
  107.             if (pfcrec == NULL) break;
  108.             if (vmscheck(vmframe, pfcrec->nref) ||
  109.                 vmscheck(vmframe, pfcrec->dref))
  110.             {   *ppfcrec = pfcrec->chain;
  111.                 pfcrec->count = 0;
  112.             }
  113.             else
  114.                 ppfcrec = &pfcrec->chain;
  115.         }
  116.     }
  117.  
  118.     /* Scan the character cache, joining adjacent free records */
  119.  
  120.     pfcrec = fcbeg;
  121.     while (pfcrec != fcend)
  122.     {   if (pfcrec->count == 0)
  123.         {   pfcnxt = (struct fcrec *) ((char *) pfcrec + pfcrec->reclen);
  124.             if (pfcnxt != fcend && pfcnxt->count == 0)
  125.             {   if (fcptr == pfcnxt) fcptr = pfcrec;
  126.                 pfcrec->reclen += pfcnxt->reclen;
  127.             }
  128.         }
  129.         pfcrec = (struct fcrec *) ((char *) pfcrec + pfcrec->reclen);
  130.     }
  131. }
  132.  
  133. /* Define a font */
  134.  
  135. void definefont(struct object *key, struct object *font)
  136. {   struct object token;
  137.  
  138.     /* Validate the font.  Get the uniqe id if we have one and construct
  139.      * the font id */
  140.  
  141.     checkfont(font, 0);
  142.     fontid = 0;
  143.     if (dictget(font->value.vref, &charname[charuniqueid], &token, 0))
  144.     {   if (token.type != typeint || (token.value.ival & 0xff000000) != 0)
  145.             error(errinvalidfont);
  146.         fontid = (fonttype << 24) | token.value.ival;
  147.     }
  148.     token.type = typefont;
  149.     token.flags = 0;
  150.     token.length = 0;
  151.     token.value.ival = fontid;
  152.     dictput(font->value.vref, &charname[charfid], &token);
  153.  
  154.     /* Make it read only and insert it into the font directory */
  155.  
  156.     vmdptr(font->value.vref)->flags |= flagwprot;
  157.     dictput(fontdir.value.vref, key, font);
  158. }
  159.  
  160. /* Find a font */
  161.  
  162. void findfont(struct object *key, struct object *font)
  163. {   if (!dictget(fontdir.value.vref, key, font, 0)) error(errinvalidfont);
  164. }
  165.  
  166. /* Make a font */
  167.  
  168. void makefont(struct object *font, float *matrix)
  169. {   struct object token;
  170.     struct dictionary *odict, *ndict;
  171.     struct fmrec *pfmrec, *pfmrcu;
  172.     vmref ndref;
  173.     float oldmatrix[6], newmatrix[6];
  174.     int count, i;
  175.  
  176.     /* Validate the font and calculate the new matrix */
  177.  
  178.     checkfont(font, 1);
  179.     getmatrix(fontmatrix, oldmatrix);
  180.     multiplymatrix(newmatrix, oldmatrix, matrix);
  181.  
  182.     /* Look in the make cache to see if we have made one like this before.
  183.      * We only cache fonts that have unique ids.  If we find one update the
  184.      * usage counter on its cache record */
  185.  
  186.     fmcount++;
  187.     if (fontid != 0)
  188.     {   pfmrec = &fmcache[0];
  189.         i = fmsize;
  190.         while (i--)
  191.         {   if (pfmrec->id == fontid &&
  192.                 pfmrec->encodlen == fontencodlen &&
  193.                 pfmrec->encoding == fontencoding &&
  194.                 memcmp((char *) pfmrec->matrix,
  195.                        (char *) newmatrix, sizeof newmatrix) == 0)
  196.             {   pfmrec->count = fmcount;
  197.                 font->value.vref = pfmrec->dref;
  198.                 return;
  199.             }
  200.             pfmrec++;
  201.         }
  202.     }
  203.  
  204.     /* Copy the font.  Replace the matrix with the new one */
  205.  
  206.     odict = vmdptr(font->value.vref);
  207.     ndref = vmalloc(odict->length);
  208.     ndict = vmdptr(ndref);
  209.     memcpy((char *) ndict, (char *) odict, odict->length);
  210.     ndict->saved = vmnest;
  211.     ndict->flags &= ~flagwprot;
  212.     fontmatrix = arrayalloc(6);
  213.     token.type = typearray;
  214.     token.flags = 0;
  215.     token.length = 6;
  216.     token.value.vref = fontmatrix;
  217.     putmatrix(fontmatrix, newmatrix);
  218.     dictput(ndref, &charname[charfontmatrix], &token);
  219.     ndict->flags |= flagwprot;
  220.     font->value.vref = ndref;
  221.  
  222.     /* Save the new font in the cache.  Look for an empty slot; if we don't
  223.      * find one use the least recently used */
  224.  
  225.     if (fontid != 0)
  226.     {   pfmrcu = pfmrec = &fmcache[0];
  227.         i = fmsize;
  228.         count = 0x7fffffff;
  229.         while (i--)
  230.         {   if (pfmrec->count < count)
  231.             {   count = pfmrec->count;
  232.                 pfmrcu = pfmrec;
  233.             }
  234.             if (pfmrec->id == 0)
  235.             {   pfmrcu = pfmrec;
  236.                 break;
  237.             }
  238.             pfmrec++;
  239.         }
  240.         pfmrcu->count = fmcount;
  241.         pfmrcu->id = fontid;
  242.         pfmrcu->encodlen = fontencodlen;
  243.         pfmrcu->encoding = fontencoding;
  244.         memcpy((char *) pfmrcu->matrix,
  245.                (char *) newmatrix, sizeof newmatrix);
  246.         pfmrcu->dref = ndref;
  247.     }
  248. }
  249.  
  250. /* Set a font */
  251.  
  252. void setfont(struct object *font)
  253. {   if (font->type != typenull) checkfont(font, 1);
  254.     gstate.font = *font;
  255. }
  256.  
  257. /* Check a font for validity */
  258.  
  259. void checkfont(struct object *font, int fid)
  260. {   struct object token;
  261.     if (font->type != typedict) error(errtypecheck);
  262.     if (!dictget(font->value.vref, &charname[charfonttype], &token, 0))
  263.         error(errinvalidfont);
  264.     if (token.type != typeint ||
  265.         (token.value.ival != 1 && token.value.ival != 3))
  266.         error(errinvalidfont);
  267.     fonttype = token.value.ival;
  268.     if (!dictget(font->value.vref, &charname[charfontmatrix], &token, 0))
  269.         error(errinvalidfont);
  270.     if (token.type != typearray || token.length != 6 ||
  271.         (token.flags & flagrprot))
  272.         error(errinvalidfont);
  273.     fontmatrix = token.value.vref;
  274.     if (!dictget(font->value.vref, &charname[charfontbbox], &token, 0))
  275.         error(errinvalidfont);
  276.     if ((token.type != typearray && token.type != typepacked) ||
  277.         token.length != 4 || (token.flags & flagrprot))
  278.         error(errinvalidfont);
  279.     if (!dictget(font->value.vref, &charname[charencoding], &token, 0))
  280.         error(errinvalidfont);
  281.     if (token.type != typearray || (token.flags & flagrprot))
  282.         error(errinvalidfont);
  283.     fontencodlen = token.length;
  284.     fontencoding = token.value.vref;
  285.     if (dictget(font->value.vref, &charname[charfid], &token, 0) != fid)
  286.         error(errinvalidfont);
  287.     if (fid)
  288.     {   if (token.type != typefont) error(errinvalidfont);
  289.         fontid = token.value.ival;
  290.     }
  291. }
  292.  
  293. /* Show a string (type = 0,1 charpath; 2 stringwidth; 3 show) */
  294.  
  295. void show(struct object *string, int type,
  296.           struct point *width, int wchar, struct object *kproc)
  297. {   struct object token, font, *encoding, bproc;
  298.     struct point cpoint, fpoint;
  299.     struct fcrec fcrec, *pfcrec, **ppfcrec;
  300.     char *sptr;
  301.     float newctm[6], oldctm[6], matrix[6];
  302.     int encodlen, length, schar, iflag, ftype;
  303.     int id, nest, i, lev;
  304.  
  305.     if (istate.flags & intgraph) error(errundefined);
  306.  
  307.     lev = flushlevel(-1);
  308.  
  309.     /* Look up the matrix, encoding, font id */
  310.  
  311.     iflag = 0;
  312.     font = gstate.font;
  313.     if (font.type != typedict) error(errinvalidfont);
  314.     if (!dictget(font.value.vref, &charname[charfontmatrix], &token, 0))
  315.         error(errinvalidfont);
  316.     getmatrix(token.value.vref, matrix);
  317.     if (!dictget(font.value.vref, &charname[charencoding], &token, 0))
  318.         error(errinvalidfont);
  319.     encodlen = token.length;
  320.     encoding = vmaptr(token.value.vref);
  321.     if (!dictget(font.value.vref, &charname[charfid], &token, 0))
  322.         error(errinvalidfont);
  323.     id = token.value.ival;
  324.  
  325.     /* For stringwidth start at zero */
  326.  
  327.     if (type == 2)
  328.     {   cpoint.type = ptmove;
  329.         cpoint.x = cpoint.y = 0.0;
  330.     }
  331.  
  332.     /* Loop for every character in the string */
  333.  
  334.     length = string->length;
  335.     sptr = vmsptr(string->value.vref);
  336.     while (length--)
  337.     {   schar = *((unsigned char *) sptr);
  338.         sptr++;
  339.  
  340.         /* Find the current point */
  341.  
  342.         if (type != 2)
  343.         {   if (gstate.pathend == gstate.pathbeg) error(errnocurrentpoint);
  344.             closepath(ptclosei);
  345.             cpoint = patharray[gstate.pathend - 1];
  346.         }
  347.  
  348.         /* Build the new ctm (current point rounded to pixel boundary) */
  349.  
  350.         memcpy((char *) oldctm, (char *) gstate.ctm, 4 * sizeof (float));
  351.         oldctm[4] = cpoint.x;
  352.         oldctm[5] = cpoint.y;
  353.         multiplymatrix(newctm, matrix, oldctm);
  354.         fpoint.x = newctm[4] = floor(newctm[4] + 0.5);
  355.         fpoint.y = newctm[5] = floor(newctm[5] + 0.5);
  356.  
  357.         /* Don't use the cache for charpath */
  358.  
  359.         fcrec.reclen = 0;
  360.         fcrec.width.x = fcrec.width.y = 0.0;
  361.         if (type < 2) goto nocache;
  362.  
  363.         /* Construct the cache key */
  364.  
  365.         if (schar < encodlen)
  366.         {   token = encoding[schar];
  367.             if (token.type != typename) error(errinvalidfont);
  368.         }
  369.         else
  370.             token = charname[charnotdef];
  371.         fcrec.id = id;
  372.         fcrec.nref = token.value.vref;
  373.         fcrec.dref= (id == 0) ? font.value.vref : 0;
  374.         memcpy((char *) fcrec.matrix, (char *) newctm, 4 * sizeof (float));
  375.         fcrec.hash = id;
  376.         fcrec.hash = fcrec.hash * 12345 + (int) fcrec.dref;
  377.         fcrec.hash = fcrec.hash * 12345 + (int) fcrec.nref;
  378.         for (i = 0; i < 4 ; i++)
  379.             fcrec.hash = fcrec.hash * 12345 + *((int *) &fcrec.matrix[i]);
  380.  
  381.         /* Search the cache for the character */
  382.  
  383.         for (ppfcrec = &fccache[fcrec.hash % fcsize];
  384.              pfcrec = *ppfcrec, pfcrec != NULL;
  385.              ppfcrec = &pfcrec->chain)
  386.             if (pfcrec->hash == fcrec.hash &&
  387.                 pfcrec->dref == fcrec.dref &&
  388.                 pfcrec->nref == fcrec.nref &&
  389.                 pfcrec->matrix[0] == fcrec.matrix[0] &&
  390.                 pfcrec->matrix[1] == fcrec.matrix[1] &&
  391.                 pfcrec->matrix[2] == fcrec.matrix[2] &&
  392.                 pfcrec->matrix[3] == fcrec.matrix[3] &&
  393.                 pfcrec->id == fcrec.id)
  394.                 goto incache;
  395.  
  396.         /* Not in the cache; look up the build data.  Type 1 uses external
  397.          * data as we can't recurse, whereas type 3 uses local data */
  398.  
  399. nocache:
  400.         if (iflag == 0)
  401.         {   if (!dictget(font.value.vref, &charname[charfonttype],
  402.                                           &token, 0))
  403.                 error(errinvalidfont);
  404.             ftype = token.value.ival;
  405.             if (ftype == 1)
  406.                 initbuild(font.value.vref);
  407.             else
  408.             {   if (!dictget(font.value.vref, &charname[charbuildchar],
  409.                                               &bproc, 0))
  410.                     error(errinvalidfont);
  411.             }
  412.             iflag = 1;
  413.         }
  414.  
  415.         /* Build the character.  Push the interpreter state; save the
  416.          * graphics state and set up the new ctm.  Type 1 executes the
  417.          * character string, whereas type 3 interprets the build proc */
  418.  
  419.         nest = opernest;
  420.         pushint();
  421.         istate.flags = intchar;
  422.         istate.type = type;
  423.         istate.pfcrec = &fcrec;
  424.         gsave();
  425.         gstate.pathend = gstate.pathbeg;
  426.         memcpy((char *) gstate.ctm, (char *) newctm, sizeof newctm);
  427.         gstate.linecap = 0;
  428.         gstate.linejoin = 0;
  429.         gstate.mitrelimit = 10.0;
  430.         gstate.mitresin = 0.198997;
  431.         gstate.dashoffset = 0.0;
  432.         gstate.dasharray.length = 0;
  433.  
  434.         if (ftype == 1)
  435.             buildchar(schar);
  436.         else
  437.         {   gstate.flatness = 1.0;
  438.             gstate.linewidth = 1.0;
  439.             if (opernest + 2 > operstacksize) error(errstackoverflow);
  440.             operstack[opernest++] = font;
  441.             token.type = typeint;
  442.             token.flags = 0;
  443.             token.length = 0;
  444.             token.value.ival = schar;
  445.             operstack[opernest++] = token;
  446.             interpret(&bproc);
  447.         }
  448.  
  449.         grest();
  450.         pfcrec = istate.pfcrec;
  451.         popint();
  452.         if (opernest > nest) error(errstackoverflow);
  453.         if (opernest < nest) error(errstackunderflow);
  454.     
  455.         /* Increment the cache record usage count.  If the character is in
  456.          * the cache image it onto the page.  Add the width to the current
  457.          * point */
  458. incache:
  459.         pfcrec->count++;
  460.         if (type == 3 && pfcrec->reclen != 0)
  461.             cacheimage(pfcrec, &fpoint);
  462.         cpoint.x += pfcrec->width.x;
  463.         cpoint.y += pfcrec->width.y;
  464.  
  465.         /* Adjust the width */
  466.  
  467.         if (type == 3 && width != NULL)
  468.         {   if (schar == wchar)
  469.             {   cpoint.x += width[0].x;
  470.                 cpoint.y += width[0].y;
  471.             }
  472.             cpoint.x += width[1].x;
  473.             cpoint.y += width[1].y;
  474.         }
  475.  
  476.         /* Update the current point */
  477.  
  478.         if (type != 2)
  479.         {   cpoint.type = ptmove;
  480.             if (gstate.pathbeg == gstate.pathend ||
  481.                 patharray[gstate.pathend - 1].type != ptmove)
  482.                 checkpathsize(gstate.pathend + 1);
  483.             else
  484.                 gstate.pathend--;
  485.             patharray[gstate.pathend++] = cpoint;
  486.         }
  487.  
  488.         /* Call the kerning proc */
  489.  
  490.         if (kproc != NULL && length != 0)
  491.         {   if (opernest + 2 > operstacksize) error(errstackoverflow);
  492.             token.type = typeint;
  493.             token.flags = 0;
  494.             token.length = 0;
  495.             token.value.ival = schar;
  496.             operstack[opernest++] = token;
  497.             token.value.ival = *((unsigned char *) sptr);
  498.             operstack[opernest++] = token;
  499.             pushint();
  500.             interpret(kproc);
  501.             popint();
  502.         }
  503.     }
  504.  
  505.     /* For stringwidth return the width */
  506.  
  507.     if (type == 2)
  508.         *width = cpoint;
  509.  
  510.     flushlevel(lev);
  511. }
  512.  
  513. /*  Append the character path to the path of the saved graphics state */
  514.  
  515. void charpath(void)
  516. {   struct gstate *pgstate;
  517.     struct point *ppoint1, *ppoint2;
  518.     int pathlen, len, gap, snest;
  519.  
  520.     /* Locate the graphics state we saved before beginning the build proc */
  521.  
  522.     snest = istate.gbase;
  523.     pgstate = &gstack[snest];
  524.  
  525.     /* Shuffle all the newer paths up to make room */
  526.  
  527.     len = gstate.pathend - pgstate->pathend;
  528.     gap = pathlen = gstate.pathend - gstate.pathbeg;
  529.     if (patharray[pgstate->pathend - 1].type == ptmove) gap--;
  530.     checkpathsize(gstate.pathend + gap);
  531.     ppoint2 = &patharray[gstate.pathend];
  532.     ppoint1 = ppoint2 + gap;
  533.     while (len--) *--ppoint1 = *--ppoint2;
  534.  
  535.     /* Adjust the pointers to the paths we have moved */
  536.  
  537.     pgstate->pathend += gap;
  538.     while (++snest < gnest)
  539.     {    pgstate++;
  540.          pgstate->clipbeg += gap;
  541.          pgstate->pathbeg += gap;
  542.          pgstate->pathend += gap;
  543.     }
  544.     gstate.clipbeg += gap;
  545.     gstate.pathbeg += gap;
  546.     gstate.pathend = gstate.pathbeg;
  547.  
  548.     /* Copy the path */
  549.  
  550.     ppoint1 -= pathlen;
  551.     ppoint2 = &patharray[gstate.pathbeg];
  552.     while (pathlen--) *ppoint1++ = *ppoint2++;
  553. }
  554.  
  555. /* Set character width */
  556.  
  557. void setcharwidth(struct point *width)
  558. {   if (!(istate.flags & intchar)) error(errundefined);
  559.     istate.pfcrec->width = *width;
  560. }
  561.  
  562. /* Set cache device */
  563.  
  564. void setcachedevice(struct point *ll, struct point *ur, int ftype)
  565. {   struct fcrec *pfcrec, *pfcnxt, **ppfcrec;
  566.     float llx, lly, urx, ury;
  567.     int reclen, length, xbytes, xsize, ysize, fclim;
  568.  
  569.     /* Calculate the bitmap dimensions, check cache limit */
  570.  
  571.     llx = floor(ll->x);
  572.     lly = floor(ll->y);
  573.     urx = floor(ur->x - llx) + 1.0;
  574.     ury = floor(ur->y - lly) + 1.0;
  575.     if (fabs(llx) > 10000.0 || urx > 10000.0) return;
  576.     if (fabs(lly) > 10000.0 || ury > 10000.0) return;
  577.     xsize = urx;
  578.     ysize = ury;
  579.     xbytes = (xsize + 7) >> 3;
  580.     length = xbytes * ysize;
  581.     if (length > fclimit) return;
  582.  
  583.     /* For type 3 fonts we must ensure there is sufficient space for all
  584.      * the simultaneously active cache records; so we limit the record
  585.      * length to one third of the total length, and set the limit for the
  586.      * next level to one third too (allowing for fragmentation).  For type
  587.      * 1 fonts we can use the full length as there is no recursion */
  588.  
  589.     reclen =
  590.        (sizeof (struct fcrec) + length + (mcalign - 1)) & ~(mcalign - 1);
  591.     fclim = istate.fclim;
  592.     if (ftype == 3) fclim /= 3;
  593.     if (reclen > fclim) return;
  594.     if (ftype == 1) fclim = 0;
  595.     istate.fclim = fclim;
  596.  
  597.     /* Find a free cache slot.  Halve the usage counts as we go; free the
  598.      * records when they become empty, joining adjacent free records */
  599.  
  600.     for (;;)
  601.     {   if (fcptr == fcend) fcptr = fcbeg;
  602.         pfcrec = fcptr;
  603.         for (;;)
  604.         {   if (fcptr->count == 1)
  605.             {   ppfcrec = &fccache[fcptr->hash % fcsize];
  606.                 while (*ppfcrec != fcptr) ppfcrec = &((*ppfcrec)->chain);
  607.                 *ppfcrec = fcptr->chain;
  608.                 pfcnxt = (struct fcrec *) ((char *) fcptr + fcptr->reclen);
  609.                 if (pfcnxt != fcend && pfcnxt->count == 0)
  610.                     fcptr->reclen += pfcnxt->reclen;
  611.             }
  612.             if (fcptr->count != -1) fcptr->count >>= 1;
  613.             if (fcptr->count == 0 && fcptr != pfcrec)
  614.                 pfcrec->reclen += fcptr->reclen;
  615.             fcptr = (struct fcrec *) ((char *) fcptr + fcptr->reclen);
  616.             if (fcptr == fcend) break;
  617.             if (fcptr->count != 0 && fcptr->count != 1) break;
  618.             if (pfcrec->count != 0) break;
  619.             if (pfcrec->reclen >= reclen) break;
  620.         }
  621.         if (pfcrec->count == 0 && pfcrec->reclen >= reclen) break;
  622.     }
  623.  
  624.     /* If the record is large enough split it */
  625.  
  626.     if (pfcrec->reclen - reclen > sizeof (struct fcrec))
  627.     {   fcptr = (struct fcrec *) ((char *) pfcrec + reclen);
  628.         fcptr->count = 0;
  629.         fcptr->reclen = pfcrec->reclen - reclen;
  630.         pfcrec->reclen = reclen;
  631.     }
  632.  
  633.     /* Set up the cache record, adjust the ctm */
  634.  
  635.     ppfcrec = &fccache[istate.pfcrec->hash % fcsize];
  636.     pfcrec->chain = *ppfcrec;
  637.     *ppfcrec = pfcrec;
  638.     pfcrec->count = -1;
  639.     pfcrec->dref = istate.pfcrec->dref;
  640.     pfcrec->nref = istate.pfcrec->nref;
  641.     pfcrec->width = istate.pfcrec->width;
  642.     pfcrec->matrix[0] = istate.pfcrec->matrix[0];
  643.     pfcrec->matrix[1] = istate.pfcrec->matrix[1];
  644.     pfcrec->matrix[2] = istate.pfcrec->matrix[2];
  645.     pfcrec->matrix[3] = istate.pfcrec->matrix[3];
  646.     pfcrec->len = length;
  647.     pfcrec->hash = istate.pfcrec->hash;
  648.     pfcrec->id = istate.pfcrec->id;
  649.     pfcrec->xbytes = xbytes;
  650.     pfcrec->xsize = xsize;
  651.     pfcrec->ysize = ysize;
  652.     pfcrec->xoffset = llx;
  653.     pfcrec->yoffset = lly;
  654.     istate.pfcrec = pfcrec;
  655.     gstate.ctm[4] = -llx;
  656.     gstate.ctm[5] = -lly;
  657.  
  658.     /* Install the cache device */
  659.  
  660.     gstate.cacheflag = 1;
  661.     gstate.clipflag = 0;
  662.     gstate.gray = 0.0;
  663.     gstate.shade[0] = 0.0;
  664.     gstate.shadeok = 1;
  665.     screenok = 0;
  666.     gstate.dev.buf[0] = (char *) (pfcrec + 1);
  667.     gstate.dev.len = length;
  668.     gstate.dev.depth = 1;
  669.     gstate.dev.xbytes = pfcrec->xbytes;
  670.     gstate.dev.xsize = pfcrec->xsize;
  671.     gstate.dev.ysize = pfcrec->ysize;
  672.     gstate.dev.ybase = 0;
  673.     gstate.dev.yheight = pfcrec->ysize;
  674.     memset(gstate.dev.buf[0], 0, length);
  675. }
  676.  
  677. /* Get cache status */
  678.  
  679. void cachestatus(int *status)
  680. {   struct fmrec *pfmrec;
  681.     struct fcrec *pfcrec;
  682.     int count, length, i;
  683.     count = 0;
  684.     pfmrec = &fmcache[0];
  685.     i = fmsize;
  686.     while (i--)
  687.     {   if (pfmrec->id != 0) count++;
  688.         pfmrec++;
  689.     }
  690.     status[2] = count;
  691.     status[3] = fmsize;
  692.     count = 0;
  693.     length = 0;
  694.     if (fclen == 0)
  695.         status[1] = status[5] = 0;
  696.     else
  697.     {   pfcrec = fcbeg;
  698.         while (pfcrec != fcend)
  699.         {   if (pfcrec->count != 0)
  700.             {   count++;
  701.                 length += pfcrec->reclen;
  702.             }
  703.             pfcrec = (struct fcrec *) ((char *) pfcrec + pfcrec->reclen);
  704.         }
  705.         status[1] = fclen;
  706.         status[5] = fclen / sizeof (struct fcrec) - 1;
  707.     }
  708.     status[0] = length;
  709.     status[4] = count;
  710.     status[6] = fclimit;
  711. }
  712.  
  713. /* Set null device */
  714.  
  715. void nulldevice(void)
  716. {   gstate.dev.depth = 0;
  717.     gstate.dev.len = 0;
  718.     gstate.dev.xoff = 0;
  719.     gstate.dev.yoff = 0;
  720.     gstate.dev.xbytes = 0;
  721.     gstate.dev.xsize = 0;
  722.     gstate.dev.ysize = 0;
  723.     gstate.dev.ybase = 0;
  724.     gstate.dev.yheight = 0;
  725.     gstate.dev.xden = 72;
  726.     gstate.dev.yden = 72;
  727.     gstate.dev.ydir = 1;
  728.     gstate.clipflag = 0;
  729.     gstate.cacheflag = 0;
  730.     gstate.nullflag = 0;
  731.     cliplength(0);
  732.     halfok = gstacksize + 1;
  733.     initctm(gstate.ctm);
  734. }
  735.  
  736. /* Image the character data from the cache onto the page */
  737.  
  738. void cacheimage(struct fcrec *pfcrec, struct point *point)
  739. {   struct line *pline;
  740.     int xpos1, ypos1;
  741.     int x1, x2, y1, y2, xx;
  742.     int count, cdir;
  743.  
  744.     setupfill();
  745.  
  746.     /* Locate the image bounds */
  747.  
  748.     if (point->x < -1000.0 || point->x > 31000.0) return;
  749.     if (point->y < -1000.0 || point->y > 31000.0) return;
  750.  
  751.     xpos1 = (int) point->x + pfcrec->xoffset;
  752.     ypos1 = (int) point->y + pfcrec->yoffset;
  753.     y1 = ypos1;
  754.     y2 = ypos1 + pfcrec->ysize;
  755.     if (y1 < gstate.dev.ybase)
  756.         y1 = gstate.dev.ybase;
  757.     if (y2 > gstate.dev.ybase + gstate.dev.ysize)
  758.         y2 = gstate.dev.ybase + gstate.dev.ysize;
  759.     if (y1 == y2) return;
  760.  
  761.     /* If there is no clip path we always can do a fast image */
  762.  
  763.     if (!gstate.clipflag)
  764.         cachefast(pfcrec, xpos1, ypos1, y1, y2);
  765.  
  766.     /* Otherwise we must see if the image is within the clip path */
  767.  
  768.     else
  769.     {
  770.  
  771.         /* Set up the clip lines.   We clip them, using the minimum and
  772.          * maximum y values from the image */
  773.  
  774.         ymax = ylwb = y1 * 256.0;
  775.         ymin = yupb = y2 * 256.0;
  776.         lineend = 0;
  777.         filllines(&patharray[gstate.clipbeg],
  778.                   gstate.pathbeg - gstate.clipbeg, 1, 0);
  779.         if (lineend == 0) return;
  780.  
  781.         /* See if any of the clip lines intersect the image */
  782.  
  783.         x1 = xpos1 << 16;
  784.         x2 = (xpos1 + pfcrec->xsize) << 16;
  785.         count = lineend;
  786.         pline = &linearray[0];
  787.         cdir = 0;
  788.         while (count)
  789.         {   if (pline->y1 == y1 && pline->y2 != y1 && pline->xx < x1)
  790.                 cdir += pline->cdir;
  791.             xx = pline->xx + pline->d1 + pline->d2;
  792.             if (pline->y2 > pline->y1 + 1)
  793.                 xx +=  (pline->y2 - pline->y1 - 1) * pline->dx;
  794.             if (xx < x1 && pline->xx >= x2) break;
  795.             if (pline->xx < x1 && xx >= x2) break;
  796.             if (pline->xx >= x1 && pline->xx < x2) break;
  797.             if (xx >= x1 && xx < x2) break;
  798.             pline++;
  799.             count--;
  800.         }
  801.  
  802.         /* No lines intersect: either entirely visible or invisible */
  803.  
  804.         if (count == 0)
  805.         {   if (cdir == 0) return;
  806.             cachefast(pfcrec, xpos1, ypos1, y1, y2);
  807.         }
  808.  
  809.         /* If any lines intersect we must do a slow image */
  810.  
  811.         else
  812.             cacheslow(pfcrec, xpos1, ypos1, y1, y2);
  813.     }
  814.  
  815.     flushlpage(y1, y2);
  816. }
  817.  
  818. /* Slow image the character cache data */
  819.  
  820. void cacheslow(struct fcrec *pfcrec, int xpos1, int ypos1, int yy, int y2)
  821. {   struct line *pline, **ppline;
  822.     struct halfscreen *hscreen;
  823.     struct halftone *htone;
  824.     unsigned char *cbuf, *cbeg, *cptr; /* cache buffer row base, pointer */
  825.     char *dptr1, *dptr2;        /* device buffer pointers */
  826.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  827.     int count;                  /* counter */
  828.     int active, discard, sort;  /* lines active, to be discarded, sorted */
  829.     int x1, x2, xp, xx;         /* current, previous x position range */
  830.     int cdir;                   /* clip direction counter */
  831.     int poff;                   /* offset of line from page */
  832.     int xmod, hxsize;           /* position modulo halftone screen */
  833.     int mask1, mask2;           /* bit masks for first and last bytes */
  834.     int xbyt1, xbyt2;           /* bytes offsets from beginning of line */
  835.     int s1, s2;                 /* segment to draw */
  836.     int xshf, xbeg, ibyte, ilast;
  837.     int xpos2;
  838.     int plane;
  839.  
  840.     /* Set up the y buckets */
  841.  
  842.     setybucket(gstate.dev.ybase, gstate.dev.ysize);
  843.  
  844.     /* Fill the area.  Start at the lowest scan line in the path and loo
  845.      * until we reach the highest */
  846.  
  847.     active = discard = sort = 0;
  848.     xshf = xpos1 & 7;
  849.     xbeg = (xpos1 < 0) ? ~((~xpos1) >> 3) : xpos1 >> 3;
  850.     xpos2 = xpos1 + pfcrec->xsize;
  851.     cbuf = (char *) (pfcrec + 1) + (yy - ypos1) * pfcrec->xbytes;
  852.     poff = (yy - gstate.dev.ybase) * gstate.dev.xbytes;
  853.  
  854.     while (yy < y2)
  855.     {
  856.         /* Add all the new lines */
  857.  
  858.         pline = ybucket[yy - gstate.dev.ybase];
  859.         ybucket[yy - gstate.dev.ybase] = NULL;
  860.         while (pline)
  861.         {   lineptr[active++] = pline;
  862.             pline = pline->chain;
  863.             sort++;
  864.         }
  865.  
  866.         /* If we have any lines out of order or (new, being discarded) then
  867.          * we Shell sort the lines according to their current x coordinates.
  868.          * Any previously finished lines have large x coordinates so will be
  869.          * moved to the end of the array where they are discarded */
  870.  
  871.         sort += discard;
  872.         if (sort != 0)
  873.         {   count = active;
  874.             for (;;)
  875.             {   count = count / 3 + 1;
  876.                 for (x1 = count; x1 < active; x1++)
  877.                     for (x2 = x1 - count;
  878.                          x2 >= 0 &&
  879.                              lineptr[x2]->xx > lineptr[x2 + count]->xx;
  880.                          x2 -= count)
  881.                     {   pline = lineptr[x2];
  882.                         lineptr[x2] = lineptr[x2 + count];
  883.                         lineptr[x2 + count] = pline;
  884.                     }
  885.                 if (count == 1) break;
  886.             }
  887.             active -= discard;
  888.             discard = sort = 0;
  889.         }
  890.  
  891.         /* Scan convert the scan line */
  892.  
  893.         count = active;
  894.         cdir = 0;
  895.         ppline = &lineptr[0];
  896.         xp = -32767;
  897.  
  898.         while (count--)
  899.         {   pline = *ppline++;
  900.             x1 = pline->xx >> 16;
  901.  
  902.             /* At the end of the line (or if it is horizontal), use the
  903.              * special value of the x increment.  Flag it to be discarded.
  904.              * Draw only its width */
  905.  
  906.             if (yy == pline->y2)
  907.             {   pline->xx += pline->d2;
  908.                 x2 = pline->xx >> 16;
  909.                 pline->xx = 0x7fffffff;
  910.                 discard++;
  911.                 if (x2 < x1)
  912.                 {   xx = x1;
  913.                     x1 = x2;
  914.                     x2 = xx;
  915.                 }
  916.                 if (cdir == 0)
  917.                 {   s1 = x1;
  918.                     s2 = x2;
  919.                 }
  920.                 else
  921.                 {   if (x1 < s1) s1 = x1;
  922.                     if (x2 > s2) s2 = x2;
  923.                     continue;
  924.                 }
  925.             }
  926.  
  927.             /* At the beginning of the line, use the special value of the x
  928.              * increment, otherwise add the gradient to its current x
  929.              * coordinate.  We have to draw both the lines widths and the
  930.              * area enclosed.  For left edges we start drawing at the left
  931.              * of the line and draw the width too; for right edges we stop
  932.              * drawing at the right of the line. For interior lines we draw
  933.              * the line width (as it may not be interior higher up in the
  934.              * pixel */
  935.  
  936.             else
  937.             {   if      (yy == pline->y1)
  938.                     pline->xx += pline->d1;  /* Beginning */
  939.                 else
  940.                     pline->xx += pline->dx;  /* Middle */
  941.                 x2 = pline->xx >> 16;
  942.                 if (x2 < xp) sort++;
  943.                 xp = x2;
  944.                 if (x2 < x1)
  945.                 {   xx = x1;
  946.                     x1 = x2;
  947.                     x2 = xx;
  948.                 }
  949.                 if      (cdir == 0)          /* Left edge */
  950.                 {   cdir += pline->cdir;
  951.                     s1 = x1;
  952.                     s2 = x2;
  953.                     continue;
  954.                 }
  955.                 if (x1 < s1) s1 = x1;        /* Right edge, or ... */
  956.                 if (x2 > s2) s2 = x2;
  957.                 cdir += pline->cdir;
  958.                 if      (cdir != 0)          /* Interior */
  959.                     continue;
  960.             }
  961.             s2++;
  962.  
  963.             /* Draw from s1 to s2 */
  964.  
  965.             if (s1 < xpos1) s1 = xpos1;
  966.             if (s2 > xpos2) s2 = xpos2;
  967.             if (s1 < 0) s1 = 0;
  968.             if (s2 > gstate.dev.xsize) s2 = gstate.dev.xsize;
  969.             if (s1 >= s2) continue;
  970.             xbyt1 = s1 >> 3;
  971.             xbyt2 = (s2 - 1) >> 3;
  972.             mask1 =  0xff >> (s1 & 7);
  973.             mask2 = ~0xff >> (((s2 - 1) & 7) + 1);
  974.             cbeg = cbuf + xbyt1 - xbeg;
  975.  
  976.             /* Loop through the bit planes */
  977.  
  978.             hscreen = &halfscreen[0];
  979.             for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  980.             {   htone = hscreen->halftone;
  981.                 dptr1 = gstate.dev.buf[plane] + poff + xbyt1;
  982.                 dptr2 = gstate.dev.buf[plane] + poff + xbyt2;
  983.                 cptr = cbeg;
  984.                 ilast = 0;
  985.                 if (xbyt1 > xbeg) ilast = *(cptr - 1) << 8;
  986.  
  987.                 /* Optimise black or white */
  988.  
  989.                 if      (hscreen->num == 0)
  990.                 {   if (dptr1 == dptr2)
  991.                     {   mask1 &= mask2;
  992.                         *dptr1 |= (((ilast | *cptr) >> xshf) & mask1);
  993.                     }
  994.                     else
  995.                     {   *dptr1++ |=  (((ilast | *cptr) >> xshf) & mask1);
  996.                         ilast = *cptr++ << 8;
  997.                         while (dptr1 != dptr2)
  998.                         {   *dptr1++ |=  ((ilast | *cptr) >> xshf);
  999.                             ilast = *cptr++ << 8;
  1000.                         }
  1001.                         *dptr1 |=  (((ilast | *cptr) >> xshf) & mask2);
  1002.                     }
  1003.                 }
  1004.                 else if (hscreen->num == htone->area)
  1005.                 {   if (dptr1 == dptr2)
  1006.                     {   mask1 &= mask2;
  1007.                         *dptr1 &= ~(((ilast | *cptr) >> xshf) & mask1);
  1008.                     }
  1009.                     else
  1010.                     {   *dptr1++ &= ~(((ilast | *cptr) >> xshf) & mask1);
  1011.                         ilast = *cptr++ << 8;
  1012.                         while (dptr1 != dptr2)
  1013.                         {   *dptr1++ &= ~((ilast | *cptr) >> xshf);
  1014.                             ilast = *cptr++ << 8;
  1015.                         }
  1016.                         *dptr1 &= ~(((ilast | *cptr) >> xshf) & mask2);
  1017.                     }
  1018.                 }
  1019.  
  1020.                 /* The general case needs a halftone screen */
  1021.  
  1022.                 else
  1023.                 {   xmod = xbyt1 % htone->xsize;
  1024.                     hbeg = hscreen->ptr +
  1025.                         (yy % htone->ysize) * htone->xsize;
  1026.                     hptr = hbeg + xmod;
  1027.                     hxsize = htone->xsize;
  1028.                     if (dptr1 == dptr2)
  1029.                     {   ibyte = ((ilast | *cptr) >> xshf) & mask1 & mask2;
  1030.                         *dptr1 = (*dptr1 & ~ibyte) | (*hptr & ibyte);
  1031.                     }
  1032.                     else
  1033.                     {   ibyte = ((ilast | *cptr) >> xshf) & mask1;
  1034.                         ilast = *cptr++ << 8;
  1035.                         *dptr1 = (*dptr1 & ~ibyte) | (*hptr & ibyte);
  1036.                         dptr1++;
  1037.                         hptr++;
  1038.                         for (;;)
  1039.                         {   xmod++;
  1040.                             if (xmod == hxsize)
  1041.                             {   xmod = 0;
  1042.                                 hptr = hbeg;
  1043.                             }
  1044.                             if (dptr1 == dptr2) break;
  1045.                             ibyte = (ilast | *cptr) >> xshf;
  1046.                             ilast = *cptr++ << 8;
  1047.                             *dptr1 = (*dptr1 & ~ibyte) | (*hptr & ibyte);
  1048.                             dptr1++;
  1049.                             hptr++;
  1050.                         }
  1051.                         ibyte = ((ilast | *cptr) >> xshf) & mask2;
  1052.                         *dptr1 = (*dptr1 & ~ibyte) | (*hptr & ibyte);
  1053.                     }
  1054.                 }
  1055.             }
  1056.         }
  1057.  
  1058.         /* Continue with the next scan line */
  1059.  
  1060.         cbuf += pfcrec->xbytes;
  1061.         poff += gstate.dev.xbytes;
  1062.         yy++;
  1063.     }
  1064.  
  1065.     ybflag = 0;
  1066. }
  1067.  
  1068. /* Fast image the character cache data */
  1069.  
  1070. void cachefast(struct fcrec *pfcrec, int xpos1, int ypos1, int y1, int y2)
  1071. {   struct halfscreen *hscreen;
  1072.     struct halftone *htone;
  1073.     unsigned char *cbuf, *cbeg, *cptr; /* cache buffer row base, pointer */
  1074.     char *dbeg, *dptr1, *dptr2; /* device buffer row base, pointers */
  1075.     char *hbeg, *hptr;          /* halftone screen row base, pointer */
  1076.     int xbeg, xmod, ymod, hxsize;
  1077.     int xshf, ibyte, ilast;
  1078.     int x1, x2, xx, yy;
  1079.     int plane;
  1080.  
  1081.     cbuf = (char *) (pfcrec + 1) + pfcrec->xbytes * (y1 - ypos1);
  1082.     xshf = xpos1 & 7;
  1083.     x1 = (xpos1 < 0) ? ~((~xpos1) >> 3) : xpos1 >> 3;
  1084.     x2 = x1 + pfcrec->xbytes;
  1085.     if (x1 < 0)
  1086.     {   cbuf -= x1;
  1087.         x1 = 0;
  1088.     }
  1089.     if (x2 > gstate.dev.xbytes)
  1090.         x2 = gstate.dev.xbytes;
  1091.     if (x1 >= x2) return;
  1092.     xx = x2 - x1;
  1093.  
  1094.     /* Loop through the bit planes */
  1095.  
  1096.     hscreen = &halfscreen[0];
  1097.     for (plane = 0; plane < gstate.dev.depth; plane++, hscreen++)
  1098.     {   htone = hscreen->halftone;
  1099.         cbeg = cbuf;
  1100.         dbeg = gstate.dev.buf[plane] +
  1101.             (y1 - gstate.dev.ybase) * gstate.dev.xbytes + x1;
  1102.         yy = y1;
  1103.  
  1104.         /* Optimise black or white */
  1105.  
  1106.         if      (hscreen->num == 0)
  1107.         {   while (yy < y2)
  1108.             {   dptr1 = dbeg;
  1109.                 dptr2 = dbeg + xx;
  1110.                 cptr = cbeg;
  1111.  
  1112.                 ilast = 0;
  1113.                 if (xpos1 < 0) ilast = *(cptr - 1) << 8;
  1114.  
  1115.                 for (;;)
  1116.                 {   *dptr1++ |=  ((ilast | *cptr) >> xshf);
  1117.                     ilast = *cptr++ << 8;
  1118.                     if (dptr1 == dptr2) break;
  1119.                 }
  1120.  
  1121.                 if (x2 < gstate.dev.xbytes)
  1122.                     *dptr1   |=  ( ilast          >> xshf);
  1123.                 cbeg += pfcrec->xbytes;
  1124.                 dbeg += gstate.dev.xbytes;
  1125.                 yy++;
  1126.             }
  1127.         }
  1128.         else if (hscreen->num == htone->area)
  1129.         {   while (yy < y2)
  1130.             {   dptr1 = dbeg;
  1131.                 dptr2 = dbeg + xx;
  1132.                 cptr = cbeg;
  1133.  
  1134.                 ilast = 0;
  1135.                 if (xpos1 < 0) ilast = *(cptr - 1) << 8;
  1136.  
  1137.                 for (;;)
  1138.                 {   *dptr1++ &= ~((ilast | *cptr) >> xshf);
  1139.                     ilast = *cptr++ << 8;
  1140.                     if (dptr1 == dptr2) break;
  1141.                 }
  1142.  
  1143.                 if (x2 < gstate.dev.xbytes)
  1144.                     *dptr1   &= ~( ilast          >> xshf);
  1145.                 cbeg += pfcrec->xbytes;
  1146.                 dbeg += gstate.dev.xbytes;
  1147.                 yy++;
  1148.             }
  1149.         }
  1150.  
  1151.         /* The general case needs a halftone screen */
  1152.  
  1153.         else
  1154.         {   hxsize = htone->xsize;
  1155.             xbeg = x1 % htone->xsize;
  1156.             ymod = yy % htone->ysize;
  1157.             hbeg = hscreen->ptr + ymod * hxsize;
  1158.             while (yy < y2)
  1159.             {   dptr1 = dbeg;
  1160.                 dptr2 = dbeg + xx;
  1161.                 cptr = cbeg;
  1162.                 xmod = xbeg;
  1163.                 hptr = hbeg + xbeg;
  1164.  
  1165.                 ilast = 0;
  1166.                 if (xpos1 < 0) ilast = *(cptr - 1) << 8;
  1167.  
  1168.                 for (;;)
  1169.                 {   ibyte = (ilast | *cptr) >> xshf;
  1170.                     *dptr1 = (*dptr1 & ~ibyte) | (*hptr++ &  ibyte);
  1171.                     dptr1++;
  1172.                     ilast = *cptr++ << 8;
  1173.                     xmod++;
  1174.                     if (xmod == hxsize)
  1175.                     {   xmod = 0;
  1176.                         hptr = hbeg;
  1177.                     }
  1178.                     if (dptr1 == dptr2) break;
  1179.                 }
  1180.  
  1181.                 if (x2 < gstate.dev.xbytes)
  1182.                 {   ibyte =  ilast          >> xshf;
  1183.                     *dptr1 = (*dptr1 & ~ibyte) | (*hptr   &  ibyte);
  1184.                 }
  1185.                 cbeg += pfcrec->xbytes;
  1186.                 dbeg += gstate.dev.xbytes;
  1187.                 hbeg += hxsize;
  1188.                 ymod++;
  1189.                 if (ymod == htone->ysize)
  1190.                 {   ymod = 0;
  1191.                     hbeg = hscreen->ptr;
  1192.                 }
  1193.                 yy++;
  1194.             }
  1195.         }
  1196.     }
  1197. }
  1198.  
  1199. /* End of file "postchar.c" */
  1200.