/*
 *   Code to download a font definition at the beginning of a section.
 * hacked by SPQR 8.95 to allow for non-partial downloading
 *
 */
#include "dvips.h" /* The copyright notice in that file is included too! */
#ifndef DOWNLOAD_USING_PDFTEX
#define DOWNLOAD_USING_PDFTEX
#endif
#ifndef DOWNLOAD_USING_PDFTEX
#include "t1part.h"
#endif
#define DVIPS
/*
 *   These are the external routines we call.
 */
#include "protos.h"
/*
 *   These are the external variables we access.
 */
extern char *nextstring, *infont ;
extern FILE *bitfile ;
extern fontdesctype *curfnt ;
extern long bytesleft ;
extern long mbytesleft ;
extern quarterword *raster ;
extern quarterword *mraster ;
extern Boolean compressed ;
extern Boolean partialdownload ;
extern double mag ;
extern int actualdpi ;
static unsigned char dummyend[8] = { 252 } ;
extern int prettycolumn ;
extern int quiet ;
extern Boolean disablecomments ;
extern real conv ;

/*
 *   We have a routine that downloads an individual character.
 */
static int lastccout ;
void downchar (chardesctype *c, shalfword cc)
{
   register long i, j ;
   register halfword cheight, cwidth ;
   register long k ;
   register quarterword *p ;
   register halfword cmd ;
   register shalfword xoff, yoff ;
   halfword wwidth = 0 ;
   register long len ;
   int smallchar ;

   p = c->packptr ;
   cmd = *p++ ;
   if (cmd & 4) {
      if ((cmd & 7) == 7) {
         cwidth = getlong(p) ;
         cheight = getlong(p + 4) ;
         xoff = getlong(p + 8) ;
         yoff = getlong(p + 12) ;
         p += 16 ;
      } else {
         cwidth = p[0] * 256 + p[1] ;
         cheight = p[2] * 256 + p[3] ;
         xoff = p[4] * 256 + p[5] ; /* N.B.: xoff, yoff are signed halfwords */
         yoff = p[6] * 256 + p[7] ;
         p += 8 ;
      }
   } else {
      cwidth = *p++ ;
      cheight = *p++ ;
      xoff = *p++ ;
      yoff = *p++ ;
      if (xoff > 127)
         xoff -= 256 ;
      if (yoff > 127)
         yoff -= 256 ;
   }
   if (c->flags & BIGCHAR)
      smallchar = 0 ;
   else
      smallchar = 5 ;
   if (compressed) {
      len = getlong(p) ;
      p += 4 ;
   } else {
      wwidth = (cwidth + 15) / 16 ;
      i = 2 * cheight * (long)wwidth ;
      if (i <= 0)
         i = 2 ;
      i += smallchar ;
      if (mbytesleft < i) {
         if (mbytesleft >= RASTERCHUNK)
            (void) free((char *) mraster) ;
         if (RASTERCHUNK > i) {
            mraster = (quarterword *)mymalloc((integer)RASTERCHUNK) ;
            mbytesleft = RASTERCHUNK ;
         } else {
            k = i + i / 4 ;
            mraster = (quarterword *)mymalloc((integer)k) ;
            mbytesleft = k ;
         }
      }
      k = i;
      while (k > 0)
         mraster[--k] = 0 ;
      unpack(p, (halfword *)mraster, cwidth, cheight, cmd) ;
      p = mraster ;
      len = i - smallchar ;
   }
   if (cheight == 0 || cwidth == 0 || len == 0) {
      cwidth = 1 ;
      cheight = 1 ;
      wwidth = 1 ;
      len = 2 ;
      if (compressed)
         p = dummyend ;  /* CMD(END); see repack.c */
      else
         mraster[0] = 0 ;
   }
   if (smallchar) {
      p[len] = cwidth ;
      p[len + 1] = cheight ;
      p[len + 2] = xoff + 128 ;
      p[len + 3] = yoff + 128 ;
      p[len + 4] = c->pixelwidth ;
   } else
/*
 *   Now we actually send out the data.
 */
      specialout('[') ;
   if (compressed) {
      specialout('<') ;
      mhexout(p, len + smallchar) ;
      specialout('>') ;
   } else {
      i = (cwidth + 7) / 8 ;
      if (i * cheight > 65520) {
         long bc = 0 ;
         specialout('<') ;
         for (j=0; j<cheight; j++) {
            if (bc + i > 65520) {
               specialout('>') ;
               specialout('<') ;
               bc = 0 ;
            }
            mhexout(p, i) ;
            bc += i ;
            p += 2*wwidth ;
         }
         specialout('>') ;
      } else {
         specialout('<') ;
         if (2 * wwidth == i)
            mhexout(p, ((long)cheight) * i + smallchar) ;
         else {
            for (j=0; j<cheight; j++) {
               mhexout(p, i) ;
               p += 2*wwidth ;
            }
            if (smallchar)
               mhexout(p, (long)smallchar) ;
         }
         specialout('>') ;
      }
   }
   if (smallchar == 0) {
      numout((integer)cwidth) ;
      numout((integer)cheight) ;
      numout((integer)xoff + 128) ; /* not all these casts needed. */
      numout((integer)yoff + 128) ;
      numout((integer)(c->pixelwidth)) ;
   }
   if (lastccout + 1 == cc) {
      cmdout("I") ;
   } else {
      numout((integer)cc) ;
      cmdout("D") ;
   }
   lastccout = cc ;
}
/*
 * Output the literal name of the font change command with PostScript index n
 */
