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 p

⟦1d9c49248⟧ TextFile

    Length: 23775 (0x5cdf)
    Types: TextFile
    Names: »pkfont.c«

Derivation

└─⟦52210d11f⟧ Bits:30007239 EUUGD2: TeX 3 1992-12
    └─⟦883b7f77d⟧ »dvi2vdu.tar.Z« 
        └─⟦f158c222e⟧ 
            └─⟦this⟧ »dvi2vdu/dvi2vdu-1.1J/src/pkfont.c« 

TextFile

/****************************************************************************
  PK file reader and FullChar1(), FullChar2() for DVItoVDU (True PK version)
  12 May 1990
  Masahiro Kitagawa (kitagawa@wave.ntt.jp)
  NTT Basic Research Labs. Tokyo Japan
  
  FullChar1() and FullChar2():
  Original Author:         Andrew Trevorrow
  Implementation: Modula-2 under VAX/UNIX 4.2 BSD
  Date Started:   June, 1986 (based on version 1.5 under VAX/VMS 4.2)
  
  This version converted to C and ported to BSD and System V UNIX by
  some chaps at Kernel Technology up to September 1989.
  
  Involved were:	Mark J. Hewitt
  Dave Dixon
  Marc Hadley
  
  PK reading on demand:      by Masahiro Kitagawa (12 May 1990)
  Moved from dvitovdu.c to pkfile.c
  PK stuff are borrowed from Tomas Rokicki's pktype.c and pktopx.c
  ****************************************************************************/

#include "def.h"

#ifdef USG
#include <string.h>
#include <setjmp.h>
#else
#include <strings.h>
#endif /* USG */
#include <fcntl.h>
#include <ctype.h>
#include <math.h>

#include "dvitovdu.h"
#include "dvireader.h"
#include "screenio.h"

extern int PixelRound();

extern stringvalue dummyfont,
  fontdir;

/* DVItoVDU needs to move about randomly in FONT files when getting information
   on the character widths and glyph shapes in a particular font.
   Only one FONT file will be open at any one time. */

#define CARDINAL(i) (unsigned)(i)

extern int
  papertop,
  paperleft,
  paperbottom,
  paperright,		/* these define the edges of the paper    */
  windowtop,
  windowleft,
  windowbottom,
  windowright,		/* these define the current window edges  */
  scaledht,			/* current window height in paper pixels  */
  scaledwd;			/* current window width in paper pixels   */

extern short
  allpagevisible,		/* is all of page visible in window?      */
  outsidepage;		/* is entire window outside page?         */

extern double
  vscalefactor,		/* windowht / scaledht                    */
  hscalefactor;		/* windowwd / scaledwd                    */

/* Expand/ShrinkHpos and Expand/ShrinkVpos are assigned to these procedure
   variables depending on the values of h/vscalefactor.          */

extern int   (*ScaleVpos) (), (*ScaleHpos) ();

extern ruleinfoptr thisruleinfo;  /* current rule info in rulelist          */
extern fontinfoptr unusedfont;	  /* first unused font in sorted fontlist   */
extern fontinfoptr thisfontinfo;  /* current font info in sorted fontlist   */
extern charinfoptr thischarinfo;  /* current char info in charlist          */

extern unsigned int thischar;	  /* current index into current chartable   */

extern short
  fontopen,		/* is thisfontinfo^.fontspec open?        */
  useraborted,		/* did user abort page display?           */
  charvisible;		/* was character actually displayed?      */

struct chartab *cptr;
pixeltableptr pptr;

#define namelength 80 
#define terminallinelength 132 
#define incr(a) a++
#define decr(a) a--
#define true (1)
#define false (0)
#define round(a) ((int)(a+.5))

typedef int integer ;
typedef unsigned char quarterword ;
typedef char boolean ;
typedef float real ;
typedef quarterword eightbits ; 
typedef FILE *bytefile ; 
bytefile pkfile ; 
char pkname[82] ; 
integer magnification ; 
integer hppp ;
integer i, j ; 
integer flagbyte ; 
integer endofpacket ; 
integer width, height ; 
integer dynf ; 
integer car ; 
eightbits inputbyte ; 
eightbits bitweight ; 
eightbits nybble ; 
integer repeatcount ; 
integer rowsleft ; 
boolean turnon ; 
integer hbit ; 
integer count ; 

