DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T d

⟦8da67d352⟧ TextFile

    Length: 20148 (0x4eb4)
    Types: TextFile
    Names: »dvistuff.c«

Derivation

└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
    └─⟦this⟧ »./DVIware/laser-setters/umd-dvi/previewers/dvistuff.c« 

TextFile

/*
 *	This program is Copyright (C) 1987 by the Board of Trustees of the
 *	University of Illinois, and by the author Dirk Grunwald.
 *
 *	This program may be freely copied, as long as this copyright
 *	message remaines affixed. It may not be sold, altough it may
 *	be distributed with other software which is sold. If the
 *	software is distributed, the source code must be made available.
 *
 *	No warrenty, expressed or implied, is given with this software.
 *	It is presented in the hope that it will prove useful.
 */
#include <stdio.h>
#include <ctype.h>

#include "dvistuff.h"	/* includes types & fonts */

#include "conv.h"
#include "dvi.h"
#include "dviclass.h"
#include "dvicodes.h"
#include "postamble.h"
#include "search.h"
#include "fio.h"

int	dviHH = -1;		/* current horizontal position, in DEVs */
int	dviVV = -1;		/* current vertical position, in DEVs */
int	dviHHMargin = -1;	/* horizontal margin (in DEVs) */
int	dviVVMargin = -1;	/* vertical margin (in DEVs) */
int	dviTallestPage = -1;
int	dviWidestPage = -1 ;
int	dviCurrentPage = -1;
int	dviTotalPages = -1;
int	dviDPI = -1;
int	dviMaxDrift = -1;
int	dviUserMag = -1;	/* user-specified magnification */
int	dviBlackness = -1;
FILE	*dviFile;				/* users file */
char	*dviPrintEngine = "canon";

char	*ProgName;

/*
 * Similar to dvi_stack, but includes `dviHH and `dviVV, which are usually
 * but not always the same as fromSP(h) and fromSP(v):
 */
struct localstack {
	int stack_hh;
	int stack_vv;
	struct dvi_stack stack_dvi;
};

static struct localstack *dvi_stack;	/* base of stack */
static struct localstack *dvi_stackp;	/* current place in stack */

/*
 * DVI preamble and postamble information.
 */

static long Magnification;
static long	Numerator;		/* numerator from DVI file */
static long	Denominator;		/* denominator from DVI file */

/*
 *	Font related things.
 *	We keep track of the current font, use the fontfiner
 *	and record errors in the dvi postable in FontErros. 
 *	the NoFont is a used when we cant find a font,
 *	to avoid errors.
 */

struct fontinfo *dviCurrentFont;

static int NextFamilyNumber = 0;
static int MaxFontFamily = MAX_FONTFAMILY;

static struct search *FontFinder;
int FontErrors;
static struct fontinfo NoFont;

/*
 *	We keep a list of pointers to the beginning of pages.
 *	Each page is headed by a DVI_BOP + 44 bytes of information.
 */

static long *pageOffset;

/*
 * Correct devpos (the actual device position) to be within dviMaxDrift pixels
 * of dvipos (the virtual DVI position).
 */
#define FIXDRIFT(devpos, dvipos) \
	if ((devpos) < (dvipos)) \
		if ((dvipos) - (devpos) <= dviMaxDrift) \
			/* void */; \
		else \
			(devpos) = (dvipos) - dviMaxDrift; \
	else \
		if ((devpos) - (dvipos) <= dviMaxDrift) \
			/* void */; \
		else \
			(devpos) = (dvipos) + dviMaxDrift

#define	ABS(X)	( (X) < 0 ? -(X) : (X) )

/*
 * Store the relevant information from the DVI postamble, and set up
 * various internal things.
 */