static char goodnames[] =
   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" ;
void
makepsname (register char *s, register int n)
{
   n-- ;
   *s++ = 'F' + n / (sizeof(goodnames)-1) ;
   *s++ = goodnames[n % (sizeof(goodnames)-1)] ;
   *s++ = 0 ;
}
void
lfontout (int n)
{
        char buf[10];
        char *b = buf ;
        *b++ = '/' ;
        makepsname(b, n) ;
        cmdout(buf);
}

/*
 *   And the download procedure.
 */
void download (charusetype *p, int psfont)
{
   register int b, i ;
   register halfword bit ;
   register chardesctype *c ;
   int cc, maxcc = -1, numcc ;
   double fontscale ;
   char name[10] ;
   lastccout = -5 ;
   name[0] = '/' ;
   makepsname(name + 1, psfont) ;
   curfnt = p->fd ;
   curfnt->psname = psfont ;
   if (curfnt->resfont) {
      struct resfont *rf = curfnt->resfont ;
      int non_empty=0;
      for (b=0; b<16; b++)
        if(p->bitmap[b] !=0)
            non_empty =1;
      if(non_empty==0 && curfnt->iswide == 0 && curfnt->codewidth==1)
        return;
      cmdout(name) ;
/* following code re-arranged - Rob Hutchings 1992Apr02 */
      c = curfnt->chardesc + 255 ;
      cc = 255 ;
      numcc = 0 ;
      i = 0 ;
      for (b=15; b>=0; b--) {
         for (bit=1; bit; bit<<=1) {
             if (p->bitmap[b] & bit) {
               if (i > 0) {
                  numout((integer)i) ;
                  specialout('[') ;
                  i = 0 ;
               }
               numout((integer)c->pixelwidth) ;
               c->flags |= EXISTS ;
               numcc++ ;
            } else {
               i++ ;
               c->flags &= ~EXISTS ;
            }
            c-- ;
            cc-- ;
         }
      }
      if (i > 0) {
         numout((integer)i) ;
         specialout('[') ;
      }
      specialout ('{') ;
      if (rf->specialinstructions)
         cmdout(rf->specialinstructions) ;
      specialout ('}') ;
      numout((integer)numcc) ;
      /*
       *   This code has been bogus for a long time.  The fix is
       *   straightforward.  The input, curfnt->scaledsize, is the
       *   desired size of the font in dvi units.  The output is the
       *   fontscale, which is the height of the font in output units
       *   which are simply pixels.  Thus, all we need to do is multiply
       *   by the default generic conv, which properly takes into
       *   account magnification, num/den, output resolution, and so on.
       *   Sorry this bug has been in here so long.   -tgr
       */
      fontscale = curfnt->scaledsize * conv ;
      (void)sprintf(nextstring, "%g", fontscale) ;
      cmdout(nextstring) ;
      (void)strcpy(nextstring, "/") ;
      (void)strcat(nextstring, rf->PSname) ;
      cmdout(nextstring) ;
/* end of changed section - Rob */
      cmdout("rf") ;
      rf->sent = 1 ;
      return ;
   }
/*
 *   Here we calculate the largest character actually used, and
 *   send it as a parameter to df.
 */
   cc = 0 ;
   numcc = 0 ;
   for (b=0; b<16; b++) {
      for (bit=32768; bit!=0; bit>>=1) {
         if (p->bitmap[b] & bit) {
            maxcc = cc ;
            numcc++ ;
         }
         cc++ ;
      }
   }
   if (numcc <= 0)
      return ;
   fontscale = ((double)(curfnt->scaledsize)) / 65536.0 ;
   fontscale *= (mag/1000.0) ;
   newline() ;
   fprintf(bitfile, "%%DVIPSBitmapFont: %s %s %g %d\n", name+1, curfnt->name,
                     fontscale, numcc) ;
   cmdout(name) ;
   numout((integer)numcc) ;
   numout((integer)maxcc + 1) ;
/*
 *   If we need to scale the font, we say so by using dfs
 *   instead of df, and we give it a scale factor.  We also
 *   scale the character widths; this is ugly, but scaling
 *   fonts is ugly, and this is the best we can probably do.
 */
   if (curfnt->dpi != curfnt->loadeddpi) {
      numout((integer)curfnt->dpi) ;
      numout((integer)curfnt->loadeddpi) ;
      if (curfnt->alreadyscaled == 0) {
         for (b=0, c=curfnt->chardesc; b<256; b++, c++)
            c->pixelwidth = (c->pixelwidth * 
      (long)curfnt->dpi * 2 + curfnt->loadeddpi) / (2 * curfnt->loadeddpi) ;
         curfnt->alreadyscaled = 1 ;
      }
      cmdout("dfs") ;
   } else
      cmdout("df") ;
   c = curfnt->chardesc ;
   cc = 0 ;
   for (b=0; b<16; b++) {
      for (bit=32768; bit; bit>>=1) {
         if (p->bitmap[b] & bit) {
            downchar((chardesctype *)c, (shalfword)cc) ;
            c->flags |= EXISTS ;
         } else
            c->flags &= ~EXISTS ;
         c++ ;
         cc++ ;
      }
   }
   cmdout("E") ;
   newline() ;
   fprintf(bitfile, "%%EndDVIPSBitmapFont\n") ;
}