#define MAXPXLWORD 1024 /* Maximum number of word in PXL raster. Enough ? */
int pxlword[MAXPXLWORD]; /* PXL raster */
int ipxl;                /* word in PXL raster */

#define ONEFOURTH 1073741824
integer power[32];
integer gpower[33];

jumpout () {
  RestoreTerminal ();
  (void) exitprog (1);
} 
short openpkfile (filename)
     char *filename; 
{
  (void) sprintf (pkname, "%s/%s", fontdir, filename);
  pkfile = fopen ( pkname , "r" ); 
  return (pkfile != NULL);
} 

void closepkfile ()
{
  /* Close the currently open PK file. */
  (void) fclose (pkfile);
} 

#define  pkbyte() ( (eightbits) getc ( pkfile ) )
#define get16() ( (integer) ( pkbyte() * 256 + pkbyte () ) )
integer get32 ()
{
  integer a ; 
  return ( ( a = get16 () ) > 32767 )?
    ( ( a - 65536 ) * 65536 + get16 () ) :
      ( a * 65536 + get16 () );
} 
integer getnyb ()
{
  eightbits temp ; 
  if ( bitweight == 0 ) 
    { inputbyte = pkbyte () ; 
      bitweight = 16 ; 
    } 
  temp = inputbyte / bitweight ; 
  inputbyte = inputbyte - temp * bitweight ; 
  bitweight = bitweight / 16 ; 
  return ( temp ) ; 
} 
boolean getbit ()
{
  boolean temp ; 
  bitweight = bitweight / 2 ; 
  if ( bitweight == 0 ) 
    { inputbyte = pkbyte () ; 
      bitweight = 128 ; 
    } 
  temp = inputbyte >= bitweight ; 
  if ( temp ) inputbyte = inputbyte - bitweight ; 
  return ( temp ) ; 
} 

void initpower ()
{
  integer i;
  power[0] = 1;
  for (i = 1; i <= 30; i++)
    power[i] = power[i - 1] * 2;
  power[31] = -ONEFOURTH - ONEFOURTH;
  gpower[0] = 0;
  for (i = 1; i <= 32; i++)
    gpower[i] = gpower[i - 1] + power[i - 1];
}

integer pkpackednum ()
{
  integer i, j;
  
  i = getnyb ();
  if (i == 0)
    {
      do
	{
	  j = getnyb ();
	  incr (i);
	} while (!(j != 0));
      while (i > 0)
	{
	  j = j * 16 + getnyb ();
	  decr (i);
	}
      return (j - 15 + (13 - dynf) * 16 + dynf);
    }
  else
    if (i <= dynf)
      return (i);
    else
      if (i < 14)
	return ((i - dynf - 1) * 16 + getnyb () + dynf + 1
		);
      else
	{
	  if (i == 14)
	    repeatcount = pkpackednum ();
	  else
	    repeatcount = 1;
	  return (pkpackednum ());
	}
}

skipspecials ()
{
  integer i, j, k ; 
  do { flagbyte = pkbyte () ; 
       if ( flagbyte >= 240 ) switch ( flagbyte ) 
	 { case 240 : 
	   case 241 : 
	   case 242 : 
	   case 243 : 
	     { i = 0 ; 
	       for ( j = 240 ; j <= flagbyte ; j ++ ) i = 256 * i + pkbyte (); 
	       for ( j = 1 ; j <= i ; j ++ ) pkbyte();
	     } 
	     break ; 
	   case 244 : 
	     get32();
	     break ; 
	   case 245 : 
	     break ; 
	   case 246 : 
	     break ; 
	   case 247 : 
	   case 248 : 
	   case 249 : 
	   case 250 : 
	   case 251 : 
	   case 252 : 
	   case 253 : 
	   case 254 : 
	   case 255 : 
	     { ; 
	       jumpout () ; 
	     } 
	     break ; 
	   } } while ( ! ( ( flagbyte < 240 ) || ( flagbyte == 245 ) ) ) ; 
} 

