be4311c07e14feb728abc6425ee606ffaa611a58
markd
  Fri Jan 22 06:46:58 2021 -0800
merge with master

diff --git src/lib/pscmGfx.c src/lib/pscmGfx.c
index 06db3d6..4f98893 100644
--- src/lib/pscmGfx.c
+++ src/lib/pscmGfx.c
@@ -1,793 +1,796 @@
 /* pscmGfx - routines for making postScript output seem a
  * lot like 256 color bitmap output. 
  *
  * This file is copyright 2002 Jim Kent, but license is hereby
  * granted for all use - public, private or commercial. */
 
 #include <math.h>
 #ifdef MACHTYPE_sparc
 #include <ieeefp.h>
 int isinf(double x) { return !finite(x) && x==x; }
 #endif
 #include "common.h"
 #include "hash.h"
 #include "memgfx.h"
 #include "gfxPoly.h"
 #include "colHash.h"
 #include "psGfx.h"
 #include "pscmGfx.h"
 #include "gemfont.h"
 #include "vGfx.h"
 #include "vGfxPrivate.h"
 
 static struct pscmGfx *boxPscm;	 /* Used to keep from drawing the same box again
                                   * and again with no other calls between.  This
 				  * ends up cutting down the file size by 5x
 				  * in the whole chromosome case of the browser. */
 
 void pscmSetHint(struct pscmGfx *pscm, char *hint, char *value)
 /* set a hint */
 {
 if (!value) return;
 if (sameString(value,""))
     {
     hashRemove(pscm->hints, hint);
     }
 struct hashEl *el = hashLookup(pscm->hints, hint);
 if (el) 
     {
     freeMem(el->val);
     el->val = cloneString(value);
     }
 else
     {
     hashAdd(pscm->hints, hint, cloneString(value));
     }
 }
 
 char *pscmGetHint(struct pscmGfx *pscm, char *hint)
 /* get a hint */
 {
 return hashOptionalVal(pscm->hints, hint, "");
 }
 
 int pscmGetFontPixelHeight(struct pscmGfx *pscm, MgFont *font)
 /* How high in pixels is font? */
 {
 return font_cel_height(font);
 }
 
 int pscmGetFontStringWidth(struct pscmGfx *pscm, MgFont *font, char *string)
 /* How wide is a string? */
 {
 return fnstring_width(font, (unsigned char *)string, strlen(string));
 }
 
 void pscmSetClip(struct pscmGfx *pscm, int x, int y, int width, int height)
 /* Set clipping rectangle. */
 {
 double x2 = x + width;
 double y2 = y + height;
 pscm->clipMinX = x;
 pscm->clipMinY = y;
 pscm->clipMaxX = x2;     /* one beyond actual last pixel */
 pscm->clipMaxY = y2;
 /* adjust to pixel-centered coordinates */
 x2 -= 1;
 y2 -= 1;
 double x1 = x;
 double y1 = y;
 /* pad a half-pixel all the way around the box */
 x1 -= 0.5;
 y1 -= 0.5;
 x2 += 0.5;
 y2 += 0.5;
 psClipRect(pscm->ps, x1, y1, x2-x1, y2-y1);
 }
 
 void pscmUnclip(struct pscmGfx *pscm)
 /* Set clipping rect to cover full thing. */
 {
 pscmSetClip(pscm, 0, 0, pscm->ps->userWidth, pscm->ps->userHeight);
 }
 
 int pscmFindColorIx(struct pscmGfx *pscm, int r, int g, int b)
 /* Returns closest color in color map to rgb values.  If it doesn't
  * already exist in color map and there's room, it will create
  * exact color in map. */
 {
 return MAKECOLOR_32(r,g,b);
 }
 
 struct rgbColor pscmColorIxToRgb(struct pscmGfx *pscm, int colorIx)
 /* Return rgb value at color index. */
 {
 static struct rgbColor rgb;
 rgb.r = (colorIx >> 0) & 0xff;
 rgb.g = (colorIx >> 8) & 0xff;
 rgb.b = (colorIx >> 16) & 0xff;
 
 return rgb;
 }
 
 void pscmSetWriteMode(struct pscmGfx *pscm, unsigned int writeMode)
 /* Set write mode */
 {
 pscm->writeMode = writeMode;
 }
 
 struct pscmGfx *pscmOpen(int width, int height, char *file)
 /* Return new pscmGfx. */
 {
 struct pscmGfx *pscm;
 
 AllocVar(pscm);
 pscm->ps = psOpen(file, width, height, 72.0 * 7.5, 0, 0);
 psTranslate(pscm->ps,0.5,0.5);  /* translate all coordinates to pixel centers */
 pscm->clipMinX = pscm->clipMinY = 0;
 pscm->clipMaxX = width;     
 pscm->clipMaxY = height;
 pscm->hints = hashNew(6);
 return pscm;
 }
 
 void pscmClose(struct pscmGfx **pPscm)
 /* Finish writing out and free structure. */
 {
 struct pscmGfx *pscm = *pPscm;
 if (pscm != NULL)
     {
     psClose(&pscm->ps);
     colHashFree(&pscm->colorHash);
     freez(pPscm);
     }
 }
 
 void pscmSetColor(struct pscmGfx *pscm, Color color)
 /* Set current color to Color. */
 {
 struct rgbColor *col;
 
 struct rgbColor myCol;
 col = &myCol;
 
 col->r = (color >> 0) & 0xff;
 col->g = (color >> 8) & 0xff;
 col->b = (color >> 16) & 0xff;
 
 if (color != pscm->curColor)
     {
     psSetColor(pscm->ps, col->r, col->g, col->b);
     pscm->curColor = color;
     }
 }
 
 void pscmBoxToPs(struct pscmGfx *pscm, int x, int y, 
 	int width, int height)
 /* adjust coordinates for PS */
 {
 /* Do some clipping here to make the postScript
  * easier to edit in illustrator. */
 double x2 = x + width;
 double y2 = y + height;
 
 if (x < pscm->clipMinX) x = pscm->clipMinX;
 if (y < pscm->clipMinY) y = pscm->clipMinY;
 if (x2 > pscm->clipMaxX) x2 = pscm->clipMaxX;
 if (y2 > pscm->clipMaxY) y2 = pscm->clipMaxY;
 
 /* adjust to pixel-centered coordinates */
 x2 -= 1;
 y2 -= 1;
 double x1 = x;
 double y1 = y;
 /* pad a half-pixel all the way around the box */
 x1 -= 0.5;
 y1 -= 0.5;
 x2 += 0.5;
 y2 += 0.5;
 psDrawBox(pscm->ps, x1, y1, x2-x1, y2-y1);
 }
 
 void pscmBox(struct pscmGfx *pscm, int x, int y, 
 	int width, int height, int color)
 /* Draw a box. */
 {
 /* When viewing whole chromosomes the browser tends
  * to draw the same little vertical tick over and
  * over again.  This tries to remove the worst of
  * the redundancy anyway. */
 
 static int lx, ly, lw, lh, lc=-1;
 if (x != lx || y != ly || width != lw || height != lh || color != lc || 
 	pscm != boxPscm)
     {
     pscmSetColor(pscm, color);
     pscmBoxToPs(pscm, x, y, width, height);
     lx = x;
     ly = y;
     lw = width;
     lh = height;
     lc = color;
     boxPscm = pscm;
     }
 }
 
 void pscmDot(struct pscmGfx *pscm, int x, int y, int color)
 /* Set a dot. */
 {
 pscmBox(pscm, x, y, 1, 1, color);
 }
 
 static void pscmVerticalSmear(struct pscmGfx *pscm,
 	int xOff, int yOff, int width, int height, 
 	Color *dots, boolean zeroClear)
 /* Put a series of one 'pixel' width vertical lines. */
 {
 int x, i;
 struct psGfx *ps = pscm->ps;
 Color c;
 for (i=0; i<width; ++i)
     {
     x = xOff + i;
     c = dots[i];
     if (c != MG_WHITE || !zeroClear)
 	{
 	pscmSetColor(pscm, c);
 	psDrawBox(ps, x, yOff, 1, height);
 	}
     }
 }
 
 static void pscmSetFont(struct pscmGfx *pscm, MgFont *font)
 /* Set font. */
 {
 /* For now we basically still get the sizing info from the old
  * gem fonts.   I'm not sure how to get sizing info out of
  * PostScript.  We'll try and arrange it so that the PostScript
  * fonts match the gem fonts more or less. */
 void *v = font;
-if ((pscm->fontMethod == 0) && (v != pscm->curFont))
+if (v != pscm->curFont)
     {
+    if (pscm->fontMethod == 0) 
         psTimesFont(pscm->ps, font->psHeight);
+    else
+        psSetFont(pscm->ps, pscm->fontName, font->psHeight);
+
     pscm->curFont = v;
     }
 }
 
 void pscmText(struct pscmGfx *pscm, int x, int y, int color, 
 	MgFont *font, char *text)
 /* Draw a line of text with upper left corner x,y. */
 {
 pscmSetColor(pscm, color);
 pscmSetFont(pscm, font);
 psTextAt(pscm->ps, x, y, text);
 boxPscm = NULL;
 }
 
 void pscmTextRight(struct pscmGfx *pscm, int x, int y, int width, int height,
 	int color, MgFont *font, char *text)
 /* Draw a line of text right justified in box defined by x/y/width/height */
 {
 pscmSetColor(pscm, color);
 pscmSetFont(pscm, font);
 psTextRight(pscm->ps, x, y, width, height, text);
 boxPscm = NULL;
 }
 
 void pscmTextCentered(struct pscmGfx *pscm, int x, int y, 
 	int width, int height, int color, MgFont *font, char *text)
 /* Draw a line of text centered in box defined by x/y/width/height */
 {
 pscmSetColor(pscm, color);
 pscmSetFont(pscm, font);
 psTextCentered(pscm->ps, x, y, width, height, text);
 boxPscm = NULL;
 }
 
 void pscmFillUnder(struct pscmGfx *pscm, int x1, int y1, int x2, int y2, 
 	int bottom, Color color)
 /* Draw a 4 sided filled figure that has line x1/y1 to x2/y2 at
  * it's top, a horizontal line at bottom at it's bottom,  and
  * vertical lines from the bottom to y1 on the left and bottom to
  * y2 on the right. */
 {
 pscmSetColor(pscm, color);
 psFillUnder(pscm->ps, x1, y1, x2, y2, bottom);
 boxPscm = NULL;
 }
 
 void psPolyFindExtremes(struct gfxPoly *poly, 
   int *pMinX, int *pMaxX,  
   int *pMinY, int *pMaxY)
 /* find min and max of x and y */
 {
 struct gfxPoint *p = poly->ptList;
 int minX, maxX, minY, maxY;
 minX = maxX =  p->x;
 minY = maxY =  p->y;
 for (;;)
     {
     p = p->next;
     if (p == poly->ptList)
 	break;
     if (minX > p->x) minX = p->x;
     if (minY > p->y) minY = p->y;
     if (maxX < p->x) maxX = p->x;
     if (maxY < p->y) maxY = p->y;
     }
 *pMinX = minX;
 *pMaxX = maxX;
 *pMinY = minY;
 *pMaxY = maxY;
 }
 
 double gfxSlope(struct gfxPoint *q, struct gfxPoint *p)
 /* determine slope from two gfxPoints */
 {
 double dx = p->x - q->x;
 double dy = p->y - q->y;
 return dy/dx;
 }
 
 boolean colinearPoly(struct gfxPoly *poly)
 /* determine if points are co-linear */
 {
 if (poly->ptCount < 2) return TRUE;
 struct gfxPoint *q = poly->ptList, *p=q->next;
 double m0 = gfxSlope(q,p);
 for (;;)
     {
     p = p->next;
     if (p == poly->ptList)
 	break;
     double m1 = gfxSlope(q,p);
     if (!(isinf(m0) && isinf(m1)) && (m1 != m0))
 	return FALSE;
     }
 return TRUE;
 }
 
 double fatPixel(double c, double center, double fat)
 /* fatten coordinate by scaling */
 {
 return center+((c-center)*fat);
 }
 
 void pscmPolyFatten(struct psPoly *psPoly, 
   int minX, int maxX, int minY, int maxY)
 /* Fatten polygon by finding the center and then
  * scaling by 0.5 pixel from the center in all directions.
  * Caller assures dx and dy will NOT be zero. */
 {
 int dx = maxX - minX;
 int dy = maxY - minY;
 double centerX = (maxX + minX) / 2.0;
 double centerY = (maxY + minY) / 2.0;
 double fatX = (dx + 1.0)/dx;
 double fatY = (dy + 1.0)/dy;
 struct psPoint *p = psPoly->ptList;
 for (;;)
     {
     p->x = fatPixel(p->x, centerX, fatX);
     p->y = fatPixel(p->y, centerY, fatY);
     p = p->next;
     if (p == psPoly->ptList)
 	break;
     }
 }
 
 void findLineParams(double x1, double y1, double x2, double y2, double *m, double *b)
 /* Return parameters slope m and y-intercept b of equation for line from x1,y1 to x2,y2, 
  * vertical lines return infinite slope with b = x value instead */
 {
 double dx = x2 - x1;
 double dy = y2 - y1;
 *m = dy/dx;
 if (dx == 0)
     *b = x1;
 else
     *b = y1 - (*m)*x1;
 }
 
 
 double bDeltaForParallelLine(double d, double m)
 /* find delta-b value for parallel line at distance d for line slope m */
 {
 return d * sqrt(1 + m*m); /* do not call with m == infinity */
 }
 
 void adjustBForParallelLine(boolean cw, double m, 
 double x1, double y1, 
 double x2, double y2, 
 double *b)
 /* adjust the b value for parallel line at distance d for line slope m 
  *  cw if clockwise */
 {
 if (isinf(m))  /* handle vertical lines */
     {
     if ((cw && (y2 < y1)) || (!cw && (y2 > y1)))
 	*b += 1;   /* b holds x-value rather than y-intercept */
     else
 	*b -= 1;
     }
 else
     {
     /* Y axis is increasing downwards */
     double bDelta = bDeltaForParallelLine(1.0, m);
     if ((cw && (x2 > x1)) || (!cw && (x2 < x1)))
        *b += bDelta; 
     else
        *b -= bDelta;
     }
 }
 
 void findLinesIntersection(boolean cw, double m0, double b0, double m1, double b1, 
 double px, double py, boolean posDeltaX, boolean posDeltaY,
 double *ix, double *iy)
 /* find intersection between two lines */
 {
 
 /* colinear vert */
 if ((isinf(m0) && isinf(m1)) && (b0 == b1)) 
     {
     if (cw ^ posDeltaY)
     	*ix = px+1;
     else
     	*ix = px-1;
     *iy = py; 
     }
 /* colinear horiz */
 else if (((m0==0)&&(m1==0)) && (b0 == b1)) 
     {
     if (cw ^ posDeltaX)
     	*iy = py+1;
     else
     	*iy = py-1;
     *ix = px; 
     }
 /* colinear */
 else if ((m0 == m1) && (b0 == b1))  
     {
     /* inner point shifted 1 pixel away from the point,
      *   moving perpendicular to m0 towards the center */
 
     double dx, dy;
     double m = -1/m0; 
     dx = sqrt(1/(1+m*m));
     dy = m * dx;
 
     if (!(cw ^ posDeltaX))
 	{
 	*ix = px + dx;
 	*iy = py + dy;
 	}
     else
 	{
 	*ix = px - dx;
 	*iy = py - dy;
 	}
 
     }
 /* non-colinear */
 else
     {
     if (isinf(m0) && isinf(m1))
 	{  /* should be handled earlier by colinear vert lines above */
 	errAbort("pscmGfx: m0 and m1 both inf, shouldn't get here");
 	}
     else if (!isinf(m0) && isinf(m1))
 	{
     	*ix = b1;
 	*iy = m0*(*ix)+b0;
 	}
     else if (isinf(m0) && !isinf(m1))
 	{
     	*ix = b0;
 	*iy = m1*(*ix)+b1;
 	}
     else if (!isinf(m0) && !isinf(m1))
 	{
     	*ix = -(b1-b0)/(m1-m0);
 	*iy = m0*(*ix)+b0;
 	}
     }
 }
 
 boolean pscmIsClockwise(struct psPoly *psPoly)
 /* determine if polygon points are in clockwise order or not
  * using cross-product sum*/
 {
 struct psPoint *p = psPoly->ptList,*q;
 double x0, y0; 
 double x1, y1;
 double x2, y2;
 double crossProd = 0;
 x1 = p->x;
 y1 = p->y;
 p = p->next;
 x2 = p->x;
 y2 = p->y;
 p = p->next;
 q = p;
 for (;;)
     {
     x0 = x1;
     y0 = y1;
     x1 = x2;
     y1 = y2;
     x2 = p->x;
     y2 = p->y;
     crossProd += ((x1-x0)*(y2-y1) - (y1-y0)*(x2-x1));
     p = p->next;
     if (p == q) 
 	break;
     }
 return (crossProd > 0);
 }
 
 void pscmPolyTrapStrokeOutline(struct pscmGfx *pscm, struct psPoly *psPoly)
 /* Stroke a fattened polygon using trapezoids. 
  * Make each stroke-segment of the poly be made of a 4-sided trapezoidal figure
  * whose inner edge is parallel 1 pixel away and the points are found
  * by finding the intersections of these parallel lines. */
 {
 
 struct psPoint *p = psPoly->ptList,*q;
 double px0, py0; /* outer points */
 double px1, py1;
 double m0,b0;
 double m1,b1;
 double ix0,iy0;  /* inner points */
 double ix1,iy1;
 
 boolean cw = pscmIsClockwise(psPoly);
 
 px1 = p->x;
 py1 = p->y;
 p = p->next;
 findLineParams(px1, py1, p->x, p->y, &m1, &b1);
 adjustBForParallelLine(cw, m1, px1, py1, p->x, p->y, &b1);
 px0 = px1;
 py0 = py1;
 px1 = p->x;
 py1 = p->y;
 p = p->next;
 m0 = m1;
 b0 = b1;
 findLineParams(px1, py1, p->x, p->y, &m1, &b1);
 adjustBForParallelLine(cw, m1, px1, py1, p->x, p->y, &b1);
 
 findLinesIntersection(cw,m0,b0,m1,b1,px1,py1,
     (px1<px0) ^ (m0 < 0),
     (py1>py0),
     &ix1,&iy1);
 
 px0 = px1;
 py0 = py1;
 px1 = p->x;
 py1 = p->y;
 p = p->next;
 q = p;
 for (;;)
     {
 
     m0 = m1;
     b0 = b1;
     ix0 = ix1;
     iy0 = iy1;
     findLineParams(px1, py1, p->x, p->y, &m1, &b1);
     adjustBForParallelLine(cw, m1, px1, py1, p->x, p->y, &b1);
 
     findLinesIntersection(cw,m0,b0,m1,b1,px1,py1,
 	(px1<px0) ^ (m0 < 0),
 	(py1>py0),
 	&ix1,&iy1);
 
     struct psPoly *inner = psPolyNew();
     psPolyAddPoint(inner,px0, py0);
     psPolyAddPoint(inner,px1, py1);
     psPolyAddPoint(inner,ix1, iy1);
     psPolyAddPoint(inner,ix0, iy0);
     psDrawPoly(pscm->ps, inner, TRUE);
     psPolyFree(&inner);
 
     px0 = px1;
     py0 = py1;
     px1 = p->x;
     py1 = p->y;
     p = p->next;
     if (p == q) 
 	break;
     }
 }
 
 void pscmDrawPoly(struct pscmGfx *pscm, struct gfxPoly *poly, Color color, 
 	boolean filled)
 /* Draw a polygon, possibly filled, in color. */
 {
 struct gfxPoint *p = poly->ptList;
 struct psPoly *psPoly = psPolyNew();
 int minX, maxX, minY, maxY;
 if (poly->ptCount < 1)  /* nothing to do */
     {
     return;
     }
 psPolyFindExtremes(poly, &minX, &maxX, &minY, &maxY);
 /*  check for co-linear polygon, render as line instead */
 if (colinearPoly(poly)) 
     {
     pscmLine(pscm, minX, minY, maxX, maxY, color);
     return;
     }
 pscmSetColor(pscm, color);
 /* convert pixel coords to real values */
 for (;;)
     {
     psPolyAddPoint(psPoly,p->x, p->y);
     p = p->next;
     if (p == poly->ptList)
 	break;
     }
 boolean fat = sameString(pscmGetHint(pscm,"fat"),"on");
 if (fat)
     pscmPolyFatten(psPoly, minX, maxX, minY, maxY);
 if (fat && !filled)
     pscmPolyTrapStrokeOutline(pscm,psPoly);
 else
     psDrawPoly(pscm->ps, psPoly, filled);
 psPolyFree(&psPoly);
 }
 
 void pscmFatLine(struct pscmGfx *pscm, double x1, double y1, double x2, double y2)
 /* Draw a line from x1/y1 to x2/y2 by making a filled polygon.
  *  This also avoids some problems with stroke-width variation
  *  from different postscript implementations. */
 {
 struct psPoly *psPoly = psPolyNew();
 
 double cX = (x1+x2)/2.0;
 double cY = (y1+y2)/2.0;
 double fX;
 double fY;
 
 /* fatten by lengthing line by 0.5 at each end */
 fX = fY = 1.0+0.5*sqrt(0.5);  
 
 /* expand the length of the line by a half-pixel on each end */
 x1 = fatPixel(x1,cX,fX);
 x2 = fatPixel(x2,cX,fX);
 y1 = fatPixel(y1,cY,fY);
 y2 = fatPixel(y2,cY,fY);
 
 /* calculate 4 corners {h,i,j,k} of the rectangle covered */
 
 double m = (y2 - y1)/(x2 - x1);
 m = -1/m;  /* rotate slope 90 degrees */
 
 double ddX = sqrt( (0.5*0.5) / (m*m+1) );
 double ddY = m * ddX;
 
 double hX = x1-ddX, hY = y1-ddY;
 double iX = x1+ddX, iY = y1+ddY;
 double jX = x2+ddX, jY = y2+ddY;
 double kX = x2-ddX, kY = y2-ddY;
 
 psPolyAddPoint(psPoly,hX,hY);
 psPolyAddPoint(psPoly,iX,iY);
 psPolyAddPoint(psPoly,jX,jY);
 psPolyAddPoint(psPoly,kX,kY);
 psDrawPoly(pscm->ps, psPoly, TRUE);
 psPolyFree(&psPoly);
 
 }
 
 void pscmLine(struct pscmGfx *pscm, 
 	int x1, int y1, int x2, int y2, int color)
 /* Draw a line from one point to another. */
 {
 pscmSetColor(pscm, color);
 boolean fat = sameString(pscmGetHint(pscm,"fat"),"on");
 if (fat)
     pscmFatLine(pscm, x1, y1, x2, y2);
 else
     psDrawLine(pscm->ps, x1, y1, x2, y2);
 boxPscm = NULL;
 }
 
 void pscmCircle(struct pscmGfx *pscm, int xCen, int yCen, int rad,
         Color color, boolean filled)
 {
 pscmSetColor(pscm, color);
 psCircle(pscm->ps, (double)xCen, (double)yCen, (double)rad, filled);
 }
 
 void pscmEllipse(struct pscmGfx *pscm, int x1, int y1, int x2, int y2, Color color, 
                         int mode, boolean isDashed)
 /* Draw an ellipse specified as a rectangle. Args are left-most and top-most points.
  * Optionally draw half-ellipse (top or bottom) */
 {
 pscmSetColor(pscm, color);
 if (isDashed)
     psSetDash(pscm->ps, TRUE);
 else
     psSetDash(pscm->ps, FALSE);
 int startAngle = 0;
 int endAngle = 360;
 if (mode == ELLIPSE_TOP)
     endAngle = 180;
 else if (mode == ELLIPSE_BOTTOM)
     startAngle = 180;
 int yrad = abs(y1 - y2)/2;
 int xrad = abs(x1 - x2)/2;
 x2 = x2 - xrad;
 y1 = y1 - yrad;
 psDrawEllipse(pscm->ps, (double)x2, (double)y1, (double)xrad, (double)yrad,
                 startAngle, endAngle);
 psSetDash(pscm->ps, FALSE);
 }
 
 static double bezierQuadraticToCubic(int a, int b)
 /* Derive cubic control points from quadratic control point. */
 {
 return (double)a + (2 * (b - a))/3.0;
 }
 
 void pscmCurve(struct pscmGfx *pscm, int x1, int y1, int x2, int y2, int x3, int y3, Color color,
                         boolean isDashed)
 /* Draw Bezier curve specified by 3 points (quadratic Bezier).
  * The points are: first (p1) and last (p3), and 1 control point (p2).
  */ 
 {
 pscmSetColor(pscm, color);
 if (isDashed)
     psSetDash(pscm->ps, TRUE);
 else
     psSetDash(pscm->ps, FALSE);
 // PostScript bezier is cubic -- derive the two control points from the single quadratic control point
 double c1x = bezierQuadraticToCubic(x1, x2);
 double c1y = bezierQuadraticToCubic(y1, y2);
 double c2x = bezierQuadraticToCubic(x3, x2);
 double c2y = bezierQuadraticToCubic(y3, y2);
 psDrawCurve(pscm->ps, (double)x1, (double)y1, c1x, c1y, c2x, c2y, (double)x3, (double)y3);
 psSetDash(pscm->ps, FALSE);
 }
 
 void pscmSetFontMethod(struct pscmGfx *pscm, unsigned int method, char *fontName, char *fontFile)
 /* Which font drawing method shoud we use. */
 {
 pscm->fontMethod = method;
 pscm->fontName = cloneString(fontName);
-psSetFont(pscm->ps, fontName);
 }
 
 struct vGfx *vgOpenPostScript(int width, int height, char *fileName)
 /* Open up something that will someday be a PostScript file. */
 {
 struct vGfx *vg = vgHalfInit(width, height);
 vg->data = pscmOpen(width, height, fileName);
 vg->close = (vg_close)pscmClose;
 vg->dot = (vg_dot)pscmDot;
 vg->box = (vg_box)pscmBox;
 vg->line = (vg_line)pscmLine;
 vg->text = (vg_text)pscmText;
 vg->textRight = (vg_textRight)pscmTextRight;
 vg->textCentered = (vg_textCentered)pscmTextCentered;
 vg->findColorIx = (vg_findColorIx)pscmFindColorIx;
 vg->colorIxToRgb = (vg_colorIxToRgb)pscmColorIxToRgb;
 vg->setClip = (vg_setClip)pscmSetClip;
 vg->unclip = (vg_unclip)pscmUnclip;
 vg->verticalSmear = (vg_verticalSmear)pscmVerticalSmear;
 vg->fillUnder = (vg_fillUnder)pscmFillUnder;
 vg->drawPoly = (vg_drawPoly)pscmDrawPoly;
 vg->ellipse = (vg_ellipse)pscmEllipse;
 vg->circle = (vg_circle)pscmCircle;
 vg->curve = (vg_curve)pscmCurve;
 vg->setHint = (vg_setHint)pscmSetHint;
 vg->getHint = (vg_getHint)pscmGetHint;
 vg->getFontPixelHeight = (vg_getFontPixelHeight)pscmGetFontPixelHeight;
 vg->getFontStringWidth = (vg_getFontStringWidth)pscmGetFontStringWidth;
 vg->setWriteMode = (vg_setWriteMode)pscmSetWriteMode;
 vg->setFontMethod = (vg_setFontMethod)pscmSetFontMethod;
 return vg;
 }