static void
PostAmbleHeader(p)
    register struct PostAmbleInfo *p;
{
    int i;
    int pageSize;
    int stackSize;
    long prevPagePointer;
    long wuzAt;
    
    Numerator = p->pai_Numerator;
    Denominator = p->pai_Denominator;
    Magnification = p->pai_DVIMag;
    
/*
 *	Set the conversion factor.  This must be done before using
 *	any fonts or the fromSP routine.
 */
    
    SetConversion(dviDPI, dviUserMag, Numerator, Denominator, Magnification);
    
    dviTotalPages = p -> pai_NumberOfPages;
    dviWidestPage = fromSP(p -> pai_WidestPageWidth);
    dviTallestPage = fromSP(p -> pai_TallestPageHeight);

/*
 *	Set up the DVI stack
 */
    stackSize = p -> pai_DVIStackSize * sizeof(*dvi_stack);
    dvi_stack = (struct localstack *) malloc((unsigned) stackSize);  

/*
 *	Set of the table of pointers to pages
 */
    
    pageSize = dviTotalPages * sizeof(long);
    pageOffset = (long *) malloc(pageSize);
    
    if (pageOffset == NULL) {
	fprintf(stderr,"xdvi: Can not allocate page directory (%d pages)",
		dviTotalPages);
	exit(1);
    }
    
/*
 * Follow back pointers through pages in the DVI file,
 * storing the offsets in the pageOffset table.
 */

    prevPagePointer = p->pai_PrevPagePointer;
    wuzAt = (long) ftell(dviFile);
    
    if( fseek(dviFile, prevPagePointer, 0) < 0) {
	perror("fseek");
	fprintf(stderr,"[postamble] improper seek looking up pages\n");
	fprintf(stderr,"prevPagePointer = %lx\n",
		prevPagePointer);
    }

    for (i = dviTotalPages - 1; i > 0 ; i--) {
	
	pageOffset[i] = prevPagePointer;
	
	if (fseek(dviFile, (long) prevPagePointer, 0) < 0) {
	    perror("fseek");
	    fprintf(stderr,"[postamble] improper seek looking up pages\n");
	    fprintf(stderr,"prevPagePointer = %lx\n",
		    prevPagePointer);
	    exit(1);
	}
/*
 *	Skip past the other counters at the beginning of the page
 */
	if (fseek(dviFile, (long) (1 + 10 * 4), 1) < 0) {
	    perror("fseek");
	    fprintf(stderr,"[postamble] attemping to align to prevPointer\n");
	    exit(1);
	}
	
	fGetLong(dviFile, prevPagePointer);
    }
    
    pageOffset[0] = prevPagePointer;
    fseek(dviFile, wuzAt, 0);
}

static void
PostAmbleFontDef(p)
register struct PostAmbleFont *p;
{
    register struct fontinfo *fi;
    register struct font *f;
    
    char *fname;
    int def = S_CREATE | S_EXCL;
    
    fi = (struct fontinfo *) SSearch(FontFinder, p->paf_DVIFontIndex,
				     &def);
    if (fi == NULL) {
	if (def & S_COLL)
	    GripeFontAlreadyDefined(p->paf_DVIFontIndex);
	else {
	    fprintf(stderr, "Can not stash font %ld (out of memory?)\n",
		    p -> paf_DVIFontIndex);
	    exit(1);
	}
    }

    if (NextFamilyNumber == MaxFontFamily) {
	fprintf(stderr,"Out of font family!\n");
	exit(1);
    }

    fi->family = NextFamilyNumber;
    NextFamilyNumber++;

    f = GetFont(p->paf_name, p->paf_DVIMag, p->paf_DVIDesignSize,
		dviPrintEngine, &fname);

/*
 *	Give the application a chance to bang on this if they want to.
 */

    f = applicationNewFont(f, fi -> family);

    if ((fi->f = f) == NULL) {
	GripeCannotGetFont(p->paf_name, p->paf_DVIMag,
			   p->paf_DVIDesignSize, dviPrintEngine, fname);
	FontErrors++;
	return;
    }

    /* match checksums, if not zero */
    if (p->paf_DVIChecksum && f->f_checksum &&
	p->paf_DVIChecksum != f->f_checksum)
	GripeDifferentChecksums(fname, p->paf_DVIChecksum,
				f->f_checksum);
    
    fi->pspace = p->paf_DVIMag / 6;	/* a three-unit "thin space" */
    fi->nspace = -4 * fi->pspace;
    fi->vspace = 5 * fi->pspace;
}

static void
ReadPostAmble()
{

    if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0) {
	fprintf(stderr, "can not create FontFinder (out of memory?)");
	exit(1);
    }

    ScanPostAmble(dviFile, PostAmbleHeader, PostAmbleFontDef);

    if (FontErrors)
	GripeMissingFontsPreventOutput(FontErrors);
}

/*
 *	Read the preamble and do a few sanity checks
 */