Void MyPixelTableRoutine ()
{
  
  /* SYSDEP: PixelTableRoutine for DVIReader which has just allocated a new
     pixeltable for currfont^.  DVIReader calls this routine from InterpretPage
     only ONCE per font (the first time the font is used).
     We get the pixeltable information from the font file given by fontspec.
     (If this is the first time we've seen the font then we build fontspec first.
     Note that the Show command also requires fontspec to be built.)
     If we can't open the PXL file, we return dummyfont values but using the
     current font's scaledsize.
     */
  int  j, r;
  unsigned int  i;
  int   alpha, beta, b0, b1, b2, b3;/* 4 bytes in fix width */
  int off;
  
  if (currfont->fontspeclen == 0)/* need to build fontspec */
    BuildFontSpec (currfont);
  
  ClearMessageLine ();
  
  if (openpkfile (currfont->fontspec))
    {
      WriteString ("Loading font data from ");
      WriteString (currfont->fontspec);
      WriteLn ();
    }
  else
    if (openpkfile (dummyfont))
      {
	/* we return a pixeltable with dummyfont values */
	WriteString ("Couldn't open ");
	WriteString (currfont->fontspec);
	WriteString ("!   Loading dummy font.");
	WaitForReturn ();
	ClearMessageLine ();
	WriteBuffer ();	/* user RETURN clears message line immediately */
      }
    else
      {
	(*ResetVDU) ();
	WriteLn ();
	WriteString ("Couldn't open dummy font ");
	WriteString (dummyfont);
	Write ('!');
	WriteLn ();
	RestoreTerminal ();
	(void) exitprog (1);
      }
  if ( pkbyte () != 247 ) 
    { ; 
      jumpout () ; 
    } 
  if ( pkbyte () != 89 ) 
    { ; 
      jumpout () ; 
    } 
  j = pkbyte () ; 
  for ( i = 1 ; i <= j ; i ++ ) pkbyte();
  fseek(pkfile, 8, 1);  /* designsize, checksum */
  hppp = get32 () ; 
  fseek(pkfile, 4, 1);  /* vppp */
  magnification = round ( hppp * 72.27 / 65536 ) ; 
  skipspecials () ; 
  while ( flagbyte != 245 ) 
    {
      off = ftell(pkfile) - 1;
      dynf = flagbyte / 16 ; 
      flagbyte = flagbyte % 16 ; 
      if ( flagbyte >= 8 ) flagbyte = flagbyte - 8 ; 
      if ( flagbyte == 7 ) 
	{ endofpacket = off + 5 + get32 () ; 
	  car = get32 () ; /* character */
	  b0=pkbyte();
	  b1=pkbyte();
	  b2=pkbyte();
	  b3=pkbyte();
	  fseek(pkfile, 8, 1);  /* dx, dy */
	  currfont->pixelptr[car].wd = get32 () ;
	  currfont->pixelptr[car].ht = get32 () ;
	  currfont->pixelptr[car].xo = get32 () ;
	  currfont->pixelptr[car].yo = get32 () ;
        } 
      else if ( flagbyte > 3 ) 
	{ endofpacket = off + 4 + ( flagbyte - 4 ) * 65536 + get16 () ; 
	  car = pkbyte () ; 
	  b0=0;
	  b1=pkbyte();
	  b2=pkbyte();
	  b3=pkbyte();
	  fseek(pkfile, 2, 1); /* dx = get16 () * 65536 ; dy = 0 ; */
	  currfont->pixelptr[car].wd = get16 () ;
	  currfont->pixelptr[car].ht = get16 () ;
	  currfont->pixelptr[car].xo = ((r = get16 ()) > 32767) ?
	    r - 65536 : r;
	  currfont->pixelptr[car].yo = ((r = get16 ()) > 32767) ?
	    r - 65536 : r;
        } 
      else 
	{ endofpacket = off + 3 + flagbyte * 256 + pkbyte () ; 
	  car = pkbyte () ; 
	  b0=0;
	  b1=pkbyte();
	  b2=pkbyte();
	  b3=pkbyte();
	  fseek(pkfile, 1, 1);  /* dx = pkbyte () * 65536 ; dy = 0 ; */
	  currfont->pixelptr[car].wd = pkbyte () ;
	  currfont->pixelptr[car].ht = pkbyte () ;
	  currfont->pixelptr[car].xo = ((r = pkbyte ()) > 127) ?
	    r - 256 : r;
	  currfont->pixelptr[car].yo = ((r = pkbyte ()) > 127) ?
	    r - 256 : r;
        } 
      currfont->pixelptr[car].mapadr = off;  /* byte offset in PK file */
      /*
	Convert the fix width into the corresponding dwidth and pwidth values
	using the method recommended in DVITYPE. WARNING: DVI translators
	that read RST files will have to use a different method because the
	widths in such files are  NOT equivalent to those in a TFM file.
	*/
      alpha = 16 * currfont->scaledsize;
      beta = 16;
      while (currfont->scaledsize >= 040000000)    /* 2^23 */
	{
	  currfont->scaledsize = currfont->scaledsize / 2;
	  beta = beta / 2;
	}
      currfont->pixelptr[car].dwidth = 
	(((((b3 * ((int) currfont->scaledsize)) / 0400) +
	   (b2 * ((int) currfont->scaledsize))) / 0400) +
	 (b1 * ((int) currfont->scaledsize))) / beta;
      if (b0 > 0)
	if (b0 == 255)
	  currfont->pixelptr[car].dwidth -= alpha;
	else
	  {
#ifdef DEBUG
	    (*ResetVDU)();
	    WriteLn();
	    WriteString("Bad fix width! 1st byte=");
	    WriteInt(b0);
	    WriteLn();
	    RestoreTerminal();
	    exitprog (1);
#endif /* DEBUG */
	  }
      /* convert DVI units to pixels */
      currfont->pixelptr[car].pwidth =
	PixelRound (currfont->pixelptr[car].dwidth);
      bitweight = 0 ; 
      fseek(pkfile, endofpacket, 0);
      skipspecials () ; 
    }
  (void) fclose(pkfile);
}

