/* $Id: splinesave.c 5989 2018-04-05 17:42:29Z mskala $ */
/* Copyright (C) 2000-2012  George Williams
 * Copyright (C) 2015, 2018  Matthew Skala
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * The name of the author may not be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "fontanvil.h"
#include <stdio.h>
#include <math.h>
#include "splinefont.h"
#include "psfont.h"
#include <ustring.h>
#include <string.h>
#include <utype.h>

int autohint_before_generate=1;

/* Let's talk about references. */
/* If we are doing Type1 output, then the obvious way of doing them is seac */
/*  but that's so limitting. It only works for exactly two characters both */
/*  of which are in Adobe's Standard Enc. Only translations allowed. Only */
/*  one reference may be translated and the width of the char must match */
/*  that of the non-translated reference */
/*   The first extension we can make is to allow a single character reference */
/*  by making the other character be a space */
/*   But if we want to do more than that we must use subrs. If we have two */
/*  refs in subrs then we can do translations by preceding the subr calls by */
/*  appropriate rmovetos. Actually the specs say that only one rmoveto should */
/*  precede a path, so that means we can't allow the subroutines to position */
/*  themselves, they must just assume that they are called with the current */
/*  position correct for the first point. But then we need to know where the */
/*  first point should be placed, so we allocate a BasePoint to hold that info*/
/*  and store it into the "keys" array (which the subrs don't use). Similarly */
/*  we need to know where the subr will leave us, so we actually allocate 2 */
/*  BasePoints, one containing the start point, one the end point */
/*   But that's still not good enough, hints are defined in such a way that */
/*  they are not relocateable. So our subrs can't include any hint definitions*/
/*  (or if they do then that subr can't be translated at all). So hints must */
/*  be set outside the subrs, and the subrs can't be for chars that need hint */
/*  substitution. Unless... The subr will never be relocated. */
/*   So we generate two types of reference subrs, one containing no hints, the*/
/*  other containing all the hints, stems and flexes. The first type may be */
/*  translated, the second cannot */
/* Type2 doesn't allow any seacs */
/*  So everything must go in subrs. We have a slightly different problem here:*/
/*  hintmasks need to know exactly how many stem hints there are in the char */
/*  so we can't include any hintmask operators inside a subr (unless we */
/*  guarantee that all invocations of that subr are done with the same number */
/*  of hints in the character). This again means that no char with hint subs- */
/*  titutions may be put in a subr. UNLESS all the other references in a */
/*  refering character contain no hints */

/* That's very complex. And it doesn't do a very good job. */
/* Instead let's take all strings bounded by either moveto or hintmask operators */
/*  store these as potential subroutines. So a glyph becomes a sequence of    */
/*  potential subroutine calls preceded by the glyph header (width, hint decl,*/
/*  counter declarations, etc.) and intersperced by hintmask/moveto operators */
/* Each time we get a potential subr we hash it and see if we've used that    */
/*  string before. If we have then we merge the two. Otherwise it's a new one.*/
/* Then at the end we see what strings get used often enough to go into subrs */
/*  we create the subrs array from that.				      */
/* Then each glyph. We insert the preamble. We check of the potential subroutine */
/*  became a real subroutine. If so we call it, else we insert the data inline*/
/*  Do the same for the next hintmask/moveto and potential subroutine...      */

/* Then, on top of that I tried generating some full glyph subroutines, and   */
/*  to my surprise, it just made things worse.                                */

struct potentialsubrs {
   uint8_t *data;			/* the charstring of the subr */
   int len;			/* the length of the charstring */
   int idx;			/* initially index into psubrs array */
   /*  then index into subrs array or -1 if none */
   int cnt;			/* the usage count */
   int fd;			/* Which sub font is it in */
   /* -1 => used in more than one */
   int next;
   int full_glyph_index;	/* Into the glyphbits array */
   /* for full references */
   BasePoint *startstop;	/* Again for full references */
};

struct bits {
   uint8_t *data;
   int dlen;
   int psub_index;
};

struct glyphbits {
   SplineChar *sc;
   int fd;			/* Which subfont is it in */
   int bcnt;
   struct bits *bits;
   uint8_t wasseac;
};

#define HSH_SIZE	511
/* In type2 charstrings we divide every character into bits where a bit is */
/* bounded by a hintmask/moveto. Each of these is a potential subroutine and */
/* is stored here */
typedef struct glyphinfo {
   struct potentialsubrs *psubrs;
   int pcnt, pmax;
   int hashed[HSH_SIZE];
   struct glyphbits *gb, *active;
   SplineFont *sf;
   int layer;
   int glyphcnt;
   int subfontcnt;
   int bcnt, bmax;
   struct bits *bits;		/* For current glyph */
   const int *bygid;
   int justbroken;
   int instance_count;
} GlyphInfo;

struct mhlist {
   uint8_t mask[HntMax/8];
   int subr;
   struct mhlist *next;
};

struct hintdb {
   uint8_t mask[HntMax/8];
   int cnt;			/* number of hints */
   struct mhlist *sublist;
   struct pschars *subrs;
   /*SplineChar *sc; */
   SplineChar **scs;
   int instance_count;
   unsigned int iscjk:1;	/* If cjk then don't do stem3 hints */
   /* Will be done with counters instead */
   /* actually, most of the time we can't use stem3s, only if those three */
   /* stems are always active and there are no other stems !(h/v)hasoverlap */
   unsigned int noconflicts:1;
   unsigned int startset:1;
   unsigned int skiphm:1;	/* Set when coming back to the start point of a contour. hintmask should be set the first time, not the second */
   unsigned int donefirsthm:1;
   int cursub;			/* Current subr number */
   DBasePoint current;
   GlyphInfo *gi;
};

static void GIContentsFree(GlyphInfo *gi,SplineChar *dummynotdef) {
   int i, j;

   if (gi->glyphcnt>0 && gi->gb[0].sc==dummynotdef) {
      if (dummynotdef->layers != NULL) {
	 SplinePointListsFree(dummynotdef->layers[gi->layer].splines);
	 dummynotdef->layers[gi->layer].splines=NULL;
      }
      StemInfosFree(dummynotdef->hstem);
      StemInfosFree(dummynotdef->vstem);
      dummynotdef->vstem=dummynotdef->hstem=NULL;
      free(dummynotdef->layers);
      dummynotdef->layers=NULL;
   }

   for (i=0; i<gi->pcnt; ++i) {
      free(gi->psubrs[i].data);
      free(gi->psubrs[i].startstop);
      gi->psubrs[i].data=NULL;
      gi->psubrs[i].startstop=NULL;
   }
   for (i=0; i<gi->glyphcnt; ++i) {
      for (j=0; j<gi->gb[i].bcnt; ++j)
	 free(gi->gb[i].bits[j].data);
      free(gi->gb[i].bits);
      gi->gb[i].bits=NULL;
      gi->gb[i].bcnt=0;
   }

   gi->pcnt=0;
   gi->bcnt=0;
   gi->justbroken=0;
}

static void GIFree(GlyphInfo *gi,SplineChar *dummynotdef) {

   GIContentsFree(gi, dummynotdef);

   free(gi->gb);
   free(gi->psubrs);
   free(gi->bits);
}

static void StartNextSubroutine(GrowBuf *gb,struct hintdb *hdb) {
   GlyphInfo *gi;

   if (hdb==NULL)
      return;
   gi=hdb->gi;
   if (gi==NULL)
      return;
   /* Store everything in the grow buf into the data/dlen of the next bit */
   if (gi->bcnt==-1)
      gi->bcnt=0;
   if (gi->bcnt >= gi->bmax)
      gi->bits=realloc(gi->bits, (gi->bmax += 20)*sizeof(struct bits));
   gi->bits[gi->bcnt].dlen=gb->pt-gb->base;
   gi->bits[gi->bcnt].data=malloc(gi->bits[gi->bcnt].dlen);
   gi->bits[gi->bcnt].psub_index=-1;
   memcpy(gi->bits[gi->bcnt].data, gb->base, gi->bits[gi->bcnt].dlen);
   gb->pt=gb->base;
   gi->justbroken=false;
}

static int hashfunc(uint8_t *data,int len) {
   uint8_t *end=data+len;
   unsigned int hash=0, r;

   while (data<end) {
      r=(hash >> 30)&3;
      hash <<= 2;
      hash=(hash|r)&0xffffffff;
      hash ^= *data++;
   }
   return (hash%HSH_SIZE);
}

static void BreakSubroutine(GrowBuf *gb,struct hintdb *hdb) {
   GlyphInfo *gi;
   struct potentialsubrs *ps;
   int hash;
   int pi;

   if (hdb==NULL)
      return;
   gi=hdb->gi;
   if (gi==NULL)
      return;
   /* The stuff before the first moveto in a glyph (the header that sets */
   /*  the width, sets up the hints, counters, etc.) can't go into a subr */
   if (gi->bcnt==-1) {
      gi->bcnt=0;
      gi->justbroken=true;
      return;
   } else if (gi->justbroken)
      return;
   /* Otherwise stuff everything in the growbuffer into a subr */
   hash=hashfunc(gb->base, gb->pt-gb->base);
   ps=NULL;
   for (pi=gi->hashed[hash]; pi != -1; pi=gi->psubrs[pi].next) {
      ps=&gi->psubrs[pi];
      if (ps->len==gb->pt-gb->base
	  && memcmp(ps->data, gb->base, gb->pt-gb->base)==0)
	 break;
   }
   if (pi==-1) {
      if (gi->pcnt >= gi->pmax)
	 gi->psubrs =
	    realloc(gi->psubrs,
		    (gi->pmax +=
		     gi->glyphcnt)*sizeof(struct potentialsubrs));
      ps=&gi->psubrs[gi->pcnt];
      memset(ps, 0, sizeof(*ps));	/* set cnt to 0 */
      ps->idx=gi->pcnt++;
      ps->len=gb->pt-gb->base;
      ps->data=malloc(ps->len);
      memcpy(ps->data, gb->base, ps->len);
      ps->next=gi->hashed[hash];
      gi->hashed[hash]=ps->idx;
      ps->fd=gi->active->fd;
      ps->full_glyph_index=-1;
   }
   if (ps->fd != gi->active->fd)
      ps->fd=-1;		/* used in multiple cid sub-fonts */
   gi->bits[gi->bcnt].psub_index=ps->idx;
   ++ps->cnt;
   gb->pt=gb->base;
   ++gi->bcnt;
   gi->justbroken=true;
}

static void MoveSubrsToChar(GlyphInfo *gi) {
   struct glyphbits *active;

   if (gi==NULL)
      return;
   active=gi->active;
   active->bcnt=gi->bcnt;
   active->bits=malloc(active->bcnt * sizeof(struct bits));
   memcpy(active->bits, gi->bits, active->bcnt * sizeof(struct bits));
   gi->bcnt=0;
}

static int NumberHints(SplineChar *scs[MmMax],int instance_count) {
   int i, j, cnt=-1;
   StemInfo *s;

   for (j=0; j<instance_count; ++j) {
      for (s=scs[j]->hstem, i=0; s != NULL; s=s->next) {
	 if (i<HntMax)
	    s->hintnumber=i++;
	 else
	    s->hintnumber=-1;
      }
      for (s=scs[j]->vstem; s != NULL; s=s->next) {
	 if (i<HntMax)
	    s->hintnumber=i++;
	 else
	    s->hintnumber=-1;
      }
      if (cnt==-1)
	 cnt=i;
      else if (cnt != i)
	 ErrorMsg(2,"MM font with different hint counts\n");
   }
   return (cnt);
}

static void MarkTranslationRefs(SplineFont *sf,int layer) {
   int i;
   SplineChar *sc;
   RefChar *r;

   for (i=0; i<sf->glyphcnt; ++i)
      if ((sc=sf->glyphs[i]) != NULL) {
	 for (r=sc->layers[layer].refs; r != NULL; r=r->next)
	    r->justtranslated=(r->transform[0]==1 && r->transform[3]==1
				 && r->transform[1]==0
				 && r->transform[2]==0);
      }
}

/* ************************************************************************** */
/* ********************** Type1 PostScript CharStrings ********************** */
/* ************************************************************************** */

static double myround(double pos,int round) {
   if (round)
      return (rint(pos));
   else
      return (rint(pos*1024.)/1024.);
}

static void AddNumber(GrowBuf *gb,double pos,int round) {
   int dodiv=0;
   int val;
   unsigned char *str;

   if (gb->pt+8 >= gb->end)
      GrowBuffer(gb);

   if (!round && pos != floor(pos)) {
      {
	 if (rint(pos*64)/64==pos) {
	    pos *= 64;
	    dodiv=64;
	 } else {
	    pos *= 1024;
	    dodiv=1024;
	 }
      }
   }
   pos=rint(pos);
   if (dodiv>0 && floor(pos)/dodiv==floor(pos/dodiv)) {
      pos=rint(pos/dodiv);
      dodiv=0;
   }
   val=pos;
   str=gb->pt;

   if (pos >= -107 && pos <= 107)
      *str++=val+139;
   else if (pos >= 108 && pos <= 1131) {
      val -= 108;
      *str++=(val >> 8)+247;
      *str++=val&0xff;
   } else if (pos >= -1131 && pos <= -108) {
      val=-val;
      val -= 108;
      *str++=(val >> 8)+251;
      *str++=val&0xff;
   } else {
      *str++='\377';
      *str++=(val >> 24)&0xff;
      *str++=(val >> 16)&0xff;
      *str++=(val >> 8)&0xff;
      *str++=val&0xff;
   }
   if (dodiv) {
      if (dodiv<107)
	 *str++=dodiv+139;
      else {
	 dodiv -= 108;
	 *str++=(dodiv >> 8)+247;
	 *str++=dodiv&0xff;
      }
      *str++=12;		/* div (byte1) */
      *str++=12;		/* div (byte2) */
   }
   gb->pt=str;
}

/* When doing a multiple master font we have multiple instances of the same data */
/*  which must all be added, and then a call made to the appropriate blend routine */
/* This is complicated because all the data may not fit on the stack so we */
/*  may need to make multiple calls */
static void AddData(GrowBuf *gb,double data[MmMax][6],int instances,
		    int num_coords, int round) {
   int allsame=true, alls[6];
   int i, j, chunk, min, max, subr;

   for (j=0; j<num_coords; ++j) {
      alls[j]=true;
      for (i=1; i<instances; ++i) {
	 if (data[i][j] != data[0][j]) {
	    alls[j]=false;
	    allsame=false;
	    break;
	 }
      }
   }

   if (allsame) {		/* No need for blending */
      /*  Probably a normal font, but possible in an mm */
      for (j=0; j<num_coords; ++j)
	 AddNumber(gb, data[0][j], round);
      return;
   }

   chunk=22/instances;
   if (chunk==5)
      chunk=4;		/* No subroutine for 5 items */
   min=0;
   while (min<num_coords) {
      while (min<num_coords && alls[min]) {
	 AddNumber(gb, data[0][min], round);
	 ++min;
      }
      max=min+chunk;
      if (max>num_coords)
	 max=num_coords;
      while (max-1>min && alls[max-1])
	 --max;
      if (max-min==5)
	 max=min+4;
      if (min<max) {
	 for (j=min; j<max; ++j)
	    AddNumber(gb, data[0][j], round);
	 for (j=min; j<max; ++j)
	    for (i=1; i<instances; ++i)
	       AddNumber(gb, data[i][j]-data[0][j], round);
	 subr=(j-min)+4;
	 if (j-min==6)
	    subr=9;
	 AddNumber(gb, subr, round);
	 if (gb->pt+1 >= gb->end)
	    GrowBuffer(gb);
	 *gb->pt++=10;	/* callsubr */
	 min=j;
      }
   }
}

int CvtPsStem3(GrowBuf * gb, SplineChar * scs[MmMax], int instance_count,
	       int ishstem, int round) {
   StemInfo *h1, *h2, *h3;

   StemInfo _h1, _h2, _h3;
   double data[MmMax][6];
   int i;
   double off;

   for (i=0; i<instance_count; ++i) {
      if ((ishstem && scs[i]->hconflicts) || (!ishstem && scs[i]->vconflicts))
	 return (false);
      h1=ishstem?scs[i]->hstem:scs[i]->vstem;
      if (h1==NULL || (h2=h1->next)==NULL || (h3=h2->next)==NULL)
	 return (false);
      if (h3->next != NULL)
	 return (false);
      off=ishstem?0:scs[i]->lsidebearing;
      if (h1->width<0) {
	 _h1=*h1;
	 _h1.start += _h1.width;
	 _h1.width=-_h1.width;
	 h1=&_h1;
      }
      if (h2->width<0) {
	 _h2=*h2;
	 _h2.start += _h2.width;
	 _h2.width=-_h2.width;
	 h2=&_h2;
      }
      if (h3->width<0) {
	 _h3=*h3;
	 _h3.start += _h3.width;
	 _h3.width=-_h3.width;
	 h3=&_h3;
      }

      if (h1->start>h2->start) {
	 StemInfo *ht=h1;

	 h1=h2;
	 h2=ht;
      }
      if (h1->start>h3->start) {
	 StemInfo *ht=h1;

	 h1=h3;
	 h3=ht;
      }
      if (h2->start>h3->start) {
	 StemInfo *ht=h2;

	 h2=h3;
	 h3=ht;
      }
      if (h1->width != h3->width)
	 return (false);
      if ((h2->start+h2->width/2)-(h1->start+h1->width/2) !=
	  (h3->start+h3->width/2)-(h2->start+h2->width/2))
	 return (false);
      data[i][0]=h1->start-off;
      data[i][1]=h1->width;
      data[i][2]=h2->start-off;
      data[i][3]=h2->width;
      data[i][4]=h3->start-off;
      data[i][5]=h3->width;
   }
   if (gb==NULL)
      return (true);
   AddData(gb, data, instance_count, 6, round);
   if (gb->pt+3 >= gb->end)
      GrowBuffer(gb);
   *(gb->pt)++=12;
   *(gb->pt)++=ishstem?2:1;	/* h/v stem3 */
   return (true);
}