static void
ReadPreAmble()
{
	register int n;

	rewind(dviFile);
	if (GetByte(dviFile) != Sign8(DVI_PRE))
		GripeMissingOp("PRE");

	if (GetByte(dviFile) != Sign8(DVI_VERSION))
		GripeMismatchedValue("version numbers");

	if (GetLong(dviFile) != Numerator)
		GripeMismatchedValue("numerator");

	if (GetLong(dviFile) != Denominator)
		GripeMismatchedValue("denominator");

	if (GetLong(dviFile) != Magnification)
		GripeMismatchedValue("\\magfactor");

	n = UnSign8(GetByte(dviFile));
	while (--n >= 0)
		(void) GetByte(dviFile);
}

void
dviInit()
{
    extern char *ProgName;

    if (dviUserMag == -1) {
	dviUserMag = 1000;
    }

    if (dviMaxDrift == -1) {
	dviMaxDrift = 3;
    }

    if (dviDPI == -1) {
	dviDPI = DEFAULT_DPI;
    }

    if (dviBlackness == -1) {
	dviBlackness = DEFAULT_BLACKNESS;
    }

    ReadPostAmble();
    ReadPreAmble();

    /* Margins -- needs work! */

    if (dviHHMargin == -1) {
	dviHHMargin = DEFAULT_HHMARGIN;
    }

    if (dviVVMargin == -1) {
	dviVVMargin = DEFAULT_VVMARGIN;
    }

    dviCurrentFont = &NoFont; /* fake font, all zeros */

}

static void
SelectFont(n)
i32 n;
{
    int x = S_LOOKUP;

    if ((dviCurrentFont = (struct fontinfo *)SSearch(FontFinder, n, &x)) == 0)
	GripeNoSuchFont(n);
}

/* Read the postamble. */

/*
 * Skip a font definition (since we are using those from the postamble)
 */

/*ARGSUSED*/
void
SkipFontDef(font)
i32 font;
{
    register int i;

    (void) GetLong(dviFile);
    (void) GetLong(dviFile);
    (void) GetLong(dviFile);
    i = UnSign8(GetByte(dviFile)) + UnSign8(GetByte(dviFile));
    while (--i >= 0)
	(void) GetByte(dviFile);
}


static void
doDviChar(c, advance)
int c;
int advance;
{
    register struct glyph *g;
    register struct font *f;
    int p;

    f = dviCurrentFont->f;

    if (c < f -> f_lowch || c > f -> f_highch) {
	fprintf(stderr,"Character out of range: %d\n",
		c);
	return;
    }

    g = GLYPH(f, c);
    if (!GVALID(g)) {
	fprintf(stderr, "there is no character %d in %s",
	      c, f->f_path);
	exit(1);
    } else {

	if (HASRASTER(g)) {	/* workaround for Imagen bug */
	    applicationPutChar(dviHH,dviVV,c);
	}
	
	if (advance) {
	    dviHH += g->g_pixwidth;
	    dvi_h += g->g_tfmwidth;
	    p = fromSP(dvi_h);
	    FIXDRIFT(dviHH, p);
	}
    }
}

/*
 *	The next two routines are used to reset all the glyphs.
 *	the dviResetFont routine is called for each font in the font table.
 *	It de-allocates the rasters & glyphs for the shrunken fonts, leaving
 *	the original glyph data untouched.
 */


static void
dviResetFont(fi, key)
struct fontinfo *fi;
int key;
{
    if (fi != 0) {
	applicationResetFont(fi, fi -> family);
    }
}
	    
void
dviResetAll()
{
    SEnumerate(FontFinder, dviResetFont);
}

/*
 *	Process the DVI commands for page #page. If the page number is
 *	out of range, it is cropped to the end.
 *
 *	Updates dviCurrentPage
 */