#ifdef VFLIB
void downvffont (charusetype *p, charusetype *all)
{
  register int b;
  register halfword bit ;
  register chardesctype *c ;
  struct resfont *rf ;
  int cc;
  int unuminfo[256][2], unumcc, lastunum, curunum, curlnum, jiscc;
  halfword bitmap[553] ;
  int vffd;

  curfnt = p->fd ;
  rf = curfnt->resfont ;
  if (rf == 0 || rf->Fontfile == NULL)
    return ;
  for (; all->fd; all++)
    if (all->fd->resfont &&
        strcmp(rf->PSname, all->fd->resfont->PSname) == 0)
      break ;
  if (all != p)
    return ;
  if (all->fd == 0)
    error("! internal error in downpsfont") ;
/* This never happens.
    if (!partialdownload) {
        infont = all->fd->resfont->PSname ;
        copyfile(all->fd->resfont->Fontfile);
        infont = 0 ;
        return;
    }
*/
  for (b=0; b<553; b++)
    bitmap[b] = 0 ;
  for (b=0; b<256; b++)
    unuminfo[b][0] = unuminfo[b][1] = 0;
  for (; all->fd; all++) {
    if (all->fd->resfont == 0 ||
        strcmp(rf->PSname, all->fd->resfont->PSname))
      continue ;
    cc = 0 ;
    for (b=0; b<553; b++) {
      for (bit=32768; bit!=0 && cc<MAX_CODE; bit>>=1) {
        if (all->bitmap[b] & bit)
          bitmap[b] |= bit;
      }
      cc++ ;
    }
  }

  cc = 0;
  unumcc = 0;
  curunum = curlnum = lastunum = -1;
  for (b=0; b<553; b++) {
    for (bit=32768; bit!=0 && cc<MAX_CODE; bit>>=1) {
      if (bitmap[b] & bit) {
        jiscc = CCTOJIS(cc);
        curunum = jiscc>>8;
        curlnum = jiscc & 0xff;
/*        fprintf(stderr, "curunum:%d\n", curunum);
        fprintf(stderr, "curlnum:%d\n", curlnum); */
        unuminfo[curunum][0]++ ;             /* numcc */
        if (unuminfo[curunum][1] < curlnum) {
          unuminfo[curunum][1] = curlnum; /* maxcc */
        }
        if (lastunum != curunum) {
          lastunum = curunum;
          unumcc++;
        }
      }
      cc++;
    }
  }

/*  fprintf(stderr, "unumcc:%d\n", unumcc); */
  if (unumcc <= 0)
    return;

  if (!quiet) {
    if (strlen(rf->Fontfile) + prettycolumn > STDOUTSIZE) {
      fprintf(stderr, "\n") ;
      prettycolumn = 0 ;
    }
    (void)fprintf(stderr, "<%s>", rf->Fontfile);
    prettycolumn += strlen(rf->Fontfile) + 2 ;
  }
  if (! disablecomments)
    (void)fprintf(bitfile, "%%%%BeginFont: %s\n", rf->PSname);
  cmdout("TeXDict begin");
/* composite font */
  (void)strcpy(nextstring, "/") ;
  (void)strcat(nextstring, rf->PSname) ;
  cmdout(nextstring) ;
  numout((integer)unumcc);
  if (curfnt->dir) {
    /* WMode */
    numout((integer)1);
  }
  else
    numout((integer)0);
  cmdout("Vdf");
  cc = 0;
  lastunum = curunum = -1;
  /* base font */
  if ((vffd = VF_OpenFont(rf->Fontfile))<0) {
    extern char errbuf[];
    sprintf(errbuf, "! Failed to open font %s.", curfnt->name);
    error(errbuf);
  }
  for (b=0; b<553; b++) {
    for (bit=32768; bit!=0 && cc<MAX_CODE; bit>>=1) {
      if (bitmap[b] & bit){
        jiscc = CCTOJIS(cc);
        curunum = jiscc>>8;
        if (lastunum != curunum) {
          if (lastunum != -1) cmdout("VE");
          lastunum = curunum;
          numout((integer)curunum);
          numout((integer)unuminfo[curunum][0]);
          numout((integer)(unuminfo[curunum][1]+1));
          cmdout("Vsdf");
        }
        /*         fprintf(stderr, "Downloading VFchar %s 0x%02x\n",
                   curfnt->vfname, CCTOJIS(cc)); */
        downvfchar(vffd, jiscc, curfnt->dir);
      }
      cc++ ;
    }
  }
  VF_CloseFont(vffd);
  cmdout("VE");
  cmdout("VEE");
  cmdout("end");
  if (! disablecomments) {
    (void)fprintf(bitfile, "\n");
    (void)fprintf(bitfile, "%%%%EndFont \n");
  }
}
#endif
/*
 *   Magic code to deal with PostScript font partial downloading.
 *   We track the encodings we've seen so far and keep them in these
 *   structures.  We rely on writet1 to load the encodings for us.
 */