void movetopkchar (mapadr) /* get dynf and turnon, move to pk packed data */
     int mapadr;
{
  fseek(pkfile, mapadr, 0);
  flagbyte = pkbyte () ; 
  dynf = flagbyte / 16 ; 
  flagbyte = flagbyte % 16 ; 
  turnon = flagbyte >= 8 ; 
  if ( turnon ) flagbyte = flagbyte - 8 ; 
  if ( flagbyte == 7 ) { /* Long Form */
    fseek(pkfile, 36, 1);
  }
  else if ( flagbyte > 3 ) { /* Extended Short Form */
    fseek(pkfile, 16, 1);
  } 
  else { /* Short Form */
    fseek(pkfile, 10, 1);
  }
}

void pktopxl()      /* unpack pk into pxl raster */
{
  integer i,j;
  integer wordwidth;
  integer rp;
  integer row[101];
  integer word;
  integer wordweight;
  
  ipxl=0;
  bitweight = 0;
  wordwidth = (width + 31) / 32;
  
  bitweight = 0;
  if (dynf == 14)
    {
      bitweight = 0;
      for (i = 1; i <= height; i++)
	{
	  word = 0;
	  wordweight = 31;
	  for (j = 1; j <= width; j++)
	    {
	      if (getbit ())
		word = word + power[wordweight];
	      wordweight = wordweight - 1;
	      if (wordweight == -1)
		{
		  pxlword[ipxl++]=(int)(word);
		  word = 0;
		  wordweight = 31;
		}
	    }
	  if (wordweight < 31)
	    pxlword[ipxl++]=(int)(word);
	}
    }
  else
    {
      rowsleft = height;
      hbit = width;
      repeatcount = 0;
      wordweight = 32;
      word = 0;
      rp = 1;
      while (rowsleft > 0)
	{
	  count = pkpackednum ();
	  while (count > 0)
	    {
	      if ((count < wordweight) && (count < hbit))
		{
		  if (turnon)
		    word = word + gpower[wordweight] - gpower
		      [wordweight - count];
		  hbit = hbit - count;
		  wordweight = wordweight - count;
		  count = 0;
		}
	      else
		if ((count >= hbit) && (hbit <= wordweight))
		  {
		    if (turnon)
		      word = word + gpower[wordweight] - gpower
			[wordweight - hbit];
		    row[rp] = word;
		    for (i = 0; i <= repeatcount; i++)
		      for (j = 1; j <=
			   wordwidth; j++)
			pxlword[ipxl++]=(int)(row[j]);
		    rowsleft = rowsleft - repeatcount - 1;
		    repeatcount = 0;
		    rp = 1;
		    word = 0;
		    wordweight = 32;
		    count = count - hbit;
		    hbit = width;
		  }
		else
		  {
		    if (turnon)
		      word = word + gpower[wordweight];
		    row[rp] = word;
		    rp = rp + 1;
		    word = 0;
		    count = count - wordweight;
		    hbit = hbit - wordweight;
		    wordweight = 32;
		  }
	    }
	  turnon = !turnon;
	}
    }
}