void
dviPreparePage(page)
int page;
{
    register int c;
    register i32 p;
    int advance;

    if (page < 0) {
	page = 0;
    }

    if (page >= dviTotalPages) {
	page = dviTotalPages - 1;
    }

    dviCurrentPage = page;

    fseek(dviFile, (long) pageOffset[page], 0);

    dviHH = dviHHMargin;
    dviVV = dviVVMargin;

    dvi_h = toSP(dviHH);
    dvi_v = toSP(dviVV);

    dvi_w = 0;
    dvi_x = 0;
    dvi_y = 0;
    dvi_z = 0;

    dvi_stackp = dvi_stack;
    
    for(;;) {
/*
 * Get the DVI byte, and switch on its parameter length and type.
 * Note that getchar() returns unsigned values.
 */

	if (feof(dviFile)) {
	    fprintf(stderr,"Unexpected end-of-file\n");
	    exit(1);
	}

	c = getc(dviFile);

	if (DVI_IsChar(c)) {
	    advance = 1;
	    doDviChar(c, advance);
	} else {
	
	switch (DVI_OpLen(c)) {
	    
	case DPL_NONE:
	    break;
	    
	case DPL_SGN1:
	    p = getc(dviFile);
	    p = Sign8(p);
	    break;
	    
	case DPL_SGN2:
	    fGetWord(dviFile, p);
	    p = Sign16(p);
	    break;
	    
	case DPL_SGN3:
	    fGet3Byte(dviFile, p);
	    p = Sign24(p);
	    break;
	    
	case DPL_SGN4:
	    fGetLong(dviFile, p);
	    break;
	    
	case DPL_UNS1:
	    p = UnSign8(getc(dviFile));
	    break;
	    
	case DPL_UNS2:
	    fGetWord(dviFile, p);
	    p = UnSign16(p);
	    break;
	    
	case DPL_UNS3:
	    fGet3Byte(dviFile, p);
	    p = UnSign24(p);
	    break;
	    
	default:
	    panic("DVI_OpLen(%d) = %d", c, DVI_OpLen(c));
	    /* NOTREACHED */
	}
	
	switch (DVI_DT(c)) {
	    
	case DT_SET:
	    c = p;
	    doDviChar(c, 1);
	    break;
	    
	case DT_PUT:
	    c = p;
	    doDviChar(c, 0);
	    break;

	case DT_SETRULE:
	case DT_PUTRULE:
	    
	{
	    i32 h, w, rw;
	    
	    fGetLong(dviFile, h);
	    fGetLong(dviFile, rw);
	    
	    h = ConvRule(h);
	    w = ConvRule(rw);
	    
	    applicationSetRule(dviHH, dviVV, h,w);
	    
	    if (DVI_DT(c) == DT_SETRULE)  {
		dviHH += w;
		dvi_h += rw;
		w = fromSP(dvi_h);
		FIXDRIFT(dviHH, w);
	    }
	}
	    break;
	    
	case DT_NOP:
	    break;
	    
	case DT_BOP:
/*
 *	Each beginning of page has 11 4-byte words telling us things
 *	about the page. We ignore them.
 */
	{
	    fseek(dviFile, (long) (11 * 4), 1);
	}

	    break;
	    
	case DT_EOP:
	    return;
	    
	case DT_PUSH:
	    dvi_stackp->stack_hh = dviHH;
	    dvi_stackp->stack_vv = dviVV;
	    dvi_stackp->stack_dvi = dvi_current;
	    dvi_stackp++;
	    break;
	    
	case DT_POP:
	    dvi_stackp--;
	    dviHH = dvi_stackp->stack_hh;
	    dviVV = dvi_stackp->stack_vv;
	    dvi_current = dvi_stackp->stack_dvi;
	    break;
	    
	case DT_W0:	/* there should be a way to make these pretty */
	    p = dvi_w;
	    goto move_right;
	    
	case DT_W:
	    dvi_w = p;
	    goto move_right;
	    
	case DT_X0:
	    p = dvi_x;
	    goto move_right;
	    
	case DT_X:
	    dvi_x = p;
	    goto move_right;
	    
	case DT_RIGHT:
	move_right:
	    dvi_h += p;
/*
 * DVItype tells us that we must round motions in this way:
 * `When the horizontal motion is small, like a kern, hh
 * changes by rounding the kern; but when the motion is
 * large, hh changes by rounding the true position so that
 * accumulated rounding errors disappear. 
 */
	    if (p >= dviCurrentFont->pspace || p <= dviCurrentFont->nspace)
		dviHH = fromSP(dvi_h);
	    else {
		dviHH += fromSP(p);
		p = fromSP(dvi_h);
		FIXDRIFT(dviHH, p);
	    }
	    break;
	    
	case DT_Y0:
	    p = dvi_y;
	    goto move_down;
	    
	case DT_Y:
	    dvi_y = p;
	    goto move_down;
	    
	case DT_Z0:
	    p = dvi_z;
	    goto move_down;
	    
	case DT_Z:
	    dvi_z = p;
	    goto move_down;
	    
	case DT_DOWN:
	move_down:
	    dvi_v += p;
/*
 * `Vertical motion is done similarly, but with the threshold
 * between ``small and ``large increased by a factor of
 * 5.  The idea is to make fractions like $1\over2$ round
 * consistently, but to absorb accumulated rounding errors in
 * the baseline-skip moves. 
 */
	    if (ABS(p) >= dviCurrentFont->vspace)
		dviVV = fromSP(dvi_v);
	    else {
		dviVV += fromSP(p);
		p = fromSP(dvi_v);
		FIXDRIFT(dviVV, p);
	    }
	    break;
	    
	case DT_FNTNUM:
	    SelectFont((i32) (c - DVI_FNTNUM0));
	    break;
	    
	case DT_FNT:
	    SelectFont(p);
	    break;
	    
	case DT_XXX:
	{
	    char specialBuffer [2048];
	    register char *cp;
	    int sweetp = 0;

	    if (p > 2047) {
		sweetp = p - 2047;
		p = 2047;
	    }
	    
	    for (cp = specialBuffer ; p > 0; p--) {
		*cp = getc(dviFile);
		cp++;
	    }
	    *(cp) = 0;

	    while(sweetp > 0) {
		getc(dviFile);
	    }

	    applicationDoSpecial(specialBuffer);
	}
	    break;
	    
	case DT_FNTDEF:
	    SkipFontDef(p);
	    break;
	    
	case DT_PRE:
	    GripeUnexpectedOp("PRE");
	    /* NOTREACHED */
	    
	case DT_POST:
	    GripeUnexpectedOp("POST");
	    /* NOTREACHED */
	    
	case DT_POSTPOST:
	    GripeUnexpectedOp("POSTPOST");
	    /* NOTREACHED */
	    
	case DT_UNDEF:
	    GripeUndefinedOp(c);
	    /* NOTREACHED */
	    
	default:
	    panic("DVI_DT(%d) = %d", c, DVI_DT(c));
	    /* NOTREACHED */
	}
    }
    }
}