static void CvtPsHints(GrowBuf *gb,SplineChar *scs[MmMax],
		       int instance_count, int ishstem, int round, int iscjk,
		       double * offsets) {
   StemInfo *hs[MmMax];
   double data[MmMax][6];
   int i;
   double off;

   for (i=0; i<instance_count; ++i)
      hs[i]=ishstem?scs[i]->hstem:scs[i]->vstem;

   if (hs[0] != NULL && hs[0]->next != NULL && hs[0]->next->next != NULL &&
       hs[0]->next->next->next==NULL)
      if (!iscjk && CvtPsStem3(gb, scs, instance_count, ishstem, round))
	 return;

   while (hs[0] != NULL) {
      for (i=0; i<instance_count; ++i) {
	 off=offsets != NULL?offsets[i] :
	    ishstem?0:scs[i]->lsidebearing;
	 if (hs[i]->ghost) {
	    data[i][0]=hs[i]->start-off+hs[i]->width;
	    data[i][1]=-hs[i]->width;
	 } else {
	    data[i][0]=hs[i]->start-off;
	    data[i][1]=hs[i]->width;
	 }
      }
      AddData(gb, data, instance_count, 2, round);
      if (gb->pt+1 >= gb->end)
	 GrowBuffer(gb);
      *(gb->pt)++=ishstem?1:3;	/* h/v stem */
      for (i=0; i<instance_count; ++i)
	 hs[i]=hs[i]->next;
   }
}

static void CvtPsMasked(GrowBuf *gb,SplineChar *scs[MmMax],
			int instance_count, int ishstem, int round,
			uint8_t mask[12]) {
   StemInfo *hs[MmMax];
   double data[MmMax][6], off;
   int i;

   for (i=0; i<instance_count; ++i)
      hs[i]=ishstem?scs[i]->hstem:scs[i]->vstem;

   while (hs[0] != NULL) {
      if (hs[0]->hintnumber != -1 &&
	  (mask[hs[0]->hintnumber >> 3]&(0x80 >> (hs[0]->hintnumber&7))))
      {
	 for (i=0; i<instance_count; ++i) {
	    off=ishstem?0:scs[i]->lsidebearing;
	    if (hs[i]->ghost) {
	       data[i][0]=hs[i]->start-off+hs[i]->width;
	       data[i][1]=-hs[i]->width;
	    } else {
	       data[i][0]=hs[i]->start-off;
	       data[i][1]=hs[i]->width;
	    }
	 }
	 AddData(gb, data, instance_count, 2, round);
	 if (gb->pt+1 >= gb->end)
	    GrowBuffer(gb);
	 *(gb->pt)++=ishstem?1:3;	/* h/v stem */
      }
      for (i=0; i<instance_count; ++i)
	 hs[i]=hs[i]->next;
   }
}

static int FigureCounters(StemInfo *stems,double *hints,int base,
			  double offset, int countermask_cnt,
			  HintMask * counters) {
   StemInfo *h;
   int pos=base+1, subbase, cnt=0;
   double last=offset;
   int i;

   for (i=0; i<countermask_cnt; ++i) {
      subbase=pos;
      for (h=stems; h != NULL; h=h->next) {
	 if (h->hintnumber != -1
	     && (counters[i][h->hintnumber >> 3] &
		 (0x80 >> (h->hintnumber&7)))) {
	    hints[pos++]=h->start-last;
	    hints[pos++]=h->width;
	    last=h->start+h->width;
	 }
      }
      if (pos != subbase) {
	 hints[pos-2] += hints[pos-1];
	 hints[pos-1]=-hints[pos-1];	/* Mark end of group */
	 last=offset;		/* Each new group starts at 0 or lbearing */
	 ++cnt;
      }
   }
   hints[base]=cnt;
   return (pos);
}

static void CounterHints1(GrowBuf *gb,SplineChar *sc,int round) {
   double hints[HntMax*2+2];	/* At most 96 hints, no hint used more than once */
   int pos, i, j;

   if (sc->countermask_cnt==0)
      return;

   pos=FigureCounters(sc->hstem, hints, 0, 0, sc->countermask_cnt,
			sc->countermasks);
   /* Adobe's docs (T1_Supp.pdf, section 2.4) say these should be offset from */
   /*  the left side bearing. The example (T1_Supp.pdf, 2.6) shows them offset */
   /*  from 0. I've no idea which is correct, so I'll follow the words, think- */
   /*  that the lbearing might have been set to 0 even though it shouldn't */
   /*  have been. */
   pos =
      FigureCounters(sc->vstem, hints, pos, sc->lsidebearing,
		     sc->countermask_cnt, sc->countermasks);
   if (pos==2)		/* => no counters, one byte to say 0 h counters, one byte for 0 v counters */
      return;
   for (i=pos; i>22; i -= 22) {
      for (j=i-22; j<i; ++j)
	 AddNumber(gb, hints[j], round);
      AddNumber(gb, 22, round);
      AddNumber(gb, 12, round);
      if (gb->pt+2 >= gb->end)
	 GrowBuffer(gb);
      *(gb->pt)++=12;
      *(gb->pt)++=16;		/* CallOtherSubr */
   }
   for (j=0; j<i; ++j)
      AddNumber(gb, hints[j], round);
   AddNumber(gb, i, round);
   AddNumber(gb, 13, round);
   if (gb->pt+2 >= gb->end)
      GrowBuffer(gb);
   *(gb->pt)++=12;
   *(gb->pt)++=16;		/* CallOtherSubr */
}

static void SubrsCheck(struct pschars *subrs) {
   /* <subr number presumed to be on stack> 1 3 callother pop callsubr */

   if (subrs->next >= subrs->cnt) {
      subrs->cnt += 100;
      subrs->values=realloc(subrs->values, subrs->cnt * sizeof(uint8_t *));
      subrs->lens=realloc(subrs->lens, subrs->cnt * sizeof(int));
      if (subrs->keys != NULL) {
	 int i;

	 subrs->keys=realloc(subrs->keys, subrs->cnt * sizeof(char *));
	 for (i=subrs->cnt-100; i<subrs->cnt; ++i)
	    subrs->keys[i]=NULL;
      }
   }
}

/* Does the hintmask we need already exist in a subroutine? if so return that */
/*  subr. Else build a new subr with the hints we need. Note we can only use */
/*  *stem3 commands if there are no conflicts in that coordinate, it isn't cjk*/
/*  and all the other conditions are met */
static int FindOrBuildHintSubr(struct hintdb *hdb,uint8_t mask[12],int round) {
   struct mhlist *mh;
   GrowBuf gb;

   for (mh=hdb->sublist;mh!=NULL;mh=mh->next) {
      if (memcmp(mask,mh->mask,sizeof(uint8_t)*12)==0)
	return (mh->subr);
   }
   SubrsCheck(hdb->subrs);

   memset(&gb,0,sizeof(gb));
   if (!hdb->scs[0]->hconflicts)
     CvtPsHints(&gb,hdb->scs,hdb->instance_count,true,round,hdb->iscjk,
		NULL);
   else
     CvtPsMasked(&gb,hdb->scs,hdb->instance_count,true,round,mask);
   if (!hdb->scs[0]->vconflicts)
     CvtPsHints(&gb,hdb->scs,hdb->instance_count,false,round,hdb->iscjk,
		NULL);
   else
     CvtPsMasked(&gb,hdb->scs,hdb->instance_count,false,round,mask);
   if (gb.pt+1>=gb.end)
     GrowBuffer(&gb);
   *gb.pt++=11;		/* return */

   /* Replace an old subroutine */
   if (mh!=NULL) {
      free(hdb->subrs->values[mh->subr]);
      hdb->subrs->values[mh->subr]=
	(uint8_t *)copyn((char *)gb.base,gb.pt-gb.base);
      hdb->subrs->lens[mh->subr]=gb.pt-gb.base;
      memcpy(mh->mask,mask,sizeof(mh->mask));
   } else {
      hdb->subrs->values[hdb->subrs->next]=
	(uint8_t *)copyn((char *)gb.base,gb.pt-gb.base);
      hdb->subrs->lens[hdb->subrs->next]=gb.pt-gb.base;

      mh=calloc(1,sizeof(struct mhlist));
      memcpy(mh->mask,mask,sizeof(mh->mask));
      mh->subr=hdb->subrs->next++;
      mh->next=hdb->sublist;
      hdb->sublist=mh;
   }
   free(gb.base);

   return (mh->subr);
}

static void CallTransformedHintSubr(GrowBuf *gb,struct hintdb *hdb,
				    SplineChar * scs[MmMax],
				    RefChar * refs[MmMax],
				    BasePoint trans[MmMax],
				    int instance_count, int round) {
   HintMask hm;
   int s;

   if (HintMaskFromTransformedRef(refs[0], &trans[0], scs[0], &hm)==NULL)
      return;
   s=FindOrBuildHintSubr(hdb, hm, round);
   AddNumber(gb, s, round);
   AddNumber(gb, 4, round);	/* subr 4 is (my) magic subr that does the hint subs call */
   if (gb->pt+1 >= gb->end)
      GrowBuffer(gb);
   *gb->pt++=10;		/* callsubr */
}

static void HintSetup(GrowBuf *gb,struct hintdb *hdb,SplinePoint *to,
		      int round, int break_subr) {
   int s;
   int i;

   if (to->hintmask==NULL || hdb->noconflicts)
      return;
   if (hdb->scs[0]->hstem==NULL && hdb->scs[0]->vstem==NULL)	/* Hints are turned off. Hint mask still remains though */
      return;
   for (i=0; i<HntMax/8; ++i)
      if (to->hintmask[i] != 0)
	 break;
   if (i==HntMax/8)		/* Empty mask */
      return;

   s=FindOrBuildHintSubr(hdb, *to->hintmask, round);
   memcpy(hdb->mask, *to->hintmask, sizeof(HintMask));
   if (hdb->cursub==s) {	/* If we were able to redefine */
      return;			/* the subroutine currently */
   }
   /* active then we are done */
   if (break_subr)
      BreakSubroutine(gb, hdb);

   AddNumber(gb, s, round);
   AddNumber(gb, 4, round);	/* subr 4 is (my) magic subr that does the hint subs call */
   if (gb->pt+1 >= gb->end)
      GrowBuffer(gb);
   *gb->pt++=10;		/* callsubr */
   hdb->cursub=s;
   if (break_subr)
      StartNextSubroutine(gb, hdb);
}

static void _moveto(GrowBuf *gb,DBasePoint *current,BasePoint *to,
		    int instance_count, int line, int round,
		    struct hintdb *hdb) {
   BasePoint temp[MmMax];
   int i, samex, samey;
   double data[MmMax][6];

   if (gb->pt+18 >= gb->end)
      GrowBuffer(gb);

   for (i=0; i<instance_count; ++i) {
      temp[i].x=myround(to[i].x, round);
      temp[i].y=myround(to[i].y, round);
   }
   to=temp;
   samex=samey=true;
   for (i=0; i<instance_count; ++i) {
      if (current[i].x != to[i].x)
	 samex=false;
      if (current[i].y != to[i].y)
	 samey=false;
   }
   if (samex) {
      for (i=0; i<instance_count; ++i)
	 data[i][0]=to[i].y-current[i].y;
      AddData(gb, data, instance_count, 1, round);
      *(gb->pt)++=line?7:4;	/* v move/line to */
      for (i=0; i<instance_count; ++i)
	 current[i].y += data[i][0];
   } else if (samey) {
      for (i=0; i<instance_count; ++i)
	 data[i][0]=to[i].x-current[i].x;
      AddData(gb, data, instance_count, 1, round);
      *(gb->pt)++=line?6:22;	/* h move/line to */
      for (i=0; i<instance_count; ++i)
	 current[i].x += data[i][0];
   } else {
      for (i=0; i<instance_count; ++i) {
	 data[i][0]=to[i].x-current[i].x;
	 data[i][1]=to[i].y-current[i].y;
      }
      AddData(gb, data, instance_count, 2, round);
      *(gb->pt)++=line?5:21;	/* r move/line to */
      for (i=0; i<instance_count; ++i) {
	 current[i].x += data[i][0];
	 current[i].y += data[i][1];
      }
   }
   if (!line)
      StartNextSubroutine(gb, hdb);
}

static void moveto(GrowBuf *gb,DBasePoint *current,
		   Spline * splines[MmMax], int instance_count, int line,
		   int round, struct hintdb *hdb) {
   BasePoint to[MmMax];
   int i;

   if (!line)
      BreakSubroutine(gb, hdb);
   if (hdb != NULL)
      HintSetup(gb, hdb, splines[0]->to, round, line);
   for (i=0; i<instance_count; ++i)
      to[i]=splines[i]->to->me;
   _moveto(gb, current, to, instance_count, line, round, hdb);
}

static void splmoveto(GrowBuf *gb,DBasePoint *current,
		      SplineSet * spl[MmMax], int instance_count, int line,
		      int round, struct hintdb *hdb) {
   BasePoint to[MmMax];
   int i;

   if (!line)
      BreakSubroutine(gb, hdb);
   if (hdb != NULL)
      HintSetup(gb, hdb, spl[0]->first, round, line);
   for (i=0; i<instance_count; ++i)
      to[i]=spl[i]->first->me;
   _moveto(gb, current, to, instance_count, line, round, hdb);
}

static int NeverConflicts(RefChar *refs[MmMax],int instance_count) {
   int i;

   for (i=0; i<instance_count; ++i)
      if (refs[i]->sc->hconflicts || refs[i]->sc->vconflicts)
	 return (false);

   return (true);
}

static int AllStationary(RefChar *refs[MmMax],BasePoint trans[MmMax],
			 int instance_count) {
   int i;

   for (i=0; i<instance_count; ++i)
      if (!refs[i]->justtranslated ||
	  refs[i]->transform[4]+trans[i].x != 0 ||
	  refs[i]->transform[5]+trans[i].y != 0)
	 return (false);

   return (true);
}

static int AnyRefs(SplineChar *sc,int layer) {

   return (sc->layers[layer].refs != NULL);
}

static void refmoveto(GrowBuf *gb,DBasePoint *current,
		      BasePoint rpos[MmMax], int instance_count, int line,
		      int round, struct hintdb *hdb, RefChar * refs[MmMax]) {
   BasePoint to[MmMax];
   int i;

   if (!line)
      BreakSubroutine(gb, hdb);
   for (i=0; i<instance_count; ++i) {
      to[i]=rpos[i];
      if (refs != NULL) {
	 to[i].x += refs[i]->transform[4];
	 to[i].y += refs[i]->transform[5];
      }
   }
   _moveto(gb, current, to, instance_count, line, round, hdb);
}