/*****************************************************************************/
Void FullChar1 ()
{
  /* 
    Display all pixels in a glyph using bitmap from PXL font file.
    This procedure is assigned to DisplayOneChar when h))&&( AND
    (vscalefactors are >= 1.0, so we don't have to worry about
    scaledheights/widths being 0.
    */
  
  int
    vpmyo, hpmxo,		/* vp-yo, hp-xo: glyph's top and left edges */
    top, bottom, left, right,   /* visible edges of glyph */
    scaledv, scalednextv,	/* scaled vertical positions for rows */
    scaledh,		        /* scaled h coord of start of run within row */
    scaledwidth, scaledheight,  /* scaled width and height of row */
    thisrow, thisbit;	        /* in paper coordinates */
  unsigned int
    wordsperrow,	        /* rows of PXL glyph are word aligned */
    firstbit,                   /* 0..wordsperrow*32 - 1 */
    firstword,	                /* 0..wordsperrow-1 */
    bitpos;		        /* 0..31 */
  int   glyphword;	        /* current word in bitmap, must be 32 bits */
  short
    inrun;		        /* are we in a run of black pixels in row? */
  
  {
    {
      struct chartab *cptr = &thischarinfo->chartable[thischar];
      {
	pixeltableptr pptr = thisfontinfo->pixelptr;
	if (pptr[cptr->code].mapadr == 0)
	  return;		/* glyph all white or absent */
	/* check if any part of glyph is visible */
	width=pptr[cptr->code].wd;
	height=pptr[cptr->code].ht;
	
	vpmyo = (cptr->vp) - (pptr[cptr->code].yo);
	hpmxo = (cptr->hp) - (pptr[cptr->code].xo);
	if (RectangleVisible 
	    (vpmyo, vpmyo + height - 1, hpmxo, hpmxo + width - 1,
	     /* glyph edges */
	     &top, &bottom, &left, &right /* visible part */ ) )
	  {
	    if (!fontopen)	/* only open once */
	      {
		OpenFontFile ();
		fontopen = TRUE;
	      }
	    wordsperrow = (width + 31) / 32;
	    /* words in one row of bitmap */
	    firstbit = CARDINAL ((left - hpmxo));
	    /* first visible bit in row */
	    
	    firstword = firstbit / 32;        /* first visible word */
	    /* calculate scaled v coord of first visible row */
	    scaledv = (*ScaleVpos) (top - windowtop) + windowv;
	    
	    /* move to pk raster data */
	    movetopkchar(pptr[cptr->code].mapadr);
	    pktopxl();
	    
	    /* only consider visible rows; thisrow = top to bottom */
	    thisrow = top;
	    for (;;)
	      {
		/* calculate scaled v coord of next row */
		scalednextv = (*ScaleVpos) (thisrow + 1 - windowtop) + windowv;
		scaledheight = scalednextv - scaledv;/* can't be 0 */
		/* move to first byte of first visible word in this row */
		ipxl = (CARDINAL (thisrow - vpmyo) *  wordsperrow) + firstword;
		glyphword = pxlword[ipxl++];
		bitpos = 31 - (firstbit % 32);/* 31..0 */
		inrun = FALSE;
		
		/* display black pixel runs in row, doing any h/v expansion */
		/* only consider visible bits; thisbit = left to right */
		thisbit = left;
		for (;;)
		  {
		    if ((1 << bitpos) & glyphword)/* start/continue run */
		      {
			if (!inrun)
			  {
			    inrun = TRUE;
			    /* remember start of run */
			    scaledh = (*ScaleHpos) (thisbit - windowleft)
			      + windowh;
			  }
		      }
		    else
		      if (inrun)	/* 0 bit has ended run */
			{
			  inrun = FALSE;
			  scaledwidth = (*ScaleHpos) (thisbit - windowleft)
			    + windowh - scaledh;
			  ShowRectangle
			    (scaledh, scaledv, scaledwidth, scaledheight,
			     (char) (cptr->code));
			}
		    if (thisbit == right)
		      break; /* bit loop */
		    if (bitpos == 0)
		      /* look at first bit in next word of row */
		      {
			glyphword = pxlword[ipxl++];
			bitpos = 31;
		      }
		    else		/* look at next bit in word */
		      bitpos--;
		    thisbit++;
		  }			/* bit loop */
		if (inrun)	/* show run at end of row; INC thisbit */
		  {
		    scaledwidth = (*ScaleHpos) (thisbit + 1 - windowleft)
		      + windowh - scaledh;
		    ShowRectangle
		      (scaledh, scaledv, scaledwidth, scaledheight,
		       (char) (cptr->code));
		  }
		if (thisrow == bottom)
		  break; /* row loop */
		scaledv = scalednextv;
		thisrow++;
	      }			/* row loop */
	    charvisible = TRUE;
	  }
	else
	  charvisible = FALSE;	/* checked in DisplayChars() */
      }
    }
  }
}