static struct seenEncodings {
   struct seenEncodings *next ;
   char *name ;
   char **glyphs ;
} *seenEncodings ;
#define MAX_CHAR_CODE 256
/*
 *   Load a new encoding and return the array of glyphs as a vector.
 *   Linear search.
 */
static char **getEncoding(char *encoding) {
   struct seenEncodings *p = seenEncodings ;
   while (p != 0)
      if (strcmp(encoding, p->name) == 0)
         break ;
      else
         p = p->next ;
   if (p == 0) {
      int i ;
      p = (struct seenEncodings *)mymalloc(sizeof(struct seenEncodings)) ;
      p->next = seenEncodings ;
      seenEncodings = p ;
      p->name = xstrdup(encoding) ;
      p->glyphs = (char **)mymalloc((MAX_CHAR_CODE+1) * sizeof(char *)) ;
      for (i=0; i<MAX_CHAR_CODE; i++)
         p->glyphs[i] = ".notdef" ;
      load_enc(encoding, p->glyphs) ;
   }
   return p->glyphs ;
}
/*
 *   When partially downloading a type 1 font, sometimes the font uses
 *   the built-in encoding (which we don't know at this point) so we want
 *   to subset it by character code.  Sometimes the font uses a different
 *   encoding, so we want to subset it by glyph.  These routines manage
 *   accumulating all the glyph names for a particular font from all
 *   the various uses into a single, slash-delimited string for writet1().
 *
 *   If no glyphs have been added, extraGlyphs is null.  In all cases,
 *   the memory allocated for this is in extraGlyphSpace.
 */