static void curveto(GrowBuf *gb,DBasePoint *current,
		    Spline * splines[MmMax], int instance_count, int round,
		    struct hintdb *hdb) {
   BasePoint temp1[MmMax], temp2[MmMax], temp3[MmMax], *c0[MmMax], *c1[MmMax],
      *s1[MmMax];
   double data[MmMax][6];
   int i, op, opcnt;
   int vh, hv;

   if (hdb != NULL)
      HintSetup(gb, hdb, splines[0]->to, round, true);

   if (gb->pt+50 >= gb->end)
      GrowBuffer(gb);

   vh=hv=true;
   for (i=0; i<instance_count; ++i) {
      c0[i]=&splines[i]->from->nextcp;
      c1[i]=&splines[i]->to->prevcp;
      s1[i]=&splines[i]->to->me;
      temp1[i].x=myround(c0[i]->x, round);
      temp1[i].y=myround(c0[i]->y, round);
      c0[i]=&temp1[i];
      temp2[i].x=myround(c1[i]->x, round);
      temp2[i].y=myround(c1[i]->y, round);
      c1[i]=&temp2[i];
      temp3[i].x=myround(s1[i]->x, round);
      temp3[i].y=myround(s1[i]->y, round);
      s1[i]=&temp3[i];
      if (current[i].x != c0[i]->x || c1[i]->y != s1[i]->y)
	 vh=false;
      if (current[i].y != c0[i]->y || c1[i]->x != s1[i]->x)
	 hv=false;
   }
   if (vh) {
      for (i=0; i<instance_count; ++i) {
	 data[i][0]=c0[i]->y-current[i].y;
	 data[i][1]=c1[i]->x-c0[i]->x;
	 data[i][2]=c1[i]->y-c0[i]->y;
	 data[i][3]=s1[i]->x-c1[i]->x;
      }
      op=30;			/* vhcurveto */
      opcnt=4;
      for (i=0; i<instance_count; ++i) {
	 current[i].x += data[i][1]+data[i][3];
	 current[i].y += data[i][0]+data[i][2];
      }
   } else if (hv) {
      for (i=0; i<instance_count; ++i) {
	 data[i][0]=c0[i]->x-current[i].x;
	 data[i][1]=c1[i]->x-c0[i]->x;
	 data[i][2]=c1[i]->y-c0[i]->y;
	 data[i][3]=s1[i]->y-c1[i]->y;
      }
      op=31;			/* hvcurveto */
      opcnt=4;
      for (i=0; i<instance_count; ++i) {
	 current[i].x += data[i][0]+data[i][1];
	 current[i].y += data[i][2]+data[i][3];
      }
   } else {
      for (i=0; i<instance_count; ++i) {
	 data[i][0]=c0[i]->x-current[i].x;
	 data[i][1]=c0[i]->y-current[i].y;
	 data[i][2]=c1[i]->x-c0[i]->x;
	 data[i][3]=c1[i]->y-c0[i]->y;
	 data[i][4]=s1[i]->x-c1[i]->x;
	 data[i][5]=s1[i]->y-c1[i]->y;
      }
      op=8;			/* rrcurveto */
      opcnt=6;
      for (i=0; i<instance_count; ++i) {
	 current[i].x += data[i][0]+data[i][2]+data[i][4];
	 current[i].y += data[i][1]+data[i][3]+data[i][5];
      }
   }
   AddData(gb, data, instance_count, opcnt, false);
   if (gb->pt+1 >= gb->end)
      GrowBuffer(gb);
   *(gb->pt)++=op;
}

static int SplinesAreFlexible(Spline *splines[MmMax],int instance_count) {
   int i, x=false, y=false;

   for (i=0; i<instance_count; ++i) {
      if (!splines[i]->to->flexx && !splines[i]->to->flexy)
	 return (false);
      if ((x && splines[i]->to->flexy) || (y && splines[i]->to->flexx))
	 return (false);
      x=splines[i]->to->flexx;
      y=splines[i]->to->flexy;
   }
   return (true);
}

static void flexto(GrowBuf *gb,DBasePoint current[MmMax],
		   Spline * pspline[MmMax], int instance_count, int round,
		   struct hintdb *hdb) {
   BasePoint *c0, *c1, *mid, *end=NULL;
   Spline *nspline;
   BasePoint offsets[MmMax][8];
   int i, j;
   BasePoint temp1, temp2, temp3, temp;
   double data[MmMax][6];

   for (j=0; j<instance_count; ++j) {
      c0=&pspline[j]->from->nextcp;
      c1=&pspline[j]->to->prevcp;
      mid=&pspline[j]->to->me;

      temp1.x=myround(c0->x, round);
      temp1.y=myround(c0->y, round);
      c0=&temp1;
      temp2.x=myround(c1->x, round);
      temp2.y=myround(c1->y, round);
      c1=&temp2;
      temp.x=myround(mid->x, round);
      temp.y=myround(mid->y, round);
      mid=&temp;
/* reference point is same level as current point */
      if (current[j].y==pspline[j]->to->next->to->me.y) {
	 offsets[j][0].x=mid->x-current[j].x;
	 offsets[j][0].y=0;
	 offsets[j][1].x=c0->x-mid->x;
	 offsets[j][1].y=c0->y-current[j].y;
      } else {
	 offsets[j][0].x=0;
	 offsets[j][0].y=mid->y-current[j].y;
	 offsets[j][1].x=c0->x-current[j].x;
	 offsets[j][1].y=c0->y-mid->y;
      }
      offsets[j][2].x=c1->x-c0->x;
      offsets[j][2].y=c1->y-c0->y;
      offsets[j][3].x=mid->x-c1->x;
      offsets[j][3].y=mid->y-c1->y;
      nspline=pspline[j]->to->next;
      c0=&nspline->from->nextcp;
      c1=&nspline->to->prevcp;
      end=&nspline->to->me;

      temp1.x=myround(c0->x, round);
      temp1.y=myround(c0->y, round);
      c0=&temp1;
      temp2.x=myround(c1->x, round);
      temp2.y=myround(c1->y, round);
      c1=&temp2;
      temp3.x=myround(end->x, round);
      temp3.y=myround(end->y, round);
      end=&temp3;

      offsets[j][4].x=c0->x-mid->x;
      offsets[j][4].y=c0->y-mid->y;
      offsets[j][5].x=c1->x-c0->x;
      offsets[j][5].y=c1->y-c0->y;
      offsets[j][6].x=end->x-c1->x;
      offsets[j][6].y=end->y-c1->y;
      offsets[j][7].x=end->x;
      offsets[j][7].y=end->y;
      current[j].x=end->x;
      current[j].y=end->y;
   }

   if (hdb != NULL)
      HintSetup(gb, hdb, pspline[0]->to->next->to, round, false);

   if (gb->pt+2 >= gb->end)
      GrowBuffer(gb);

   *(gb->pt)++=1+139;	/* 1 */
   *(gb->pt)++=10;		/* callsubr */
   for (i=0; i<7; ++i) {
      if (gb->pt+20 >= gb->end)
	 GrowBuffer(gb);
      for (j=0; j<instance_count; ++j) {
	 data[j][0]=offsets[j][i].x;
	 data[j][1]=offsets[j][i].y;
      }
      AddData(gb, data, instance_count, 2, round);
      *(gb->pt)++=21;		/* rmoveto */
      *(gb->pt)++=2+139;	/* 2 */
      *(gb->pt)++=10;		/* callsubr */
   }
   if (gb->pt+20 >= gb->end)
      GrowBuffer(gb);
   *(gb->pt)++=50+139;	/* 50, .50 pixels */
   for (j=0; j<instance_count; ++j) {
      data[j][0]=offsets[j][7].x;
      data[j][1]=offsets[j][7].y;
   }
   AddData(gb, data, instance_count, 2, round);
   *(gb->pt)++=0+139;	/* 0 */
   *(gb->pt)++=10;		/* callsubr */

   current->x=end->x;
   current->y=end->y;
}

static void _CvtPsSplineSet(GrowBuf *gb,SplinePointList *spl[MmMax],
			    int instance_count, DBasePoint current[MmMax],
			    int round, struct hintdb *hdb, int is_order2,
			    int stroked) {
   Spline *spline[MmMax], *first;
   SplinePointList temp[MmMax], *freeme=NULL;
   int i;

   if (is_order2) {
      freeme=spl[0]=SplineSetsPSApprox(spl[0]);
      instance_count=1;
   }
   while (spl[0] != NULL) {
      first=NULL;
      for (i=0; i<instance_count; ++i)
	 SplineSetReverse(spl[i]);
      /* For some reason fontographer reads its spline in in the reverse */
      /*  order from that I use. I'm not sure how they do that. The result */
      /*  being that what I call clockwise they call counter. Oh well. */
      /*  If I reverse the splinesets after reading them in, and then again */
      /*  when saving them out, all should be well */
      if (spl[0]->first->flexy || spl[0]->first->flexx) {
	 /* can't handle a flex (mid) point as the first point. rotate the */
	 /* list by one, this is possible because only closed paths have */
	 /* points marked as flex, and because we can't have two flex mid- */
	 /* points in a row */
	 for (i=0; i<instance_count; ++i) {
	    temp[i]=*spl[i];
	    temp[i].first=temp[i].last=spl[i]->first->next->to;
	    spl[i]=&temp[i];
	 }
	 if (spl[0]->first->flexy || spl[0]->first->flexx) {
	    /* well, well, well. We did have two flexes in a row */
	    for (i=0; i<instance_count; ++i) {
	       spl[i]->first->flexx=spl[i]->first->flexy=false;
	    }
	 }
      }
      splmoveto(gb, current, spl, instance_count, false, round, hdb);
      for (i=0; i<instance_count; ++i)
	 spline[i]=spl[i]->first->next;
      while (spline[0] != NULL && spline[0] != first) {
	 if (first==NULL)
	    first=spline[0];
	 if (SplinesAreFlexible(spline, instance_count) &&
	     (hdb->noconflicts || spline[0]->to->hintmask==NULL)) {
	    flexto(gb, current, spline, instance_count, round, hdb);	/* does two adjacent splines */
	    for (i=0; i<instance_count; ++i)
	       spline[i]=spline[i]->to->next;
	 } else if (spline[0]->knownlinear && spline[0]->to==spl[0]->first) {
	    /* We can finish this off with the closepath */
	    break;
	 } else if (spline[0]->knownlinear)
	    moveto(gb, current, spline, instance_count, true, round, hdb);
	 else
	    curveto(gb, current, spline, instance_count, round, hdb);
	 for (i=0; i<instance_count; ++i)
	    spline[i]=spline[i]->to->next;
      }
      if (!stroked || spl[0]->first->prev != NULL) {
	 if (gb->pt+1 >= gb->end)
	    GrowBuffer(gb);
	 *(gb->pt)++=9;	/* closepath */
      }
      for (i=0; i<instance_count; ++i) {
	 SplineSetReverse(spl[i]);
	 /* Of course, I have to Reverse again to get back to my convention after */
	 /*  saving */
	 spl[i]=spl[i]->next;
      }
   }
   SplinePointListsFree(freeme);
}

static int IsPSSeacable(SplineChar *sc,int layer) {
   RefChar *ref;

   if (sc->layers[layer].refs==NULL || sc->layers[layer].splines != NULL)
      return (false);

   for (ref=sc->layers[layer].refs; ref != NULL; ref=ref->next) {
      if (!ref->justtranslated)
	 return (false);
   }
   return (true);
}

static RefChar *RefFindAdobe(RefChar *r,RefChar *t,int layer) {
   *t=*r;
   while (t->adobe_enc==-1 && t->sc->layers[layer].refs != NULL &&
	  t->sc->layers[layer].refs->next==NULL &&
	  t->sc->layers[layer].splines==NULL &&
	  t->sc->layers[layer].refs->justtranslated) {
      t->transform[4] += t->sc->layers[layer].refs->transform[4];
      t->transform[5] += t->sc->layers[layer].refs->transform[5];
      t->adobe_enc=t->sc->layers[layer].refs->adobe_enc;
      t->orig_pos=t->sc->layers[layer].refs->orig_pos;
      t->sc=t->sc->layers[layer].refs->sc;
   }
   return (t);
}

static int IsSeacable(GrowBuf *gb,SplineChar *scs[MmMax],
		      int instance_count, int round, int layer) {
   /* can be at most two chars in a seac (actually must be exactly 2, but */
   /*  I'll put in a space if there's only one (and if splace is blank) */
   RefChar *r1, *r2, *rt, *refs;
   RefChar space, t1, t2;
   DBounds b;
   int i, j, swap;
   double data[MmMax][6];

   for (j=0; j<instance_count; ++j)
      if (!IsPSSeacable(scs[j], layer))
	 return (false);

   refs=scs[0]->layers[layer].refs;
   if (refs==NULL)
      return (false);

   r1=refs;
   if ((r2=r1->next)==NULL) {
      RefChar *refs=r1->sc->layers[layer].refs;

      if (refs != NULL && refs->next != NULL && refs->next->next==NULL &&
	  r1->sc->layers[layer].splines==NULL &&
	  refs->adobe_enc != -1 && refs->next->adobe_enc != -1) {
	 r2=refs->next;
	 r1=refs;
      }
   }
   if (r2==NULL) {
      r2=&space;
      memset(r2, '\0', sizeof(space));
      space.adobe_enc=' ';
      space.transform[0]=space.transform[3]=1.0;
      for (i=0; i<scs[0]->parent->glyphcnt; ++i)
	 if (scs[0]->parent->glyphs[i] != NULL &&
	     strcmp(scs[0]->parent->glyphs[i]->name, "space")==0)
	    break;
      if (i==scs[0]->parent->glyphcnt)
	 r2=NULL;		/* No space???? */
      else {
	 space.sc=scs[0]->parent->glyphs[i];
	 if (space.sc->layers[layer].splines != NULL
	     || space.sc->layers[layer].refs != NULL)
	    r2=NULL;
      }
   } else if (r2->next != NULL)
      r2=NULL;

   /* check for something like "AcyrillicBreve" which has a ref to Acyril */
   /*  (which doesn't have an adobe enc) which in turn has a ref to A (which */
   /*  does) */
   if (r2 != NULL) {
      if (r1->adobe_enc==-1)
	 r1=RefFindAdobe(r1, &t1, layer);
      if (r2->adobe_enc==-1)
	 r2=RefFindAdobe(r2, &t2, layer);
   }

/* CID fonts have no encodings. So we can't use seac to reference characters */
/*  in them. The other requirements are just those of seac */
   if (r2==NULL ||
       r1->adobe_enc==-1 ||
       r2->adobe_enc==-1 ||
       ((r1->transform[4] != 0 || r1->transform[5] != 0
	 || r1->sc->width != scs[0]->width) && (r2->transform[4] != 0
						|| r2->transform[5] != 0
						|| r2->sc->width !=
						scs[0]->width)))
      return (false);

   swap=false;
   if (r1->transform[4] != 0 || r1->transform[5] != 0) {
      rt=r1;
      r1=r2;
      r2=rt;
      swap=!swap;
   }

   SplineCharFindBounds(r1->sc, &b);
   r1->sc->lsidebearing=myround(b.minx, round);
   SplineCharFindBounds(r2->sc, &b);
   r2->sc->lsidebearing=myround(b.minx, round);

   if ((r1->sc->width != scs[0]->width
	|| r1->sc->lsidebearing != scs[0]->lsidebearing)
       && r2->sc->width==scs[0]->width
       && r2->sc->lsidebearing==scs[0]->lsidebearing
       && r2->transform[4]==0 && r2->transform[5]==0) {
      rt=r1;
      r1=r2;
      r2=rt;
      swap=!swap;
   }
   if (r1->sc->width != scs[0]->width
       || r1->sc->lsidebearing != scs[0]->lsidebearing
       || r1->transform[4] != 0 || r1->transform[5] != 0)
      return (false);

   for (j=0; j<instance_count; ++j) {
      SplineChar *r2sc=scs[j]->parent->glyphs[r2->sc->orig_pos];
      RefChar *r3, t3;

      SplineCharFindBounds(r2sc, &b);
      if (scs[j]->layers[layer].refs != NULL
	  && scs[j]->layers[layer].refs->next==NULL)
	 r3=r2;		/* Space, not offset */
      else if (swap)
	 r3=RefFindAdobe(scs[j]->layers[layer].refs, &t3, layer);
      else
	 r3=RefFindAdobe(scs[j]->layers[layer].refs->next, &t3, layer);

      b.minx=myround(b.minx, round);
      data[j][0]=b.minx;
      data[j][1]=r3->transform[4]+b.minx-scs[j]->lsidebearing;
      data[j][2]=r3->transform[5];
   }
   AddData(gb, data, instance_count, 3, round);
   AddNumber(gb, r1->adobe_enc, round);
   AddNumber(gb, r2->adobe_enc, round);
   if (gb->pt+2>gb->end)
      GrowBuffer(gb);
   *(gb->pt)++=12;
   *(gb->pt)++=6;		/* seac 12,6 */

   return (true);
}

static int _SCNeedsSubsPts(SplineChar *sc,int layer) {
   RefChar *ref;

   if (sc->hstem==NULL && sc->vstem==NULL)
      return (false);

   if (sc->layers[layer].splines != NULL)
      return (sc->layers[layer].splines->first->hintmask==NULL);

   for (ref=sc->layers[layer].refs; ref != NULL; ref=ref->next)
      if (ref->layers[0].splines != NULL)
	 return (ref->layers[0].splines->first->hintmask==NULL);

   return (false);		/* It's empty. that's easy. */
}

static int SCNeedsSubsPts(SplineChar *sc,enum fontformat format,int layer) {
   if ((format != ff_mma && format != ff_mmb) || sc->parent->mm==NULL) {
      if (!sc->hconflicts && !sc->vconflicts)
	 return (false);	/* No conflicts, no swap-over points needed */
      return (_SCNeedsSubsPts(sc, layer));
   } else {
      MMSet *mm=sc->parent->mm;
      int i;

      for (i=0; i<mm->instance_count; ++i)
	 if (sc->orig_pos<mm->instances[i]->glyphcnt) {
	    if (_SCNeedsSubsPts
		(mm->instances[i]->glyphs[sc->orig_pos], layer))
	       return (true);
	 }
      return (false);
   }
}