/*
 *	The following routine is used to shrink a glyph by some
 *	shrink factor (in the width & height dimension).
 *
 *	These shrunken glyphs are more appropriate for previewers.
 *
 *	To do this, we simple scan the original raster, counting the
 *	number of pixels within a given area. If the number of on pixels is
 *	at least twice the total number of pixels, we turn the pixel in
 *	the shrunken glyph ON, else OFF.
 *
 *	We use a lookup table to hasten the process of counting pixels.
 *
 *	The method used should be independent of byte-order (I think).
 *
 *	You need to define two types. One should be 32-bits long, and
 *	the other 16 bits long.
 */

typedef unsigned short B16;
typedef unsigned long B32;

#define LOOKUP_BYTES	256
#define	LOOKUP_BITS	8
#define LOOKUP_MASK	0xff

static char dviLookUpTable[LOOKUP_BYTES];
static char tableNotInitialized = 1;

struct glyph *
dviShrinkGlyph(gly, shrinkH, shrinkW)
DviGlyph *gly;
int shrinkH;
int shrinkW;
{
    int shrunkHeight;
    int shrunkWidth;
    int glyphWide;
    int glyphHigh;

    int bytesWide;
    int shrunkBytesWide;

    struct glyph *ngly;

    B16 *shrunkRaster;
    int rasterSize;

    int x,y;
    char *cp;
    B16 *ptr;

    B32 shrinkMask;

    int sampleSize;

    if (gly == 0 || !HASRASTER(gly)) {
	return(0);
    }

    if (gly -> g_raster == 0) {
	gly-> g_raster = RASTER(gly, dviCurrentFont -> f, ROT_NORM);
    }

/*
 *	Initialize the lookup table of the number of bits in a given byte
 */

    if (tableNotInitialized) {
	register int i;
	register int j;
	register int k;
	register int acc;
	for (i = 0; i < LOOKUP_BYTES; i++) {
	    j = i;
	    acc = 0;
	    for (k = 0; j != 0 && k < LOOKUP_BITS ; k++) {
		acc += (j & 1);
		j >>= 1;
	    }
	    dviLookUpTable[i] = acc;
	}
	tableNotInitialized = 0;
    }

/*
 *	When shrinking the fonts, we convert them from byte alligned
 *	to 16 bit-aligned fonts. I think that this is needed by X,
 *	and also SunWindows. This is done rather than changing the
 *	library routines because some device drivers, i.e. imagen1,
 *	depend on the byte-alligned fonts.
 */
    glyphHigh = gly -> g_height;
    glyphWide = gly -> g_width;

    shrunkHeight = (glyphHigh + shrinkH - 1) / shrinkH;
    shrunkWidth =  (glyphWide + shrinkW - 1) / shrinkW;

    bytesWide = (gly -> g_width + 7) >> 3;
    
    shrunkBytesWide = ((shrunkWidth + 15) >> 4) * 2;

    rasterSize = (shrunkHeight + 1) * shrunkBytesWide;
    ptr = shrunkRaster = (B16 *) malloc(rasterSize);
    bzero(ptr, rasterSize);
    
    if (ptr == NULL) {
	fprintf(stderr, "Out of memory!\n");
	exit(1);
    }

    for (y = 0; y < glyphHigh; y+= shrinkH) {
	cp = (char *) ptr;
	shrinkMask = 0x8000;
	for (x = 0; x < glyphWide; x += shrinkW) {
	    int i;
	    int samples;
	    char *baseP;
	    int upper;
	    register int thisShrinkW;

	    baseP = gly -> g_raster + (y * bytesWide);

/*
 *	Set the upper limit on the height iteration so we dont count
 *	off the end of the raster
 */

	    upper = y + shrinkH;
	    if (upper > glyphHigh) {
		upper = glyphHigh;
	    }

	    if (x + shrinkW > glyphWide) {
		thisShrinkW = glyphWide - x;
	    } else {
		thisShrinkW = shrinkW;
	    }

	    samples = 0;
	    sampleSize = thisShrinkW * shrinkH;

	    for (i = y; i < upper; i++) {
		register int acc;
		register char *p;
		register char *ep;
/*
 *	Determine how many bytes our shrink window crosses (we might
 *	overlap on byte-edges)
 */

		p = baseP + (x >> 3);
		ep = baseP + ( (x + thisShrinkW - 1) >> 3);
		baseP += bytesWide;

/*
 *	stuff everything in the accumulator
 */

		acc = 0;
		while (p <= ep) {
		    acc = ((acc << 8) & 0xff) | *p;
		    p++;
		}

/*
 *	clean off the right hand-side of extra bits, then clean off
 *	the left hand side of extra bits, and then count them.
 */

		acc = acc >> ( 7 - ((x + thisShrinkW - 1) & 0x7));
		acc &= ~(-1 << thisShrinkW);
		while (acc != 0) {
		    samples += dviLookUpTable[ acc & LOOKUP_MASK ];
		    acc >>= LOOKUP_BITS;
		}
	    }
/*
 *	If at least 1/blackness of the bits are on, treat this entire sample as
 *	being on.
 */

	    if ((samples * dviBlackness) >= sampleSize) {
		*ptr |= shrinkMask;
	    } else {
		*ptr &= ~ shrinkMask;
	    }
	    shrinkMask >>= 1;
	    if (shrinkMask == 0) {
		shrinkMask = 0x8000;
		ptr ++;
	    }
	}
	ptr = (B16 *) (cp + shrunkBytesWide);
    }

/*
 *	Build a new glyph from the shrunken raster
 */

#ifdef	UNDEF
    printf("Old glyph:\n");
    seeGlyph(gly -> g_raster, glyphHigh, bytesWide);
    printf("New glyph:\n");
    seeGlyph(shrunkRaster, shrunkHeight, shrunkBytesWide);
#endif	UNDEF

    ngly = (struct glyph *) malloc(sizeof(struct glyph));
    bzero(ngly, sizeof(struct glyph));

    ngly -> g_raster = (char * ) shrunkRaster;
    ngly -> g_width = shrunkWidth;
    ngly -> g_height = shrunkHeight;

    ngly -> g_xorigin = gly -> g_xorigin / shrinkH;
    ngly -> g_yorigin = gly -> g_yorigin / shrinkW;

    ngly -> g_flags |= GF_SHRUNK;	/* yes, its been shrunk */

    return(ngly);
}

#ifdef	UNDEF

seeGlyph(c, h, w)
char *c;
int h;
int w;
{
    int i,j;

    for (i = 0; i < h; i++ ) {
	for (j = 0; j < w; j++) {
	    int k;
	    register int ch;
	    register int m;
	    char str[9];

	    ch = *(c++);
	    m = 0x80;
	    for (k = 0; k < 8; k++) {
		str[k] = '0' + ( (ch & m) ? 1 : 0 );
		m >>= 1;
	    }
	    str[8] = 0;
	    printf("%s", str);
	}
	printf("\n");
    }
}
		
		
#endif	UNDEF