static char *extraGlyphs = 0 ;
#ifdef DOWNLOAD_USING_PDFTEX
static char *extraGlyphSpace = 0 ;
static int extraGlyphSize = 0 ;
static int glyphSizeUsed = 0 ;
/*
 *   We want to make sure we pass in null or "/" but never "".  
 */
static void clearExtraGlyphList() {
   glyphSizeUsed = 0 ;
   extraGlyphs = 0 ;
}
/*
 *   Add the glyph name; make sure it hasn't been added already.
 *   We do this by adding it, so we can get the // around it,
 *   and *then* see if it's already there and if it is un-add it.
 */
static void addGlyph(char *glyphName) {
   int len = strlen(glyphName) ;
   char *startOfAdd = 0 ;
   if (len + glyphSizeUsed + 3 > extraGlyphSize) {
      extraGlyphSize = 2 * (extraGlyphSize + len + 100) ;
      extraGlyphSpace = (char *) xrealloc(extraGlyphSpace, extraGlyphSize) ;
   }
   extraGlyphs = extraGlyphSpace ;
   if (glyphSizeUsed == 0) {
      startOfAdd = extraGlyphs + glyphSizeUsed ;
      extraGlyphs[glyphSizeUsed++] = '/' ; /* leading / */
   } else {
      startOfAdd = extraGlyphs + glyphSizeUsed - 1 ;
   }
   strcpy(extraGlyphs + glyphSizeUsed, glyphName) ;
   glyphSizeUsed += len ;
   extraGlyphs[glyphSizeUsed++] = '/' ;    /* trailing / */
   extraGlyphs[glyphSizeUsed] = 0 ;
   if (strstr(extraGlyphs, startOfAdd) != startOfAdd) { /* already there! */
      glyphSizeUsed = startOfAdd - extraGlyphs + 1 ; /* kill the second copy */
      extraGlyphs[glyphSizeUsed] = 0 ;
   }
}
#endif
/*
 *   Download a PostScript font, using partial font downloading if
 *   necessary.
 */
extern char *downloadedpsnames[];
extern int unused_top_of_psnames;