static void ExpandRef1(GrowBuf *gb,SplineChar *scs[MmMax],
		       int instance_count, struct hintdb *hdb,
		       RefChar * r[MmMax], BasePoint trans[MmMax],
		       DBasePoint current[MmMax], struct pschars *subrs,
		       int round, int iscjk, int layer) {
   BasePoint *bpt;
   BasePoint rtrans[MmMax], rpos[MmMax];
   int i;

   for (i=0; i<instance_count; ++i) {
      rtrans[i].x=r[i]->transform[4]+trans[i].x;
      rtrans[i].y=r[i]->transform[5]+trans[i].y;
      if (round) {
	 rtrans[i].x=rint(rtrans[i].x);
	 rtrans[i].y=rint(rtrans[i].y);
      }
   }

   BreakSubroutine(gb, hdb);
   if (r[0]->sc==scs[0]) {
      /* Hints for self */
      if (hdb->cnt>0 && !hdb->noconflicts
	  && NeverConflicts(r, instance_count)) {
	 CvtPsHints(gb, scs, instance_count, true, round, iscjk, NULL);
	 CvtPsHints(gb, scs, instance_count, false, round, iscjk, NULL);
      }
   } else {
      /* Hints for a real reference */
      if (!NeverConflicts(r, instance_count)
	  || r[0]->sc->layers[layer].anyflexes || AnyRefs(r[0]->sc, layer))
	 /* Hints already done */ ;
      else if (hdb->noconflicts)
	 /* Hints already done */ ;
      else if (r[0]->sc->hstem != NULL || r[0]->sc->vstem != NULL)
	 CallTransformedHintSubr(gb, hdb, scs, r, trans, instance_count,
				 round);
   }

   if (hdb != NULL && hdb->gi != NULL)
      bpt=hdb->gi->psubrs[r[0]->sc->ttf_glyph].startstop;
   else
      bpt=(BasePoint *) (subrs->keys[r[0]->sc->ttf_glyph]);
   for (i=0; i<instance_count; ++i) {
      rpos[i].x=bpt[2*i].x+rtrans[i].x;
      rpos[i].y=bpt[2*i].y+rtrans[i].y;
   }
   refmoveto(gb, current, rpos, instance_count, false, round, hdb, NULL);
   hdb->startset=true;

   if (hdb != NULL && hdb->gi != NULL) {
      GlyphInfo *gi=hdb->gi;

      StartNextSubroutine(gb, hdb);
      gi->bits[gi->bcnt].psub_index=r[0]->sc->ttf_glyph;
      ++gi->bcnt;
      gi->justbroken=true;
   } else {
      AddNumber(gb, r[0]->sc->ttf_glyph, round);
      if (gb->pt+1 >= gb->end)
	 GrowBuffer(gb);
      *gb->pt++=10;
   }

   for (i=0; i<instance_count; ++i) {
      current[i].x=bpt[2*i+1].x+rtrans[i].x;
      current[i].y=bpt[2*i+1].y+rtrans[i].y;
   }
}

static void RSC2PS1(GrowBuf *gb,SplineChar *base[MmMax],
		    SplineChar * rsc[MmMax], struct hintdb *hdb,
		    BasePoint * trans, struct pschars *subrs,
		    DBasePoint current[MmMax], int flags, int iscjk,
		    int instance_count, int layer) {
   BasePoint subtrans[MmMax];
   SplineChar *rscs[MmMax];
   int round=(flags&ps_flag_round)?true:false;
   RefChar *refs[MmMax];
   SplineSet *spls[MmMax], *freeme[MmMax];
   int i;
   int wasntconflicted=hdb->noconflicts;

   for (i=0; i<instance_count; ++i) {
      spls[i]=rsc[i]->layers[layer].splines;
      if (base[0] != rsc[0])
	 spls[i]=freeme[i] =
	    SPLCopyTranslatedHintMasks(spls[i], base[i], rsc[i], &trans[i]);
   }
   _CvtPsSplineSet(gb, spls, instance_count, current, round, hdb,
		   base[0]->layers[layer].order2,
		   base[0]->parent->strokedfont);
   if (base[0] != rsc[0])
      for (i=0; i<instance_count; ++i)
	 SplinePointListsFree(freeme[i]);

   for (i=0; i<instance_count; ++i)
      refs[i]=rsc[i]->layers[layer].refs;
   while (refs[0] != NULL) {
      for (i=0; i<instance_count; ++i)
	 spls[i]=refs[i]->layers[0].splines;
      if (!refs[0]->justtranslated) {
	 for (i=0; i<instance_count; ++i)
	    spls[i]=freeme[i] =
	       SPLCopyTransformedHintMasks(refs[i], base[i], &trans[i],
					   layer);
	 if (NeverConflicts(refs, instance_count) && !hdb->noconflicts
	     && refs[0]->transform[1]==0 && refs[0]->transform[2]==0)
	    CallTransformedHintSubr(gb, hdb, base, refs, trans,
				    instance_count, round);
	 _CvtPsSplineSet(gb, spls, instance_count, current, round, hdb,
			 base[0]->layers[layer].order2,
			 base[0]->parent->strokedfont);
	 for (i=0; i<instance_count; ++i)
	    SplinePointListsFree(freeme[i]);
      } else if (refs[0]->sc->ttf_glyph != 0x7fff &&
		 ((flags&ps_flag_nohints) ||
		  !refs[0]->sc->layers[layer].anyflexes ||
		  (refs[0]->transform[4]+trans[0].x==0
		   && refs[0]->transform[5]+trans[0].y==0))
		 && ((flags&ps_flag_nohints)
		     || NeverConflicts(refs, instance_count)
		     || AllStationary(refs, trans, instance_count))) {
	 ExpandRef1(gb, base, instance_count, hdb, refs, trans, current,
		    subrs, round, iscjk, layer);
      } else {
	 for (i=0; i<instance_count; ++i) {
	    subtrans[i].x=trans[i].x+refs[i]->transform[4];
	    subtrans[i].y=trans[i].y+refs[i]->transform[5];
	    rscs[i]=refs[i]->sc;
	 }
	 if (!hdb->noconflicts && NeverConflicts(refs, instance_count)) {
	    CallTransformedHintSubr(gb, hdb, base, refs, trans,
				    instance_count, round);
	    hdb->noconflicts=true;
	 }
	 RSC2PS1(gb, base, rscs, hdb, subtrans, subrs, current, flags, iscjk,
		 instance_count, layer);
	 hdb->noconflicts=wasntconflicted;
      }
      for (i=0; i<instance_count; ++i)
	 refs[i]=refs[i]->next;
   }
}

static unsigned char *SplineChar2PS(SplineChar *sc,int *len,int round,
				    int iscjk, struct pschars *subrs,
				    int flags, enum fontformat format,
				    GlyphInfo * gi) {
   DBounds b;
   GrowBuf gb;
   DBasePoint current[MmMax];
   unsigned char *ret;
   struct hintdb hintdb, *hdb=NULL;
   StemInfo *oldh[MmMax], *oldv[MmMax];
   int hc[MmMax], vc[MmMax];
   BasePoint trans[MmMax];
   int instance_count, i;
   SplineChar *scs[MmMax];
   double data[MmMax][6];
   MMSet *mm=sc->parent->mm;
   HintMask *hm[MmMax];
   int fixuphm=false;

   if (!(flags&ps_flag_nohints) && SCNeedsSubsPts(sc, format, gi->layer))
      SCFigureHintMasks(sc, gi->layer);

   if ((format==ff_mma || format==ff_mmb) && mm != NULL) {
      instance_count=mm->instance_count;
      if (instance_count>16)
	 instance_count=16;
      for (i=0; i<instance_count; ++i)
	 scs[i]=mm->instances[i]->glyphs[sc->orig_pos];
   } else {
      instance_count=1;
      scs[0]=sc;
      mm=NULL;
   }

   if (flags&ps_flag_nohints) {
      for (i=0; i<instance_count; ++i) {
	 oldh[i]=scs[i]->hstem;
	 oldv[i]=scs[i]->vstem;
	 hc[i]=scs[i]->hconflicts;
	 vc[i]=scs[i]->vconflicts;
	 scs[i]->hstem=NULL;
	 scs[i]->vstem=NULL;
	 scs[i]->hconflicts=false;
	 scs[i]->vconflicts=false;
      }
   } else {
      for (i=0; i<instance_count; ++i)
	 if (scs[i]->vconflicts || scs[i]->hconflicts)
	    break;
      if (scs[0]->layers[gi->layer].splines != NULL && i==instance_count) {	/* No conflicts */
	 fixuphm=true;
	 for (i=0; i<instance_count; ++i) {
	    hm[i]=scs[i]->layers[gi->layer].splines->first->hintmask;
	    scs[i]->layers[gi->layer].splines->first->hintmask=NULL;
	 }
      }
   }

   memset(&gb, '\0', sizeof(gb));
   memset(current, '\0', sizeof(current));
   for (i=0; i<instance_count; ++i) {
      SplineCharFindBounds(scs[i], &b);
      scs[i]->lsidebearing=current[i].x=myround(b.minx, round);
      data[i][0]=current[i].x;
      data[i][1]=scs[i]->width;
   }
   AddData(&gb, data, instance_count, 2, round);
   *gb.pt++=13;		/* hsbw, lbearing&width */

   memset(&hintdb, 0, sizeof(hintdb));
   hintdb.subrs=subrs;
   hintdb.iscjk=iscjk&~0x100;
   hintdb.scs=scs;
   hintdb.instance_count=instance_count;
   hintdb.cnt=NumberHints(scs, instance_count);
   hintdb.noconflicts=true;
   hintdb.gi=gi;
   for (i=0; i<instance_count; ++i)
      if (scs[i]->hconflicts || scs[i]->vconflicts)
	 hintdb.noconflicts=false;
   hdb=&hintdb;
   if (gi != NULL)
      gi->bcnt=-1;

   /* If this char is being placed in a subroutine, then we don't want to */
   /*  use seac because somebody is going to call that subroutine and */
   /*  add another reference to it later. CID keyed fonts also can't use */
   /*  seac (they have no encoding so it doesn't work), that's what iscjk&0x100 */
   /*  tests for */
   if (scs[0]->ttf_glyph==0x7fff && !(iscjk&0x100)
       && !(flags&ps_flag_noseac)
       && IsSeacable(&gb, scs, instance_count, round, gi->layer)) {
      if (gi)
	 gi->active->wasseac=true;
      /* in MM fonts, all should share the same refs, so all should be */
      /* seac-able if one is */
   } else {
      iscjk &= ~0x100;
      if (iscjk && instance_count==1)
	 CounterHints1(&gb, sc, round);	/* Must come immediately after hsbw */
      if (hintdb.noconflicts) {
	 CvtPsHints(&gb, scs, instance_count, true, round, iscjk, NULL);
	 CvtPsHints(&gb, scs, instance_count, false, round, iscjk, NULL);
      }
      memset(&trans, 0, sizeof(trans));
      RSC2PS1(&gb, scs, scs, hdb, trans, subrs, current, flags, iscjk,
	      instance_count, gi->layer);
   }
   if (gi->bcnt==-1) {	/* If it's whitespace */
      gi->bcnt=0;
      StartNextSubroutine(&gb, hdb);
   }
   BreakSubroutine(&gb, hdb);
   MoveSubrsToChar(gi);
   ret=NULL;

   if (hdb != NULL) {
      struct mhlist *mh, *mhnext;

      for (mh=hdb->sublist; mh != NULL; mh=mhnext) {
	 mhnext=mh->next;
	 free(mh);
      }
   }
   free(gb.base);
   if (flags&ps_flag_nohints) {
      for (i=0; i<instance_count; ++i) {
	 scs[i]->hstem=oldh[i];
	 scs[i]->vstem=oldv[i];
	 scs[i]->hconflicts=hc[i];
	 scs[i]->vconflicts=vc[i];
      }
   } else if (fixuphm) {
      for (i=0; i<instance_count; ++i)
	 scs[i]->layers[gi->layer].splines->first->hintmask=hm[i];
   }
   return (ret);
}

/* Mark those glyphs which can live totally in subrs */
static void SplineFont2FullSubrs1(int flags,GlyphInfo *gi) {
   int i;
   SplineChar *sc;

   if (!autohint_before_generate && !(flags&ps_flag_nohints))
      SplineFontAutoHintRefs(gi->sf, gi->layer);
   for (i=0; i<gi->glyphcnt; ++i)
      if ((sc=gi->gb[i].sc) != NULL)
	 sc->ttf_glyph=0x7fff;
}

int SFOneWidth(SplineFont *sf) {
   int width, i;

   width=-2;
   for (i=0; i<sf->glyphcnt; ++i)
      if (SCWorthOutputting(sf->glyphs[i]) &&
	  (strcmp(sf->glyphs[i]->name, ".notdef") != 0
	   || sf->glyphs[i]->layers[ly_fore].splines != NULL)) {
	 /* Only trust the width of notdef if it's got some content */
	 /* (at least as far as fixed pitch determination goes) */
	 if (width==-2)
	    width=sf->glyphs[i]->width;
	 else if (width != sf->glyphs[i]->width) {
	    width=-1;
	    break;
	 }
      }
   return (width);
}

int CIDOneWidth(SplineFont *_sf) {
   int width, i;
   int k;
   SplineFont *sf;

   if (_sf->cidmaster != NULL)
      _sf=_sf->cidmaster;
   width=-2;
   k=0;
   do {
      sf=_sf->subfonts==NULL?_sf:_sf->subfonts[k];
      for (i=0; i<sf->glyphcnt; ++i)
	 if (SCWorthOutputting(sf->glyphs[i]) &&
	     strcmp(sf->glyphs[i]->name, ".null") != 0 &&
	     strcmp(sf->glyphs[i]->name, "nonmarkingreturn") != 0 &&
	     (strcmp(sf->glyphs[i]->name, ".notdef") != 0
	      || sf->glyphs[i]->layers[ly_fore].splines != NULL)) {
	    /* Only trust the width of notdef if it's got some content */
	    /* (at least as far as fixed pitch determination goes) */
	    if (width==-2)
	       width=sf->glyphs[i]->width;
	    else if (width != sf->glyphs[i]->width) {
	       width=-1;
	       break;
	    }
	 }
      ++k;
   } while (k<_sf->subfontcnt);
   return (width);
}

int SFIsCJK(SplineFont *sf, EncMap * map) {
   char *val;

   if ((val=PSDictHasEntry(sf->private, "LanguageGroup")) != NULL)
      return (strtol(val, NULL, 10));

   if (map->enc->is_japanese || map->enc->is_korean ||
       map->enc->is_tradchinese || map->enc->is_simplechinese)
      return (true);
   if ((map->enc->is_unicodebmp || map->enc->is_unicodefull) &&
       sf->glyphcnt>0x3000 &&
       SCWorthOutputting(sf->glyphs[0x3000]) &&
       !SCWorthOutputting(sf->glyphs['A']))
      return (true);
   if (map->enc==&custom) {
      /* If it's in a CID font and it doesn't contain alphabetics, then */
      /*  it's assumed to be CJK */
      if (sf->cidmaster != NULL)
	 return (!SCWorthOutputting(SFGetChar(sf, 'A', NULL)) && !SCWorthOutputting(SFGetChar(sf, 0x391, NULL)) &&	/* Alpha */
		 !SCWorthOutputting(SFGetChar(sf, 0x410, NULL)) &&	/* Cyrillic A */
		 !SCWorthOutputting(SFGetChar(sf, -1, "uni0041.hw")));	/* Halfwidth A, non standard name, from my cidmap */
   }

   return (false);
}

static void SetupType1Subrs(struct pschars *subrs,GlyphInfo *gi) {
   int scnt, call_size;
   int i;

   scnt=subrs->next;
   call_size=gi->pcnt+scnt<1131?3:6;
   for (i=0; i<gi->pcnt; ++i) {
      /* A subroutine call takes somewhere between 2 and 6 bytes itself. */
      /*  and we must add a return statement to the end. We don't want to */
      /*  make things bigger */
      if (gi->psubrs[i].full_glyph_index != -1)
	 gi->psubrs[i].idx=scnt++;
      else if (gi->psubrs[i].cnt * gi->psubrs[i].len >
	       (gi->psubrs[i].cnt * call_size)+gi->psubrs[i].len+1)
	 gi->psubrs[i].idx=scnt++;
      else
	 gi->psubrs[i].idx=-1;
   }

   subrs->cnt=scnt;
   subrs->next=scnt;
   subrs->lens=realloc(subrs->lens, scnt * sizeof(int));
   subrs->values=realloc(subrs->values, scnt * sizeof(unsigned char *));

   for (i=0; i<gi->pcnt; ++i) {
      scnt=gi->psubrs[i].idx;
      if (scnt==-1 || gi->psubrs[i].full_glyph_index != -1)
	 continue;
      subrs->lens[scnt]=gi->psubrs[i].len+1;
      subrs->values[scnt]=malloc(subrs->lens[scnt]);
      memcpy(subrs->values[scnt], gi->psubrs[i].data, gi->psubrs[i].len);
      subrs->values[scnt][gi->psubrs[i].len]=11;	/* Add a return to end of subr */
   }
}