/*****************************************************************************/
Void FullChar2 ()
{
  /* Display all pixels in a glyph using bitmap from PXL font file.
     This procedure is assigned to DisplayOneChar when h/vscalefactor < 1.0.
     The algorithm avoids overlapping rows when vscalefactor < 1.0.
     When hscalefactor < 1.0, it is not worth the extra code to avoid
     overlapping runs of 1 bits because the majority of character glyphs
     have only one or two runs per row.
     */
  
#define MAXVISWORDS  30
  
  /* SYSDEP: 30 * 32 = 960 bits wide. Some sites may have very wide glyphs
     (such as a logo). 960 bits represents 3.2in on a 300 dpi device. */
  
  typedef int glyphrow[MAXVISWORDS - 1];
  /* SYSDEP: BITSET is 32 bit word with elements 31,30,29,...,0 */
  
  int
    vpmyo, hpmxo,		/* vp-yo, hp-xo: glyph's top and left edges */
    top, bottom, left, right,   /* visible edges of glyph */
    scaledv, scalednextv,	/* scaled vertical positions for rows */
    scaledh,		        /* scaled horizontal positions within row */
    scaledwidth, scaledheight,  /* scaled width and height of row */
    thisrow, thisbit;           /* in paper coordinates */
  
  glyphrow row;			/* holds VISIBLE bits in one row of glyph;
				   possibly > one row if vscalefactor < 1.0 */
  unsigned char
    wordsperrow,	        /* rows of PXL glyph are word aligned */
    firstbit, lastbit,          /* somewhere in 0 .. wordsperrow*32-1 */
    firstword, lastword,        /* somewhere in 0 .. wordsperrow-1 */
    endword,	                /* = visible words in row, - 1 */
    wordpos,	                /* 0 .. endword */
    bitpos,		        /* 31 .. 0 */
    i;
  
  short
    inrun;		        /* are we in a run of black pixels in row? */
  
  {
    {
      struct chartab *cptr = &thischarinfo->chartable[thischar];
      {
	pixeltableptr pptr = thisfontinfo->pixelptr;
	if (pptr[cptr->code].mapadr == 0)
	  return;		/* glyph all white or absent */
	/* check if any part of glyph is visible */
	width=pptr[cptr->code].wd;
	height=pptr[cptr->code].ht;
	
	vpmyo = cptr->vp - pptr[cptr->code].yo;
	hpmxo = cptr->hp - pptr[cptr->code].xo;
	if (RectangleVisible
	    (vpmyo, vpmyo + height - 1, hpmxo, hpmxo + width - 1, 
	     /* glyph edges */
	     &top, &bottom, &left, &right)) /* visible part */
	  {
	    if (!fontopen)	/* only open once */
	      {
		OpenFontFile ();
		fontopen = TRUE;
	      }
	    wordsperrow = (width + 31) / 32;
	    /* words in one row of bitmap */
	    firstbit = CARDINAL (left - hpmxo);      /* first visible bit */
	    lastbit = CARDINAL (right - hpmxo);      /* last visible bit */
	    firstword = firstbit / 32;               /* first visible word */
	    lastword = lastbit / 32;                 /* last visible word */
	    endword = lastword - firstword;
	    
	    /* #ifdef DEBUG			     /* Was #if 1 !! */
	      {
		/* we impose a limit on width of glyph
		   (unlikely to be exceeded) */
		if (endword > MAXVISWORDS - 1)
		  {
		    (*StartText) ();
		    ClearMessageLine ();
		    
		    WriteString ("Glyph ");
		    WriteCard ((unsigned)cptr->code);
		    WriteString (" too wide!");
		    WaitForReturn ();
		    (*StartGraphics) ();
		  }
	      }
	    /* #endif /* DEBUG */
	      
	      /* set the visible words in row to 0 */
	      for (i = 0; i <= endword; i++)
		row[i] = 0;
	    /* calculate scaled v coord of first visible row */
	    scaledv = (*ScaleVpos) (top - windowtop) + windowv;
	    
	    /* move to pk raster data */
	    movetopkchar(pptr[cptr->code].mapadr);
	    pktopxl();
	    
	    /* only consider visible rows; thisrow = top to bottom */
	    thisrow = top;
	    for (;;)
	      {
		/* move to first byte of first visible word in this row */
		ipxl = (CARDINAL (thisrow - vpmyo) *  wordsperrow) + firstword;
		/* get row of visible words from PXL file
		   and OR with row array */
		for (wordpos = 0; wordpos <= endword; wordpos++)
		  {
		    row[wordpos] = (int) pxlword[ipxl++] | row[wordpos];
		    /* set union */
		  }
		/* calculate scaled v coord of next row */
		scalednextv = (*ScaleVpos) (thisrow + 1 - windowtop) + windowv;
		scaledheight = scalednextv - scaledv;
		if ((scaledheight > 0) || (thisrow == bottom))
		  {
		    /* display black pixels in row, doing any h/v expansion */
		    if (scaledheight < 1)
		      scaledheight = 1;             /* avoid 0 */
		    inrun = FALSE;
		    bitpos = 31 - (firstbit % 32);  /* 31..0 */
		    wordpos = 0;
		    
		    /* only consider visible bits; thisbit = left to right */
		    thisbit = left;
		    for (;;)
		      {
			if ((1 << bitpos) & row[wordpos])
			  /* start/continue run */
			  {
			    if (!inrun)	/* remember start of run */
			      {
				inrun = TRUE;
				scaledh = (*ScaleHpos) (thisbit - windowleft)
				  + windowh;
			      }
			  }
			else
			  if (inrun)	/* 0 bit has ended run */
			    {
			      inrun = FALSE;
			      scaledwidth = (*ScaleHpos) (thisbit - windowleft)
				+ windowh - scaledh;
			      if (scaledwidth < 1)
				scaledwidth = 1;     /* avoid 0 */
			      ShowRectangle
				(scaledh, scaledv, scaledwidth, scaledheight,
				 (char) (cptr->code));
			    }
			if (thisbit == right)
			  break;              /* bit loop */
			if (bitpos == 0)
			  /* look at first bit in next word of row */
			  {
			    wordpos++;
			    bitpos = 31;
			  }
			else		/* look at next bit in word */
			  {
			    bitpos--;
			  }
			thisbit++;
		      }			/* bit loop */
		    if (inrun)	/* show run at end of row; INC thisbit */
		      {
			scaledwidth = (*ScaleHpos) (thisbit + 1 - windowleft)
			  + windowh - scaledh;
			if (scaledwidth < 1)
			  scaledwidth = 1;    /* avoid 0 */
			ShowRectangle
			  (scaledh, scaledv, scaledwidth, scaledheight,
			   (char) (cptr->code));
		      }
		    
		    if (thisrow == bottom)
		      break; /* row loop */
		    /* else reset the visible words in row to 0 */
		    for (i = 0; i <= endword; i++)
		      row[i] = 0;
		  }
		scaledv = scalednextv;
		thisrow++;
	      }			/* row loop */
	    
	    charvisible = TRUE;
	  }
	else
	  {
	    charvisible = FALSE;	/* checked in DisplayChars() */
	  }
      }
    }
  }
}