void downpsfont (charusetype *p, charusetype *all)
{
#ifdef DOWNLOAD_USING_PDFTEX
    static unsigned char grid[256];
#endif
    int GridCount ;
    register int b;
    register halfword bit ;
    register chardesctype *c ;
    struct resfont *rf ;
    int cc;
    extern char *realnameoffile ;
    int j;

    curfnt = p->fd ;
    rf = curfnt->resfont ;
    if (rf == 0 || rf->Fontfile == NULL)
       return ;
    for (; all->fd; all++)
       if (all->fd->resfont &&
           strcmp(rf->PSname, all->fd->resfont->PSname) == 0)
          break ;
    if (all != p)
       return ;
    if (rf->sent == 2) /* sent as header, from a PS file */
       return ;
    for (j=0; downloadedpsnames[j] && j < unused_top_of_psnames; j++) {
       if (strcmp (downloadedpsnames[j], rf->PSname) == 0)
          return;
    }
    if (all->fd == 0)
       error("! internal error in downpsfont") ;
    if (!partialdownload) {
        infont = all->fd->resfont->PSname ;
        copyfile(all->fd->resfont->Fontfile);
        infont = 0 ;
        return;
    }
    for (cc=0; cc<256; cc++)
       grid[cc] = 0 ;
#ifdef DOWNLOAD_USING_PDFTEX
    clearExtraGlyphList() ;
#endif
    for (; all->fd; all++) {
        if (all->fd->resfont == 0 ||
            strcmp(rf->PSname, all->fd->resfont->PSname))
           continue ;
        curfnt = all->fd ;
#ifdef DOWNLOAD_USING_PDFTEX
        if (curfnt->resfont->Vectfile) {
           char **glyphs = getEncoding(curfnt->resfont->Vectfile) ;
           c = curfnt->chardesc + 255 ;
           cc = 255 ;
           for (b=15; b>=0; b--) {
               for (bit=1; bit; bit<<=1) {
                   if (all->bitmap[b] & bit) {
                      addGlyph(glyphs[cc]) ;
                   }
                   c-- ;
                   cc-- ;
               }
            }
        } else {
#endif
           c = curfnt->chardesc + 255 ;
           cc = 255 ;
           for (b=15; b>=0; b--) {
               for (bit=1; bit; bit<<=1) {
                   if (all->bitmap[b] & bit) {
                       grid[cc]=1;
                   }
                   c-- ;
                   cc-- ;
               }
            }
#ifdef DOWNLOAD_USING_PDFTEX
        }
#endif
    }

    for (GridCount=0,cc=0; cc<256; cc++) {
/*      tmpgrid[cc]=grid[cc]; */
        if(grid[cc] ==1) {
            GridCount++;
        }
    }
    if(GridCount!=0 || extraGlyphs) {
        newline() ;
        if (! disablecomments)
           (void)fprintf(bitfile, "%%%%BeginFont: %s\n",  rf->PSname);
#ifdef DOWNLOAD_USING_PDFTEX
        if (!t1_subset_2(rf->Fontfile, grid, extraGlyphs))
#else
        if(FontPart(bitfile, rf->Fontfile, rf->Vectfile) < 0)
#endif
            exit(1);
        if (!quiet) {
           if (strlen(realnameoffile) + prettycolumn > STDOUTSIZE) {
              fprintf(stderr, "\n") ;
              prettycolumn = 0 ;
           }
           (void)fprintf(stderr, "<%s>", realnameoffile);
           prettycolumn += strlen(realnameoffile) + 2 ;
        }
        if (! disablecomments)
           (void)fprintf(bitfile, "%%%%EndFont \n");
   }
}

void dopsfont (sectiontype *fs)
{
    charusetype *cu ;

    cu = (charusetype *) (fs + 1) ;
#ifdef DOWNLOAD_USING_PDFTEX
    while (cu->fd) {
       if (cu->psfused)
          cu->fd->psflag = EXISTS ;
#ifdef VFLIB
       if (cu->fd->vflib) {
         downvffont(cu++, (charusetype *)(fs + 1));
       }
       else
#endif
       downpsfont(cu++, (charusetype *)(fs + 1)) ;
    }
#else
    line = getmem(BUFSIZ);
    tmpline=line;
    while (cu->fd) {
       if (cu->psfused)
          cu->fd->psflag = EXISTS ;
#ifdef VFLIB
       if (cu->fd->vflib) {
         downvffont(cu++, (charusetype *)(fs + 1));
       }
       else
#endif
       downpsfont(cu++, (charusetype *)(fs + 1)) ;
    }
    loadbase = ~FLG_LOAD_BASE;
    FirstCharB=UnDefineChars(FirstCharB);
    free(tmpline);
#endif
}