static void SetupType1Chrs(struct pschars *chrs,struct pschars *subrs,
			   GlyphInfo * gi, int iscid) {
   int i, k, j;

   /* If a glyph lives entirely in a subroutine then we need to create both */
   /*  the subroutine entry, and the char entry which calls the subr. */
   /* The subroutine entry will be everything EXCEPT the glyph header */
   /* the char entry will be the glyph header and a subroutine call */
   /* If the glyph does not go into a subr then everything goes into the char */
   for (i=0; i<gi->glyphcnt; ++i) {
      int len=0;
      struct glyphbits *gb=&gi->gb[i];

      if (gb->sc==NULL)
	 continue;
      if (!iscid)
	 chrs->keys[i]=fastrdup(gb->sc->name);
      for (k=0; k<2; ++k)
	 if (k != 0 || gb->sc->ttf_glyph != 0x7fff) {
	    uint8_t *vals;

	    for (j=0; j<gb->bcnt; ++j) {
	       if (k != 0 || j != 0)
		  len += gb->bits[j].dlen;
	       if (k==1 && gb->sc->ttf_glyph != 0x7fff) {
		  int si=gi->psubrs[gb->sc->ttf_glyph].idx;

		  len += 1+(si <= 107?1:si <= 1131?2:5);
		  break;
	       }
	       if (gi->psubrs[gb->bits[j].psub_index].idx==-1)
		  len += gi->psubrs[gb->bits[j].psub_index].len;
	       else {
		  int si=gi->psubrs[gb->bits[j].psub_index].idx;

		  len += 1+(si <= 107?1:si <= 1131?2:5);
		  /* Space for a subr call&the sub number to call */
	       }
	    }
	    if (k==0) {
	       int si=gi->psubrs[gb->sc->ttf_glyph].idx;

	       subrs->lens[si]=len+1;
	       vals=subrs->values[si]=malloc(len+2);
	    } else {
	       /* Don't need or want and endchar if we are using seac */
	       chrs->lens[i]=len+!gb->wasseac;
	       vals=chrs->values[i]=malloc(len+2);	/* space for endchar and a final NUL (which is really meaningless, but makes me feel better) */
	    }

	    len=0;
	    for (j=0; j<gb->bcnt; ++j) {
	       int si;

	       if (k != 0 || j != 0) {
		  memcpy(vals+len, gb->bits[j].data, gb->bits[j].dlen);
		  len += gb->bits[j].dlen;
	       }
	       si=-1;
	       if (k==1 && gb->sc->ttf_glyph != 0x7fff)
		  si=gi->psubrs[gb->sc->ttf_glyph].idx;
	       else if (gi->psubrs[gb->bits[j].psub_index].idx==-1) {
		  memcpy(vals+len, gi->psubrs[gb->bits[j].psub_index].data,
			 gi->psubrs[gb->bits[j].psub_index].len);
		  len += gi->psubrs[gb->bits[j].psub_index].len;
	       } else
		  si=gi->psubrs[gb->bits[j].psub_index].idx;
	       if (si != -1) {
		  /* space for the number (subroutine index) */
		  if (si <= 107)
		     vals[len++]=si+139;
		  else if (si>0 && si <= 1131) {
		     si -= 108;
		     vals[len++]=(si >> 8)+247;
		     vals[len++]=si&0xff;
		  } else {
		     vals[len++]='\377';
		     vals[len++]=(si >> 24)&0xff;
		     vals[len++]=(si >> 16)&0xff;
		     vals[len++]=(si >> 8)&0xff;
		     vals[len++]=si&0xff;
		  }
		  /* space for the subroutine operator */
		  vals[len++]=10;
	       }
	       if (k==1 && gb->sc->ttf_glyph != 0x7fff)
		  break;
	    }
	    if (k==0) {
	       vals[len++]=11;	/* return */
	       vals[len]='\0';
	    } else if (gb->wasseac) {
	       /* Don't want an endchar */
	       vals[len]='\0';
	    } else {
	       vals[len++]=14;	/* endchar */
	       vals[len]='\0';
	    }
	 }
   }
}

struct pschars *SplineFont2ChrsSubrs(SplineFont *sf, int iscjk,
				     struct pschars *subrs, int flags,
				     enum fontformat format, int layer) {
   struct pschars *chrs=calloc(1, sizeof(struct pschars));
   int i, cnt, instance_count;
   int fixed;
   int notdef_pos;
   MMSet *mm=sf->mm;
   int round=(flags&ps_flag_round)?true:false;
   GlyphInfo gi;
   SplineChar dummynotdef, *sc;

   if ((format==ff_mma || format==ff_mmb) && mm != NULL) {
      instance_count=mm->instance_count;
      sf=mm->instances[0];
      fixed=0;
      for (i=0; i<instance_count; ++i) {
	 MarkTranslationRefs(mm->instances[i], layer);
	 fixed=SFOneWidth(mm->instances[i]);
	 if (fixed==-1)
	    break;
      }
   } else {
      MarkTranslationRefs(sf, layer);
      fixed=SFOneWidth(sf);
      instance_count=1;
   }

   notdef_pos=SFFindNotdef(sf, fixed);
   cnt=0;
   for (i=0; i<sf->glyphcnt; ++i)
#if HANYANG
      if (sf->glyphs[i] != NULL && sf->glyphs[i]->compositionunit)
	 /* Don't count it */ ;
      else
#endif
      if (SCWorthOutputting(sf->glyphs[i]) &&
	     (i==notdef_pos || strcmp(sf->glyphs[i]->name, ".notdef") != 0))
	 ++cnt;
/* only honor the width on .notdef in non-fixed pitch fonts (or ones where there is an actual outline in notdef) */
   if (notdef_pos==-1)
      ++cnt;			/* one notdef entry */

   memset(&gi, 0, sizeof(gi));
   memset(&gi.hashed, -1, sizeof(gi.hashed));
   gi.instance_count=1;
   gi.sf=sf;
   gi.layer=layer;
   gi.glyphcnt=cnt;
   gi.gb=calloc(cnt, sizeof(struct glyphbits));
   gi.pmax=3*cnt;
   gi.psubrs=malloc(gi.pmax * sizeof(struct potentialsubrs));
   gi.instance_count=instance_count;

   if (notdef_pos==-1) {
      memset(&dummynotdef, 0, sizeof(dummynotdef));
      dummynotdef.name=".notdef";
      dummynotdef.parent=sf;
      dummynotdef.layer_cnt=sf->layer_cnt;
      dummynotdef.layers=calloc(sf->layer_cnt, sizeof(Layer));
      dummynotdef.width=SFOneWidth(sf);
      if (dummynotdef.width==-1)
	 dummynotdef.width=(sf->ascent+sf->descent)/2;
      gi.gb[0].sc=&dummynotdef;
   } else
      gi.gb[0].sc=sf->glyphs[notdef_pos];
   cnt=1;
   for (i=0; i<sf->glyphcnt; ++i) {
#if HANYANG
      if (sf->glyphs[i] != NULL && sf->glyphs[i]->compositionunit)
	 /* don't output it, should be in a subroutine */ ;
      else
#endif
      if (SCWorthOutputting(sf->glyphs[i]) && strcmp(sf->glyphs[i]->name, ".notdef") != 0)	/* We've already added .notdef */
	 gi.gb[cnt++].sc=sf->glyphs[i];
   }

   SplineFont2FullSubrs1(flags, &gi);

   for (i=0; i<cnt; ++i) {
      if ((sc=gi.gb[i].sc)==NULL)
	 continue;
      gi.active=&gi.gb[i];
      SplineChar2PS(sc, NULL, round, iscjk, subrs, flags, format, &gi);
   }

   SetupType1Subrs(subrs, &gi);

   chrs->cnt=cnt;
   chrs->keys=malloc(cnt * sizeof(char *));
   chrs->lens=malloc(cnt * sizeof(int));
   chrs->values=malloc(cnt * sizeof(unsigned char *));

   SetupType1Chrs(chrs, subrs, &gi, false);

   GIFree(&gi, &dummynotdef);

   chrs->next=cnt;
   if (chrs->next>chrs->cnt)
      ErrorMsg(2,"Character estimate failed, about to die...\n");
   return (chrs);
}

struct pschars *CID2ChrsSubrs(SplineFont *cidmaster,
			      struct cidbytes *cidbytes, int flags,
			      int layer) {
   struct pschars *chrs=calloc(1, sizeof(struct pschars));
   int i, cnt, cid;
   SplineFont *sf=NULL;
   struct fddata *fd;
   int round=(flags&ps_flag_round)?true:false;

   /* I don't support mm cid files. I don't think adobe does either */
   GlyphInfo gi;
   int notdef_subfont;
   SplineChar dummynotdef, *sc;

   cnt=0;
   notdef_subfont=-1;
   for (i=0; i<cidmaster->subfontcnt; ++i) {
      if (cnt<cidmaster->subfonts[i]->glyphcnt)
	 cnt=cidmaster->subfonts[i]->glyphcnt;
      if (cidmaster->subfonts[i]->glyphcnt>0 &&
	  SCWorthOutputting(cidmaster->subfonts[i]->glyphs[0]))
	 notdef_subfont=i;
   }
   cidbytes->cidcnt=cnt;

   if (notdef_subfont==-1) {
      memset(&dummynotdef, 0, sizeof(dummynotdef));
      dummynotdef.name=".notdef";
      dummynotdef.parent=cidmaster->subfonts[0];
      dummynotdef.layer_cnt=layer+1;
      dummynotdef.layers=calloc(layer+1, sizeof(Layer));;
      dummynotdef.width=SFOneWidth(dummynotdef.parent);
      if (dummynotdef.width==-1)
	 dummynotdef.width =
	    (dummynotdef.parent->ascent+dummynotdef.parent->descent);
   }

   memset(&gi, 0, sizeof(gi));
   gi.instance_count=1;
   gi.glyphcnt=cnt;
   gi.gb=malloc(cnt * sizeof(struct glyphbits));
   gi.pmax=3*cnt;
   gi.psubrs=malloc(gi.pmax * sizeof(struct potentialsubrs));
   gi.layer=layer;

   chrs->cnt=cnt;
   chrs->lens=calloc(cnt, sizeof(int));
   chrs->values=calloc(cnt, sizeof(unsigned char *));
   cidbytes->fdind=malloc(cnt * sizeof(unsigned char *));
   memset(cidbytes->fdind, -1, cnt * sizeof(unsigned char *));

   /* In a type1 CID-keyed font we must handle subroutines subfont by subfont */
   /*  as there are no global subrs */
   for (i=0; i<cidmaster->subfontcnt; ++i) {
      gi.sf=sf=cidmaster->subfonts[i];
      MarkTranslationRefs(sf, layer);
      fd=&cidbytes->fds[i];
      memset(&gi.hashed, -1, sizeof(gi.hashed));
      gi.instance_count=1;
      gi.glyphcnt=sf->glyphcnt;
      memset(gi.gb, 0, sf->glyphcnt * sizeof(struct glyphbits));
      for (cid=0; cid<cnt && cid<sf->glyphcnt; ++cid) {
	 if (cid==0 && notdef_subfont==-1
	     && i==cidmaster->subfontcnt-1)
	    gi.gb[0].sc=&dummynotdef;
	 else if (SCWorthOutputting(sf->glyphs[cid]) && ((i==notdef_subfont && cid==0) || strcmp(sf->glyphs[cid]->name, ".notdef") != 0))	/* We've already added .notdef */
	    gi.gb[cid].sc=sf->glyphs[cid];
	 if (gi.gb[cid].sc != NULL)
	    cidbytes->fdind[cid]=i;
      }
      SplineFont2FullSubrs1(flags, &gi);

      for (cid=0; cid<cnt && cid<sf->glyphcnt; ++cid) {
	 if ((sc=gi.gb[cid].sc)==NULL)
	    continue;
	 gi.active=&gi.gb[cid];
	 SplineChar2PS(sc, NULL, round, fd->iscjk|0x100, fd->subrs,
		       flags, ff_cid, &gi);
      }

      SetupType1Subrs(fd->subrs, &gi);
      SetupType1Chrs(chrs, fd->subrs, &gi, true);
      GIContentsFree(&gi, &dummynotdef);
   }
   GIFree(&gi, &dummynotdef);
   chrs->next=cnt;
   return (chrs);
}

/* ************************************************************************** */
/* ********************** Type2 PostScript CharStrings ********************** */
/* ************************************************************************** */

static double myround2(double pos,int round) {
   if (round)
      return (rint(pos));

   return (rint(65536*pos)/65536);
}

static void AddNumber2(GrowBuf *gb,double pos,int round) {
   int val, factor;
   unsigned char *str;

   if (gb->pt+5 >= gb->end)
      GrowBuffer(gb);

   pos=rint(65536*pos)/65536;
   if (round)
      pos=rint(pos);

   str=gb->pt;
   if (pos>32767.99 || pos<-32768) {
      /* same logic for big ints and reals */
      if (pos>0x3fffffff || pos<-0x40000000) {
	 ErrorMsg(2,"Number out of range: %g in type2 output (must be [-65536,65535])\n",
		  pos);
	 if (pos>0)
	    pos=0x3fffffff;
	 else
	    pos=-0x40000000;
      }
      for (factor=2; factor<32768; factor <<= 2)
	 if (pos/factor<32767.99 && pos/factor>-32768)
	    break;
      AddNumber2(gb, pos/factor, false);
      AddNumber2(gb, factor, false);
      if (gb->pt+2 >= gb->end)
	 GrowBuffer(gb);
      *(gb->pt++)=0x0c;	/* Multiply operator */
      *(gb->pt++)=0x18;
   } else if (pos != floor(pos)) {
      val=pos*65536;
      *str++='\377';
      *str++=(val >> 24)&0xff;
      *str++=(val >> 16)&0xff;
      *str++=(val >> 8)&0xff;
      *str++=val&0xff;
   } else {
      val=rint(pos);
      if (pos >= -107 && pos <= 107)
	 *str++=val+139;
      else if (pos >= 108 && pos <= 1131) {
	 val -= 108;
	 *str++=(val >> 8)+247;
	 *str++=val&0xff;
      } else if (pos >= -1131 && pos <= -108) {
	 val=-val;
	 val -= 108;
	 *str++=(val >> 8)+251;
	 *str++=val&0xff;
      } else {
	 *str++=28;
	 *str++=(val >> 8)&0xff;
	 *str++=val&0xff;
      }
   }
   gb->pt=str;
}

static void AddMask2(GrowBuf *gb,uint8_t mask[12],int cnt,int oper) {
   int i;

   if (gb->pt+1+((cnt+7) >> 3) >= gb->end)
      GrowBuffer(gb);
   *gb->pt++=oper;		/* hintmask,cntrmask */
   for (i=0; i<((cnt+7) >> 3); ++i)
      *gb->pt++=mask[i];
}

static void CounterHints2(GrowBuf *gb,SplineChar *sc,int hcnt) {
   int i;

   for (i=0; i<sc->countermask_cnt; ++i)
      AddMask2(gb, sc->countermasks[i], hcnt, 20);	/* cntrmask */
}

static int HintSetup2(GrowBuf *gb,struct hintdb *hdb,SplinePoint *to,
		      int break_subr) {

   /* We might get a point with a hintmask in a glyph with no conflicts */
   /* (ie. the initial point when we return to it at the end of the splineset */
   /* in that case hdb->cnt will be 0 and we should ignore it */
   /* components in subroutines depend on not having any hintmasks */
   if (to->hintmask==NULL || hdb->cnt==0 || hdb->noconflicts
       || hdb->skiphm)
      return (false);

   if (memcmp(hdb->mask, *to->hintmask, (hdb->cnt+7)/8)==0)
      return (false);

   if (break_subr)
      BreakSubroutine(gb, hdb);

   AddMask2(gb, *to->hintmask, hdb->cnt, 19);	/* hintmask */
   memcpy(hdb->mask, *to->hintmask, sizeof(HintMask));
   hdb->donefirsthm=true;
   if (break_subr)
      StartNextSubroutine(gb, hdb);
   return (true);
}

static void moveto2(GrowBuf *gb,struct hintdb *hdb,SplinePoint *to,
		    int round) {
   BasePoint temp, *tom;

   if (gb->pt+18 >= gb->end)
      GrowBuffer(gb);

   BreakSubroutine(gb, hdb);
   HintSetup2(gb, hdb, to, false);
   tom=&to->me;
   if (round) {
      temp.x=rint(tom->x);
      temp.y=rint(tom->y);
      tom=&temp;
   }
   if (hdb->current.x==tom->x) {
      AddNumber2(gb, tom->y-hdb->current.y, round);
      *(gb->pt)++=4;		/* v move to */
   } else if (hdb->current.y==tom->y) {
      AddNumber2(gb, tom->x-hdb->current.x, round);
      *(gb->pt)++=22;		/* h move to */
   } else {
      AddNumber2(gb, tom->x-hdb->current.x, round);
      AddNumber2(gb, tom->y-hdb->current.y, round);
      *(gb->pt)++=21;		/* r move to */
   }
   hdb->current.x=rint(32768*tom->x)/32768;
   hdb->current.y=rint(32768*tom->y)/32768;
   StartNextSubroutine(gb, hdb);
}

static Spline *lineto2(GrowBuf *gb,struct hintdb *hdb,Spline *spline,
		       Spline * done, int round) {
   int cnt, hv, hvcnt;
   Spline *test, *lastgood, *lasthvgood;
   BasePoint temp1, temp2, *tom, *fromm;
   int donehm;

   lastgood=NULL;
   for (test=spline, cnt=0; test->knownlinear && cnt<15;) {
      ++cnt;
      lastgood=test;
      test=test->to->next;
      /* it will be smaller to use a closepath operator so ignore the */
      /*  ultimate spline */
      if (test==done || test==NULL || test->to->next==done)
	 break;
   }

   HintSetup2(gb, hdb, spline->to, true);

   hv=-1;
   hvcnt=1;
   lasthvgood=NULL;
   if (spline->from->me.x==spline->to->me.x)
      hv=1;			/* Vertical */
   else if (spline->from->me.y==spline->to->me.y)
      hv=0;			/* Horizontal */
   donehm=true;
   if (hv != -1) {
      lasthvgood=spline;
      hvcnt=1;
      if (cnt != 1) {
	 for (test=spline->to->next; test != NULL; test=test->to->next) {
	    fromm=&test->from->me;
	    if (round) {
	       temp2.x=rint(fromm->x);
	       temp2.y=rint(fromm->y);
	       fromm=&temp2;
	    }
	    tom=&test->to->me;
	    if (round) {
	       temp1.x=rint(tom->x);
	       temp1.y=rint(tom->y);
	       tom=&temp1;
	    }
	    if (hv==1 && tom->y==fromm->y)
	       hv=0;
	    else if (hv==0 && tom->x==fromm->x)
	       hv=1;
	    else
	       break;
	    lasthvgood=test;
	    ++hvcnt;
	    if (test==lastgood)
	       break;
	 }
      }
      donehm=true;
      if (hvcnt==cnt || hvcnt >= 2) {
	 /* It's more efficient to do some h/v linetos */
	 for (test=spline;; test=test->to->next) {
	    if (!donehm && test->to->hintmask != NULL)
	       break;
	    donehm=false;
	    fromm=&test->from->me;
	    if (round) {
	       temp2.x=rint(fromm->x);
	       temp2.y=rint(fromm->y);
	       fromm=&temp2;
	    }
	    tom=&test->to->me;
	    if (round) {
	       temp1.x=rint(tom->x);
	       temp1.y=rint(tom->y);
	       tom=&temp1;
	    }
	    if (fromm->x==tom->x)
	       AddNumber2(gb, tom->y-fromm->y, round);
	    else
	       AddNumber2(gb, tom->x-fromm->x, round);
	    hdb->current.x=rint(32768*tom->x)/32768;
	    hdb->current.y=rint(32768*tom->y)/32768;
	    if (test==lasthvgood) {
	       test=test->to->next;
	       break;
	    }
	 }
	 if (gb->pt+1 >= gb->end)
	    GrowBuffer(gb);
	 *(gb->pt)++=spline->from->me.x==spline->to->me.x?7:6;
	 return (test);
      }
   }

   for (test=spline; test != NULL; test=test->to->next) {
      if (!donehm && test->to->hintmask != NULL)
	 break;
      donehm=false;
      fromm=&test->from->me;
      if (round) {
	 temp2.x=rint(fromm->x);
	 temp2.y=rint(fromm->y);
	 fromm=&temp2;
      }
      tom=&test->to->me;
      if (round) {
	 temp1.x=rint(tom->x);
	 temp1.y=rint(tom->y);
	 tom=&temp1;
      }
      AddNumber2(gb, tom->x-fromm->x, round);
      AddNumber2(gb, tom->y-fromm->y, round);
      hdb->current.x=rint(32768*tom->x)/32768;
      hdb->current.y=rint(32768*tom->y)/32768;
      if (test==lastgood) {
	 test=test->to->next;
	 break;
      }
   }
   if (gb->pt+1 >= gb->end)
      GrowBuffer(gb);
   *(gb->pt)++=5;		/* r line to */
   return (test);
}

static Spline *curveto2(GrowBuf *gb,struct hintdb *hdb,Spline *spline,
			Spline * done, int round) {
   int cnt=0, hv;
   Spline *first;
   DBasePoint start;
   int donehm;

   HintSetup2(gb, hdb, spline->to, true);

   hv=-1;
   if (hdb->current.x==myround2(spline->from->nextcp.x, round) &&
       myround2(spline->to->prevcp.y, round)==myround2(spline->to->me.y,
							 round))
      hv=1;
   else if (hdb->current.y==myround2(spline->from->nextcp.y, round) &&
	    myround2(spline->to->prevcp.x,
		     round)==myround2(spline->to->me.x, round))
      hv=0;
   donehm=true;
   if (hv != -1) {
      first=spline;
      start=hdb->current;
      while ((hv==1
	      && hdb->current.x==myround2(spline->from->nextcp.x, round)
	      && myround2(spline->to->prevcp.y,
			  round)==myround2(spline->to->me.y, round))
	     || (hv==0
		 && hdb->current.y==myround2(spline->from->nextcp.y, round)
		 && myround2(spline->to->prevcp.x,
			     round)==myround2(spline->to->me.x, round))) {
	 if (!donehm && spline->to->hintmask != NULL)
	    break;
	 donehm=false;
	 if (hv==1) {
	    AddNumber2(gb,
		       myround2(spline->from->nextcp.y,
				round)-hdb->current.y, round);
	    AddNumber2(gb,
		       myround2(spline->to->prevcp.x,
				round)-myround2(spline->from->nextcp.x,
						  round), round);
	    AddNumber2(gb,
		       myround2(spline->to->prevcp.y,
				round)-myround2(spline->from->nextcp.y,
						  round), round);
	    AddNumber2(gb,
		       myround2(spline->to->me.x,
				round)-myround2(spline->to->prevcp.x,
						  round), round);
	    hv=0;
	 } else {
	    AddNumber2(gb,
		       myround2(spline->from->nextcp.x,
				round)-hdb->current.x, round);
	    AddNumber2(gb,
		       myround2(spline->to->prevcp.x,
				round)-myround2(spline->from->nextcp.x,
						  round), round);
	    AddNumber2(gb,
		       myround2(spline->to->prevcp.y,
				round)-myround2(spline->from->nextcp.y,
						  round), round);
	    AddNumber2(gb,
		       myround2(spline->to->me.y,
				round)-myround2(spline->to->prevcp.y,
						  round), round);
	    hv=1;
	 }
	 hdb->current.x=myround2(spline->to->me.x, round);
	 hdb->current.y=myround2(spline->to->me.y, round);
	 ++cnt;
	 spline=spline->to->next;
	 if (spline==done || spline==NULL || cnt>9
	     || spline->knownlinear)
	    break;
      }
      if (gb->pt+1 >= gb->end)
	 GrowBuffer(gb);
      *(gb->pt)++=(start.x==myround2(first->from->nextcp.x, round) && myround2(first->to->prevcp.y, round)==myround2(first->to->me.y, round))?30:31;	/* vhcurveto:hvcurveto */
      return (spline);
   }
   while (cnt<6) {
      if (!donehm && spline->to->hintmask != NULL)
	 break;
      donehm=false;
      hv=-1;
      if (hdb->current.x==myround2(spline->from->nextcp.x, round) &&
	  myround2(spline->to->prevcp.y, round)==myround2(spline->to->me.y,
							    round)
	  && spline->to->next != NULL
	  && myround2(spline->to->me.y,
		      round)==myround2(spline->to->nextcp.y, round)
	  && myround2(spline->to->next->to->prevcp.x,
		      round)==myround2(spline->to->next->to->me.x, round))
	 break;
      else if (hdb->current.y==myround2(spline->from->nextcp.y, round) &&
	       myround2(spline->to->prevcp.x,
			round)==myround2(spline->to->me.x, round)
	       && spline->to->next != NULL
	       && myround2(spline->to->me.x,
			   round)==myround2(spline->to->nextcp.x, round)
	       && myround2(spline->to->next->to->prevcp.y,
			   round)==myround2(spline->to->next->to->me.y,
					      round))
	 break;
      AddNumber2(gb, myround2(spline->from->nextcp.x, round)-hdb->current.x,
		 round);
      AddNumber2(gb, myround2(spline->from->nextcp.y, round)-hdb->current.y,
		 round);
      AddNumber2(gb,
		 myround2(spline->to->prevcp.x,
			  round)-myround2(spline->from->nextcp.x, round),
		 round);
      AddNumber2(gb,
		 myround2(spline->to->prevcp.y,
			  round)-myround2(spline->from->nextcp.y, round),
		 round);
      AddNumber2(gb,
		 myround2(spline->to->me.x,
			  round)-myround2(spline->to->prevcp.x, round),
		 round);
      AddNumber2(gb,
		 myround2(spline->to->me.y,
			  round)-myround2(spline->to->prevcp.y, round),
		 round);
      hdb->current.x=myround2(spline->to->me.x, round);
      hdb->current.y=myround2(spline->to->me.y, round);
      ++cnt;
      spline=spline->to->next;
      if (spline==done || spline==NULL || spline->knownlinear)
	 break;
   }
   if (gb->pt+1 >= gb->end)
      GrowBuffer(gb);
   *(gb->pt)++=8;		/* rrcurveto */
   return (spline);
}

static void flexto2(GrowBuf *gb,struct hintdb *hdb,Spline *pspline,
		    int round) {
   BasePoint *c0, *c1, *mid, *end, *nc0, *nc1;
   Spline *nspline;

   c0=&pspline->from->nextcp;
   c1=&pspline->to->prevcp;
   mid=&pspline->to->me;
   nspline=pspline->to->next;
   nc0=&nspline->from->nextcp;
   nc1=&nspline->to->prevcp;
   end=&nspline->to->me;

   HintSetup2(gb, hdb, nspline->to, true);

   if (myround2(c0->y, round)==hdb->current.y
       && myround2(nc1->y, round)==hdb->current.y
       && myround2(end->y, round)==hdb->current.y
       && myround2(c1->y, round)==myround2(mid->y, round)
       && myround2(nc0->y, round)==myround2(mid->y, round)) {
      if (gb->pt+7*6+2 >= gb->end)
	 GrowBuffer(gb);
      AddNumber2(gb, myround2(c0->x, round)-hdb->current.x, round);
      AddNumber2(gb, myround2(c1->x, round)-myround2(c0->x, round), round);
      AddNumber2(gb, myround2(c1->y, round)-myround2(c0->y, round), round);
      AddNumber2(gb, myround2(mid->x, round)-myround2(c1->x, round), round);
      AddNumber2(gb, myround2(nc0->x, round)-myround2(mid->x, round),
		 round);
      AddNumber2(gb, myround2(nc1->x, round)-myround2(nc0->x, round),
		 round);
      AddNumber2(gb, myround2(end->x, round)-myround2(nc1->x, round),
		 round);
      *gb->pt++=12;
      *gb->pt++=34;		/* hflex */
   } else {
      if (gb->pt+11*6+2 >= gb->end)
	 GrowBuffer(gb);
      AddNumber2(gb, myround2(c0->x, round)-hdb->current.x, round);
      AddNumber2(gb, myround2(c0->y, round)-hdb->current.y, round);
      AddNumber2(gb, myround2(c1->x, round)-myround2(c0->x, round), round);
      AddNumber2(gb, myround2(c1->y, round)-myround2(c0->y, round), round);
      AddNumber2(gb, myround2(mid->x, round)-myround2(c1->x, round), round);
      AddNumber2(gb, myround2(mid->y, round)-myround2(c1->y, round), round);
      AddNumber2(gb, myround2(nc0->x, round)-myround2(mid->x, round),
		 round);
      AddNumber2(gb, myround2(nc0->y, round)-myround2(mid->y, round),
		 round);
      AddNumber2(gb, myround2(nc1->x, round)-myround2(nc0->x, round),
		 round);
      AddNumber2(gb, myround2(nc1->y, round)-myround2(nc0->y, round),
		 round);
      if (hdb->current.y==myround2(end->y, round))
	 AddNumber2(gb, myround2(end->x, round)-myround2(nc1->x, round),
		    round);
      else
	 AddNumber2(gb, myround2(end->y, round)-myround2(nc1->y, round),
		    round);
      *gb->pt++=12;
      *gb->pt++=37;		/* flex1 */
   }

   hdb->current.x=rint(32768*end->x)/32768;
   hdb->current.y=rint(32768*end->y)/32768;
}

static void CvtPsSplineSet2(GrowBuf *gb,SplinePointList *spl,
			    struct hintdb *hdb, int is_order2, int round) {
   Spline *spline, *first;
   SplinePointList temp, *freeme=NULL;
   int unhinted=true;;

   if (is_order2)
      freeme=spl=SplineSetsPSApprox(spl);

   for (; spl != NULL; spl=spl->next) {
      first=NULL;
      SplineSetReverse(spl);
      /* PostScript and TrueType store their splines in in reverse */
      /*  orientations. Annoying. Oh well. I shall adopt TrueType and */
      /*  If I reverse the PS splinesets after reading them in, and then */
      /*  again when saving them out, all should be well */
      if (spl->first->flexy || spl->first->flexx) {
	 /* can't handle a flex (mid) point as the first point. rotate the */
	 /* list by one, this is possible because only closed paths have */
	 /* points marked as flex, and because we can't have two flex mid- */
	 /* points in a row */
	 if (spl->first->hintmask==NULL
	     || spl->first->next->to->hintmask != NULL) {
	    /* But we can't rotate it if we expect it to provide us with */
	    /*  a hintmask.                                              */
	    temp=*spl;
	    temp.first=temp.last=spl->first->next->to;
	    spl=&temp;
	 }
	 if (spl->first->flexy || spl->first->flexx) {
	    /* If we couldn't rotate, or if we rotated to something that */
	    /*  also is flexible, then just turn off flex. That's safe   */
	    spl->first->flexx=spl->first->flexy=false;
	 }
      }
      if (unhinted && hdb->cnt>0 && spl->first->hintmask != NULL) {
	 hdb->mask[0]=~(*spl->first->hintmask)[0];	/* Make it different */
	 unhinted=false;
      }
      moveto2(gb, hdb, spl->first, round);
      for (spline=spl->first->next; spline != NULL && spline != first;) {
	 if (first==NULL)
	    first=spline;
	 else if (first->from==spline->to)
	    hdb->skiphm=true;
	 if (spline->to->flexx || spline->to->flexy) {
	    flexto2(gb, hdb, spline, round);	/* does two adjacent splines */
	    spline=spline->to->next->to->next;
	 } else if (spline->knownlinear && spline->to==spl->first)
	    /* In Type2 we don't even need a closepath to finish this off */
	    /*  (which is good, because there isn't a close path) */
	    break;
	 else if (spline->knownlinear)
	    spline=lineto2(gb, hdb, spline, first, round);
	 else
	    spline=curveto2(gb, hdb, spline, first, round);
      }
      hdb->skiphm=false;
      /* No closepath oper in type2 fonts, it's implied */
      SplineSetReverse(spl);
      /* Of course, I have to Reverse again to get back to my convention after */
      /*  saving */
   }
   SplinePointListsFree(freeme);
}

static void DumpHints(GrowBuf *gb,StemInfo *h,int oper,int midoper,
		      int round) {
   double last=0, cur;
   int cnt;

   if (h==NULL)
      return;
   cnt=0;
   while (h != NULL && h->hintnumber != -1) {
      /* Type2 hints do not support negative widths except in the case of */
      /*  ghost (now called edge) hints */
      if (cnt>24-2) {	/* stack max=48 numbers, => 24 hints, leave a bit of slop for the width */
	 if (gb->pt+1 >= gb->end)
	    GrowBuffer(gb);
	 *gb->pt++=midoper;
	 cnt=0;
      }
      cur=myround2(h->start, round)+myround2(h->width, round);
      if (h->width<0) {
	 AddNumber2(gb, cur-last, round);
	 AddNumber2(gb, -myround2(h->width, round), round);
	 cur -= myround2(h->width, round);
      } else if (h->ghost) {
	 if (h->width==20) {
	    AddNumber2(gb, myround2(h->start, round)-last+20, round);
	    AddNumber2(gb, -20, round);
	    cur=myround2(h->start, round);
	 } else {
	    AddNumber2(gb, myround2(h->start+21, round)-last, round);
	    AddNumber2(gb, -21, round);
	    cur=myround2(h->start+21, round)-21;
	 }
      } else {
	 AddNumber2(gb, myround2(h->start, round)-last, round);
	 AddNumber2(gb, myround2(h->width, round), round);
      }
      last=cur;
      h=h->next;
      ++cnt;
   }
   if (oper != -1) {
      if (gb->pt+1 >= gb->end)
	 GrowBuffer(gb);
      *gb->pt++=oper;
   }
}

static void DumpRefsHints(GrowBuf *gb,struct hintdb *hdb,RefChar *cur,
			  StemInfo * h, StemInfo * v, BasePoint * trans,
			  int round, int layer) {
   uint8_t masks[12];
   int cnt, sets=0;
   StemInfo *rs;

   /* trans has already been rounded (whole char is translated by an integral amount) */

   /* If we have a subroutine containing conflicts, then its hints will match */
   /*  ours exactly, and we can use its hintmasks directly */
   if ((cur->sc->hconflicts || cur->sc->vconflicts) &&
       cur->sc->layers[layer].splines != NULL &&
       cur->sc->layers[layer].splines->first->hintmask != NULL) {
      AddMask2(gb, *cur->sc->layers[layer].splines->first->hintmask, hdb->cnt, 19);	/* hintmask */
      hdb->donefirsthm=true;
      memcpy(hdb->mask, *cur->sc->layers[layer].splines->first->hintmask,
	     sizeof(HintMask));
      return;
   }

   if (h==NULL && v==NULL)
      ErrorMsg(2,"hintmask invoked when there are no hints\n");
   memset(masks, '\0', sizeof(masks));
   cnt=0;
   while (h != NULL && h->hintnumber >= 0) {
      /* Horizontal stems are defined by vertical bounds */
      double pos=(round?rint(h->start):h->start)-trans->y;

      for (rs=cur->sc->hstem; rs != NULL; rs=rs->next) {
	 double rpos=round?rint(rs->start):rs->start;

	 if (rpos==pos
	     && (round?(rint(rs->width)==rint(h->width))
		:(rs->width==h->width))) {
	    masks[h->hintnumber >> 3] |= 0x80 >> (h->hintnumber&7);
	    ++sets;
	    break;
	 } else if (rpos>pos)
	    break;
      }
      h=h->next;
      ++cnt;
   }
   while (v != NULL && v->hintnumber >= 0) {
      double pos=(round?rint(v->start):v->start)-trans->x;

      for (rs=cur->sc->vstem; rs != NULL; rs=rs->next) {
	 double rpos=round?rint(rs->start):rs->start;

	 if (rpos==pos
	     && (round?(rint(rs->width)==rint(v->width))
		:(rs->width==v->width))) {
	    masks[v->hintnumber >> 3] |= 0x80 >> (v->hintnumber&7);
	    ++sets;
	    break;
	 } else if (rpos>pos)
	    break;
      }
      v=v->next;
      ++cnt;
   }
   BreakSubroutine(gb, hdb);
   hdb->donefirsthm=true;
   /* if (sets!=0 ) */ /* First ref will need a hintmask even if it has no hints (if there are conflicts) */
   AddMask2(gb, masks, cnt, 19);	/* hintmask */
}

static void DummyHintmask(GrowBuf *gb,struct hintdb *hdb) {
   HintMask hm;

   memset(hm, 0, sizeof(hm));
   if (hdb->cnt != 0) {
      BreakSubroutine(gb, hdb);
      hdb->donefirsthm=true;
      AddMask2(gb, hm, hdb->cnt, 19);	/* hintmask */
   }
}

static void SetTransformedHintMask(GrowBuf *gb,struct hintdb *hdb,
				   SplineChar * sc, RefChar * ref,
				   BasePoint * trans, int round) {
   HintMask hm;

   if (HintMaskFromTransformedRef(ref, trans, sc, &hm) != NULL) {
      BreakSubroutine(gb, hdb);
      hdb->donefirsthm=true;
      AddMask2(gb, hm, hdb->cnt, 19);	/* hintmask */
   } else if (!hdb->donefirsthm)
      DummyHintmask(gb, hdb);
}

static void ExpandRef2(GrowBuf *gb,SplineChar *sc,struct hintdb *hdb,
		       RefChar * r, BasePoint * trans,
		       struct pschars *subrs, int round, int layer) {
   BasePoint *bpt;
   BasePoint temp, rtrans;
   GlyphInfo *gi;

   /* The only refs I deal with here have no hint conflicts within them */

   rtrans.x=r->transform[4]+trans->x;
   rtrans.y=r->transform[5]+trans->y;
   if (round) {
      rtrans.x=rint(rtrans.x);
      rtrans.y=rint(rtrans.y);
   }

   BreakSubroutine(gb, hdb);
   if (hdb->cnt>0 && !hdb->noconflicts)
      DumpRefsHints(gb, hdb, r, sc->hstem, sc->vstem, &rtrans, round, layer);

   /* Translate from end of last character to where this one should */
   /*  start (we must have one moveto operator to start off, none */
   /*  in the subr) */
   bpt=hdb->gi->psubrs[r->sc->lsidebearing].startstop;
   temp.x=bpt[0].x+rtrans.x;
   temp.y=bpt[0].y+rtrans.y;
   if (hdb->current.x != temp.x)
      AddNumber2(gb, temp.x-hdb->current.x, round);
   if (hdb->current.y != temp.y || hdb->current.x==temp.x)
      AddNumber2(gb, temp.y-hdb->current.y, round);
   if (gb->pt+1 >= gb->end)
      GrowBuffer(gb);
   *gb->pt++=hdb->current.x==temp.x?4 :	/* vmoveto */
      hdb->current.y==temp.y?22 :	/* hmoveto */
      21;			/* rmoveto */
   if (r->sc->lsidebearing==0x7fff)
      ErrorMsg(2,"Attempt to reference an unreferenceable glyph %s\n", r->sc->name);

   gi=hdb->gi;
   StartNextSubroutine(gb, hdb);
   gi->bits[gi->bcnt].psub_index=r->sc->lsidebearing;
   ++gi->bcnt;
   gi->justbroken=true;
   hdb->current.x=bpt[1].x+rtrans.x;
   hdb->current.y=bpt[1].y+rtrans.y;
}

static void RSC2PS2(GrowBuf *gb,SplineChar *base,SplineChar *rsc,
		    struct hintdb *hdb, BasePoint * trans,
		    struct pschars *subrs, int flags, int layer) {
   BasePoint subtrans;
   int stationary=trans->x==0 && trans->y==0;
   RefChar *r, *unsafe=NULL;
   int unsafecnt=0, allwithouthints=true;
   int round=(flags&ps_flag_round)?true:false;
   StemInfo *oldh, *oldv;
   int hc, vc;
   SplineSet *freeme, *temp;
   int wasntconflicted=hdb->noconflicts;

   if (flags&ps_flag_nohints) {
      oldh=rsc->hstem;
      oldv=rsc->vstem;
      hc=rsc->hconflicts;
      vc=rsc->vconflicts;
      rsc->hstem=NULL;
      rsc->vstem=NULL;
      rsc->hconflicts=false;
      rsc->vconflicts=false;
   } else {
      for (r=rsc->layers[layer].refs; r != NULL; r=r->next) {
	 if (!r->justtranslated)
	    continue;
	 if (r->sc->hconflicts || r->sc->vconflicts) {
	    ++unsafecnt;
	    unsafe=r;
	 } else if (r->sc->hstem != NULL || r->sc->vstem != NULL)
	    allwithouthints=false;
      }
      if (!stationary)
	 allwithouthints=false;
      if (allwithouthints && unsafe != NULL
	  && hdb->cnt != NumberHints(&unsafe->sc, 1))
	 allwithouthints=false;	/* There are other hints elsewhere in the base glyph */
   }

   if (unsafe && allwithouthints) {
      if (unsafe->sc->lsidebearing != 0x7fff) {
	 ExpandRef2(gb, base, hdb, unsafe, trans, subrs, round, layer);
      } else if (unsafe->transform[4]==0 && unsafe->transform[5]==0)
	 RSC2PS2(gb, base, unsafe->sc, hdb, trans, subrs, flags, layer);
      else
	 unsafe=NULL;
   } else
      unsafe=NULL;

   /* What is the hintmask state here? It should not matter */
   freeme=NULL;
   temp=rsc->layers[layer].splines;
   if (base != rsc)
      temp=freeme=SPLCopyTranslatedHintMasks(temp, base, rsc, trans);
   CvtPsSplineSet2(gb, temp, hdb, rsc->layers[layer].order2, round);
   SplinePointListsFree(freeme);

   for (r=rsc->layers[layer].refs; r != NULL; r=r->next)
      if (r != unsafe) {
	 if (!r->justtranslated) {
	    if (!r->sc->hconflicts && !r->sc->vconflicts && !hdb->noconflicts
		&& r->transform[1]==0 && r->transform[2]==0
		&& r->transform[0]>0 && r->transform[3]>0)
	       SetTransformedHintMask(gb, hdb, base, r, trans, round);
	    if (!hdb->donefirsthm)
	       DummyHintmask(gb, hdb);
	    temp=SPLCopyTransformedHintMasks(r, base, trans, layer);
	    CvtPsSplineSet2(gb, temp, hdb, rsc->layers[layer].order2, round);
	    SplinePointListsFree(temp);
	 } else if (r->sc->lsidebearing != 0x7fff &&
		    ((flags&ps_flag_nohints) ||
		     (!r->sc->hconflicts && !r->sc->vconflicts))) {
	    ExpandRef2(gb, base, hdb, r, trans, subrs, round, layer);
	 } else {
	    subtrans.x=trans->x+r->transform[4];
	    subtrans.y=trans->y+r->transform[5];
	    if (!hdb->noconflicts && !r->sc->hconflicts && !r->sc->vconflicts) {
	       SetTransformedHintMask(gb, hdb, base, r, trans, round);
	       hdb->noconflicts=true;
	    }
	    RSC2PS2(gb, base, r->sc, hdb, &subtrans, subrs, flags, layer);
	    hdb->noconflicts=wasntconflicted;
	 }
      }

   if (flags&ps_flag_nohints) {
      rsc->hstem=oldh;
      rsc->vstem=oldv;
      rsc->hconflicts=hc;
      rsc->vconflicts=vc;
   }
}

static unsigned char *SplineChar2PS2(SplineChar *sc,int *len,int nomwid,
				     int defwid, struct pschars *subrs,
				     int flags, GlyphInfo * gi) {
   GrowBuf gb;
   unsigned char *ret;
   struct hintdb hdb;
   StemInfo *oldh, *oldv;
   int hc, vc;
   SplineChar *scs[MmMax];
   int round=(flags&ps_flag_round)?true:false;
   HintMask *hm=NULL;
   BasePoint trans;

   if (autohint_before_generate && sc->changedsincelasthinted &&
       !sc->manualhints && !(flags&ps_flag_nohints))
      SplineCharAutoHint(sc, gi->layer, NULL);
   if (!(flags&ps_flag_nohints) && SCNeedsSubsPts(sc, ff_otf, gi->layer))
      SCFigureHintMasks(sc, gi->layer);

   if (flags&ps_flag_nohints) {
      oldh=sc->hstem;
      oldv=sc->vstem;
      hc=sc->hconflicts;
      vc=sc->vconflicts;
      sc->hstem=NULL;
      sc->vstem=NULL;
      sc->hconflicts=false;
      sc->vconflicts=false;
   } else if (sc->layers[gi->layer].splines != NULL && !sc->vconflicts &&
	      !sc->hconflicts) {
      hm=sc->layers[gi->layer].splines->first->hintmask;
      sc->layers[gi->layer].splines->first->hintmask=NULL;
   }

   memset(&gb, '\0', sizeof(gb));

   GrowBuffer(&gb);

   /* store the width on the stack */
   if (sc->width==defwid)
      /* Don't need to do anything for the width */ ;
   else
      AddNumber2(&gb, sc->width-nomwid, round);

   memset(&trans, '\0', sizeof(trans));
   memset(&hdb, '\0', sizeof(hdb));
   hdb.scs=scs;
   hdb.gi=gi;
   if (gi != NULL)
      gi->bcnt=-1;
   scs[0]=sc;
   hdb.noconflicts=!sc->hconflicts && !sc->vconflicts;
   hdb.cnt=NumberHints(hdb.scs, 1);
   DumpHints(&gb, sc->hstem, sc->hconflicts || sc->vconflicts?18:1,
	     sc->hconflicts || sc->vconflicts?18:1, round);
   DumpHints(&gb, sc->vstem, sc->hconflicts || sc->vconflicts?-1:3,
	     sc->hconflicts || sc->vconflicts?23:3, round);
   CounterHints2(&gb, sc, hdb.cnt);
   RSC2PS2(&gb, sc, sc, &hdb, &trans, subrs, flags, gi->layer);

   if (gi->bcnt==-1) {	/* If it's whitespace */
      gi->bcnt=0;
      StartNextSubroutine(&gb, &hdb);
   }
   BreakSubroutine(&gb, &hdb);
   MoveSubrsToChar(gi);
   ret=NULL;

   free(gb.base);
   if (flags&ps_flag_nohints) {
      sc->hstem=oldh;
      sc->vstem=oldv;
      sc->hconflicts=hc;
      sc->vconflicts=vc;
   } else if (hm != NULL)
      sc->layers[gi->layer].splines->first->hintmask=hm;
   return (ret);
}

static SplinePoint *LineTo(SplinePoint *last,int x,int y) {
   SplinePoint *sp=SplinePointCreate(x, y);

   SplineMake3(last, sp);
   return (sp);
}

static void Type2NotDefSplines(SplineFont *sf,SplineChar *sc,int layer) {
   /* I'd always assumed that Type2 notdefs would look like type1 notdefs */
   /*  but they don't, they look like truetype notdefs. And Ralf Stubner */
   /*  points out that the spec says they should. So make a box here */
   int stem, ymax;
   SplineSet *inner, *ss;
   StemInfo *h, *hints;

   stem=(sf->ascent+sf->descent)/20;
   ymax=2*sf->ascent/3;

   ss=chunkalloc(sizeof(SplineSet));
   ss->first=ss->last=SplinePointCreate(stem, 0);
   ss->last=LineTo(ss->last, stem, ymax);
   ss->last=LineTo(ss->last, sc->width-stem, ymax);
   ss->last=LineTo(ss->last, sc->width-stem, 0);
   SplineMake3(ss->last, ss->first);
   ss->last=ss->first;

   ss->next=inner=chunkalloc(sizeof(SplineSet));
   inner->first=inner->last=SplinePointCreate(2*stem, stem);
   inner->last=LineTo(inner->last, sc->width-2*stem, stem);
   inner->last=LineTo(inner->last, sc->width-2*stem, ymax-stem);
   inner->last=LineTo(inner->last, 2*stem, ymax-stem);
   SplineMake3(inner->last, inner->first);
   inner->last=inner->first;

   sc->layers[layer].splines=ss;

   hints=chunkalloc(sizeof(StemInfo));
   hints->start=stem;
   hints->width=stem;
   hints->next=h=chunkalloc(sizeof(StemInfo));
   h->start=sc->width-2*stem;
   h->width=stem;
   sc->vstem=hints;

   hints=chunkalloc(sizeof(StemInfo));
   hints->start=0;
   hints->width=stem;
   hints->next=h=chunkalloc(sizeof(StemInfo));
   h->start=ymax-stem;
   h->width=stem;
   sc->hstem=hints;
}

/* Mark those glyphs which can live totally in subrs */
static void SplineFont2FullSubrs2(int flags,GlyphInfo *gi) {
   int i;
   SplineChar *sc;

   if (!autohint_before_generate && !(flags&ps_flag_nohints))
      SplineFontAutoHintRefs(gi->sf, gi->layer);

   for (i=0; i<gi->glyphcnt; ++i)
      if ((sc=gi->gb[i].sc) != NULL)
	 sc->lsidebearing=0x7fff;
}

struct pschars *SplineFont2ChrsSubrs2(SplineFont *sf, int nomwid, int defwid,
				      const int *bygid, int cnt, int flags,
				      struct pschars **_subrs, int layer) {
   struct pschars *subrs, *chrs;
   int i, j, k, scnt;
   SplineChar *sc;
   GlyphInfo gi;
   SplineChar dummynotdef;

   if (!autohint_before_generate && !(flags&ps_flag_nohints))
      SplineFontAutoHintRefs(sf, layer);

   memset(&gi, 0, sizeof(gi));
   memset(&gi.hashed, -1, sizeof(gi.hashed));
   gi.instance_count=1;
   gi.sf=sf;
   gi.layer=layer;
   gi.glyphcnt=cnt;
   gi.bygid=bygid;
   gi.gb=calloc(cnt, sizeof(struct glyphbits));
   gi.pmax=3*cnt;
   gi.psubrs=malloc(gi.pmax * sizeof(struct potentialsubrs));
   for (i=0; i<cnt; ++i) {
      int gid=bygid[i];

      if (i==0 && gid==-1) {
	 sc=&dummynotdef;
	 memset(sc, 0, sizeof(dummynotdef));
	 dummynotdef.name=".notdef";
	 dummynotdef.parent=sf;
	 dummynotdef.layer_cnt=sf->layer_cnt;
	 dummynotdef.layers=calloc(sf->layer_cnt, sizeof(Layer));
	 dummynotdef.width=SFOneWidth(sf);
	 if (dummynotdef.width==-1)
	    dummynotdef.width=(sf->ascent+sf->descent)/2;
	 Type2NotDefSplines(sf, &dummynotdef, layer);
      } else if (gid != -1)
	 sc=sf->glyphs[gid];
      else
	 continue;
      gi.gb[i].sc=sc;
      if (autohint_before_generate && sc != NULL &&
	  sc->changedsincelasthinted && !sc->manualhints &&
	  !(flags&ps_flag_nohints))
	 SplineCharAutoHint(sc, layer, NULL);
      sc->lsidebearing=0x7fff;
   }
   MarkTranslationRefs(sf, layer);
   SplineFont2FullSubrs2(flags, &gi);

   for (i=0; i<cnt; ++i) {
      if ((sc=gi.gb[i].sc)==NULL)
	 continue;
      gi.active=&gi.gb[i];
      SplineChar2PS2(sc, NULL, nomwid, defwid, NULL, flags, &gi);
   }

   for (i=scnt=0; i<gi.pcnt; ++i) {
      /* A subroutine call takes somewhere between 2 and 4 bytes itself. */
      /*  and we must add a return statement to the end. We don't want to */
      /*  make things bigger */
      /* if we have more than 65535 subrs a subr call can take 9 bytes */
      if (gi.psubrs[i].full_glyph_index != -1)
	 gi.psubrs[i].idx=scnt++;
      else if (gi.psubrs[i].cnt * gi.psubrs[i].len >
	       (gi.psubrs[i].cnt*4)+gi.psubrs[i].len+1)
	 gi.psubrs[i].idx=scnt++;
      else
	 gi.psubrs[i].idx=-1;
   }
   subrs=calloc(1, sizeof(struct pschars));
   subrs->cnt=scnt;
   subrs->next=scnt;
   subrs->lens=malloc(scnt * sizeof(int));
   subrs->values=malloc(scnt * sizeof(unsigned char *));
   subrs->bias=scnt<1240?107:scnt<33900?1131:32768;
   for (i=0; i<gi.pcnt; ++i) {
      if (gi.psubrs[i].idx != -1) {
	 scnt=gi.psubrs[i].idx;
	 subrs->lens[scnt]=gi.psubrs[i].len+1;
	 subrs->values[scnt]=malloc(subrs->lens[scnt]);
	 memcpy(subrs->values[scnt], gi.psubrs[i].data, gi.psubrs[i].len);
	 subrs->values[scnt][gi.psubrs[i].len]=11;	/* Add a return to end of subr */
      }
   }

   chrs=calloc(1, sizeof(struct pschars));
   chrs->cnt=cnt;
   chrs->next=cnt;
   chrs->lens=malloc(cnt * sizeof(int));
   chrs->values=malloc(cnt * sizeof(unsigned char *));
   chrs->keys=malloc(cnt * sizeof(char *));
   for (i=0; i<cnt; ++i) {
      int len=0;
      uint8_t *vals;
      struct glyphbits *gb=&gi.gb[i];

      if (gb->sc==NULL)
	 continue;
      chrs->keys[i]=fastrdup(gb->sc->name);
      for (k=0; k<2; ++k)
	 if (k != 0 || gb->sc->lsidebearing != 0x7fff) {
	    for (j=0; j<gb->bcnt; ++j) {
	       if (k != 0 || j != 0)
		  len += gb->bits[j].dlen;
	       if (k==1 && gb->sc->lsidebearing != 0x7fff) {
		  int si=gi.psubrs[gb->sc->lsidebearing].idx;

		  len += 1+(si <= 107 && si >= -107?1:si <= 1131
			      && si >= -1131?2:si >= -32768
			      && si<32767?3:8);
		  break;
	       }
	       if (gi.psubrs[gb->bits[j].psub_index].idx==-1)
		  len += gi.psubrs[gb->bits[j].psub_index].len;
	       else {
		  int si =
		     gi.psubrs[gb->bits[j].psub_index].idx-subrs->bias;
		  /* space for the number (subroutine index) */
		  if (si >= -107 && si <= 107)
		     ++len;
		  else if (si >= -1131 && si <= 1131)
		     len += 2;
		  else if (si >= -32768 && si <= 32767)
		     len += 3;
		  else
		     len += 8;
		  /* space for the subroutine operator */
		  ++len;
	       }
	    }
	    if (k==0) {
	       int si=gi.psubrs[gb->sc->lsidebearing].idx;

	       subrs->lens[si]=len+1;
	       vals=subrs->values[si]=malloc(len+2);
	    } else {
	       chrs->lens[i]=len+1;
	       vals=chrs->values[i]=malloc(len+2);	/* space for endchar and a final NUL (which is really meaningless, but makes me feel better) */
	    }

	    len=0;
	    for (j=0; j<gb->bcnt; ++j) {
	       int si;

	       if (k != 0 || j != 0) {
		  memcpy(vals+len, gb->bits[j].data, gb->bits[j].dlen);
		  len += gb->bits[j].dlen;
	       }
	       si=0x80000000;
	       if (k==1 && gb->sc->lsidebearing != 0x7fff)
		  si=gi.psubrs[gb->sc->lsidebearing].idx-subrs->bias;
	       else if (gi.psubrs[gb->bits[j].psub_index].idx==-1) {
		  memcpy(vals+len, gi.psubrs[gb->bits[j].psub_index].data,
			 gi.psubrs[gb->bits[j].psub_index].len);
		  len += gi.psubrs[gb->bits[j].psub_index].len;
	       } else
		  si=gi.psubrs[gb->bits[j].psub_index].idx-subrs->bias;
	       if (si != 0x80000000) {
		  /* space for the number (subroutine index) */
		  if (si >= -107 && si <= 107)
		     vals[len++]=si+139;
		  else if (si>0 && si <= 1131) {
		     si -= 108;
		     vals[len++]=(si >> 8)+247;
		     vals[len++]=si&0xff;
		  } else if (si >= -1131 && si<0) {
		     si=(-si)-108;
		     vals[len++]=(si >> 8)+251;
		     vals[len++]=si&0xff;
		  } else if (si >= -32768 && si <= 32767) {
		     vals[len++]=28;
		     vals[len++]=(si >> 8)&0xff;
		     vals[len++]=si&0xff;
		  } else {
		     /* store as fixed point, then multiply by 64. Takes 8 bytes */
		     si *= (65536/64);
		     vals[len++]='\377';
		     vals[len++]=(si >> 24)&0xff;
		     vals[len++]=(si >> 16)&0xff;
		     vals[len++]=(si >> 8)&0xff;
		     vals[len++]=si&0xff;
		     vals[len++]=64+139;
		     vals[len++]=0xc;
		     vals[len++]=0x18;	/* Multiply */
		  }

		  /* space for the subroutine operator */
		  vals[len++]=10;
	       }
	       if (k==1 && gb->sc->lsidebearing != 0x7fff)
		  break;
	    }
	    if (k==0) {
	       vals[len++]=11;	/* return */
	       vals[len]='\0';
	    } else {
	       vals[len++]=14;	/* endchar */
	       vals[len]='\0';
	    }
	 }
   }

   GIFree(&gi, &dummynotdef);
   *_subrs=subrs;
   return (chrs);
}

struct pschars *CID2ChrsSubrs2(SplineFont *cidmaster, struct fd2data *fds,
			       int flags, struct pschars **_glbls,
			       int layer) {
   struct pschars *chrs, *glbls;
   int i, j, cnt, cid, max, fd;
   int *scnts;
   SplineChar *sc;
   SplineFont *sf=NULL;

   /* In a cid-keyed font, cid 0 is defined to be .notdef so there are no */
   /*  special worries. If it is defined we use it. If it is not defined */
   /*  we add it. */
   GlyphInfo gi;
   SplineChar dummynotdef;

   max=0;
   for (i=0; i<cidmaster->subfontcnt; ++i) {
      if (max<cidmaster->subfonts[i]->glyphcnt)
	 max=cidmaster->subfonts[i]->glyphcnt;
      MarkTranslationRefs(cidmaster->subfonts[i], layer);
   }
   cnt=1;			/* for .notdef */
   for (cid=1; cid<max; ++cid) {
      for (i=0; i<cidmaster->subfontcnt; ++i) {
	 sf=cidmaster->subfonts[i];
	 if (cid<sf->glyphcnt && (sc=sf->glyphs[cid]) != NULL) {
	    sc->ttf_glyph=-1;
	    sc->lsidebearing=0x7fff;
	    if (SCWorthOutputting(sc))
	       ++cnt;
	    break;
	 }
      }
   }

   memset(&gi, 0, sizeof(gi));
   memset(&gi.hashed, -1, sizeof(gi.hashed));
   gi.instance_count=1;
   gi.sf=sf;
   gi.glyphcnt=cnt;
   gi.bygid=NULL;
   gi.gb=calloc(cnt, sizeof(struct glyphbits));
   gi.pmax=3*cnt;
   gi.psubrs=malloc(gi.pmax * sizeof(struct potentialsubrs));
   gi.layer=layer;

   for (cid=cnt=0; cid<max; ++cid) {
      sf=NULL;
      for (i=0; i<cidmaster->subfontcnt; ++i) {
	 sf=cidmaster->subfonts[i];
	 if (cid<sf->glyphcnt && SCWorthOutputting(sf->glyphs[cid]))
	    break;
      }
      if (cid != 0 && i==cidmaster->subfontcnt) {
	 sc=NULL;
      } else if (i==cidmaster->subfontcnt) {
	 /* They didn't define CID 0 */
	 sc=&dummynotdef;
	 /* Place it in the final subfont (which is what sf points to) */
	 memset(sc, 0, sizeof(dummynotdef));
	 dummynotdef.name=".notdef";
	 dummynotdef.parent=sf;
	 dummynotdef.layer_cnt=layer+1;
	 dummynotdef.layers=calloc(layer+1, sizeof(Layer));
	 dummynotdef.width=SFOneWidth(sf);
	 if (dummynotdef.width==-1)
	    dummynotdef.width=(sf->ascent+sf->descent);
	 Type2NotDefSplines(sf, &dummynotdef, layer);
	 gi.gb[cnt].sc=sc;
	 gi.gb[cnt].fd=i=cidmaster->subfontcnt-1;
      } else {
	 gi.gb[cnt].sc=sc=sf->glyphs[cid];
	 gi.gb[cnt].fd=i;
      }
      if (sc != NULL) {
	 sc->lsidebearing=0x7fff;
	 gi.active=&gi.gb[cnt];
	 sc->ttf_glyph=cnt++;
	 SplineChar2PS2(sc, NULL, fds[i].nomwid, fds[i].defwid, NULL, flags,
			&gi);
      }
   }

   scnts=calloc(cidmaster->subfontcnt+1, sizeof(int));
   for (i=0; i<gi.pcnt; ++i) {
      gi.psubrs[i].idx=-1;
      if (gi.psubrs[i].cnt * gi.psubrs[i].len >
	  (gi.psubrs[i].cnt*4)+gi.psubrs[i].len+1)
	 gi.psubrs[i].idx=scnts[gi.psubrs[i].fd+1]++;
   }

   glbls=calloc(1, sizeof(struct pschars));
   glbls->cnt=scnts[0];
   glbls->next=scnts[0];
   glbls->lens=malloc(scnts[0] * sizeof(int));
   glbls->values=malloc(scnts[0] * sizeof(unsigned char *));
   glbls->bias=scnts[0]<1240?107:scnts[0]<33900?1131:32768;
   for (fd=0; fd<cidmaster->subfontcnt; ++fd) {
      fds[fd].subrs=calloc(1, sizeof(struct pschars));
      fds[fd].subrs->cnt=scnts[fd+1];
      fds[fd].subrs->next=scnts[fd+1];
      fds[fd].subrs->lens=malloc(scnts[fd+1] * sizeof(int));
      fds[fd].subrs->values=malloc(scnts[fd+1] * sizeof(unsigned char *));
      fds[fd].subrs->bias=scnts[fd+1]<1240?107 :
	 scnts[fd+1]<33900?1131:32768;
   }
   free(scnts);

   for (i=0; i<gi.pcnt; ++i) {
      if (gi.psubrs[i].idx != -1) {
	 struct pschars *subrs =
	    gi.psubrs[i].fd==-1?glbls:fds[gi.psubrs[i].fd].subrs;
	 int scnt=gi.psubrs[i].idx;

	 subrs->lens[scnt]=gi.psubrs[i].len+1;
	 subrs->values[scnt]=malloc(subrs->lens[scnt]);
	 memcpy(subrs->values[scnt], gi.psubrs[i].data, gi.psubrs[i].len);
	 subrs->values[scnt][gi.psubrs[i].len]=11;	/* Add a return to end of subr */
      }
   }


   chrs=calloc(1, sizeof(struct pschars));
   chrs->cnt=cnt;
   chrs->next=cnt;
   chrs->lens=malloc(cnt * sizeof(int));
   chrs->values=malloc(cnt * sizeof(unsigned char *));
   chrs->keys=malloc(cnt * sizeof(char *));
   for (i=0; i<cnt; ++i) {
      int len=0;
      struct glyphbits *gb=&gi.gb[i];

      chrs->keys[i]=fastrdup(gb->sc->name);
      for (j=0; j<gb->bcnt; ++j) {
	 len += gb->bits[j].dlen;
	 if (gi.psubrs[gb->bits[j].psub_index].idx==-1)
	    len += gi.psubrs[gb->bits[j].psub_index].len;
	 else {
	    struct pschars *subrs =
	       gi.psubrs[gb->bits[j].psub_index].fd ==
	       -1?glbls:fds[gi.psubrs[gb->bits[j].psub_index].fd].subrs;
	    int si=gi.psubrs[gb->bits[j].psub_index].idx-subrs->bias;

	    /* space for the number (subroutine index) */
	    if (si >= -107 && si <= 107)
	       ++len;
	    else if (si >= -1131 && si <= 1131)
	       len += 2;
	    else if (si >= -32768 && si <= 32767)
	       len += 3;
	    else
	       len += 8;
	    /* space for the subroutine operator */
	    ++len;
	 }
      }
      chrs->lens[i]=len+1;
      chrs->values[i]=malloc(len+2);	/* space for endchar and a final NUL (which is really meaningless, but makes me feel better) */

      len=0;
      for (j=0; j<gb->bcnt; ++j) {
	 memcpy(chrs->values[i]+len, gb->bits[j].data, gb->bits[j].dlen);
	 len += gb->bits[j].dlen;
	 if (gi.psubrs[gb->bits[j].psub_index].idx==-1) {
	    memcpy(chrs->values[i]+len,
		   gi.psubrs[gb->bits[j].psub_index].data,
		   gi.psubrs[gb->bits[j].psub_index].len);
	    len += gi.psubrs[gb->bits[j].psub_index].len;
	 } else {
	    struct pschars *subrs =
	       gi.psubrs[gb->bits[j].psub_index].fd ==
	       -1?glbls:fds[gi.psubrs[gb->bits[j].psub_index].fd].subrs;
	    int si=gi.psubrs[gb->bits[j].psub_index].idx-subrs->bias;

	    /* space for the number (subroutine index) */
	    if (si >= -107 && si <= 107)
	       chrs->values[i][len++]=si+139;
	    else if (si>0 && si <= 1131) {
	       si -= 108;
	       chrs->values[i][len++]=(si >> 8)+247;
	       chrs->values[i][len++]=si&0xff;
	    } else if (si >= -1131 && si<0) {
	       si=(-si)-108;
	       chrs->values[i][len++]=(si >> 8)+251;
	       chrs->values[i][len++]=si&0xff;
	    } else if (si >= -32768 && si <= 32767) {
	       chrs->values[i][len++]=28;
	       chrs->values[i][len++]=(si >> 8)&0xff;
	       chrs->values[i][len++]=si&0xff;
	    } else {
	       /* store as fixed point, then multiply by 64. Takes 8 bytes */
	       si *= (65536/64);
	       chrs->values[i][len++]='\377';
	       chrs->values[i][len++]=(si >> 24)&0xff;
	       chrs->values[i][len++]=(si >> 16)&0xff;
	       chrs->values[i][len++]=(si >> 8)&0xff;
	       chrs->values[i][len++]=si&0xff;
	       chrs->values[i][len++]=64+139;
	       chrs->values[i][len++]=0xc;
	       chrs->values[i][len++]=0x18;	/* Multiply */
	    }
	    /* space for the subroutine operator */
	    if (gi.psubrs[gb->bits[j].psub_index].fd==-1) {
	       chrs->values[i][len++]=29;
	    } else
	       chrs->values[i][len++]=10;
	 }
      }
      chrs->values[i][len++]=14;	/* endchar */
      chrs->values[i][len]='\0';
   }
   GIFree(&gi, &dummynotdef);
   *_glbls=glbls;
   return (chrs);
}
