-- AlFont.mesa Edited by: Sandman on July 1, 1980  10:04 AM
-- Copyright  Xerox Corporation 1979, 1980

DIRECTORY
  BitBltDefs USING [AlignedBBTable, BBptr, BBTableSpace, BITBLT],
  FontDefs USING [BitmapState, FontHandle, FontObject],
  InlineDefs USING [BITAND, BITOR, BITSHIFT],
  SegmentDefs USING [
    FileSegmentAddress, FileSegmentHandle, SwapIn, SwapOut, Unlock],
  Storage USING [Node, Free];

AlFont: PROGRAM
  IMPORTS BitBltDefs, InlineDefs, SegmentDefs, Storage EXPORTS FontDefs =
  BEGIN OPEN FontDefs;

  FileSegmentHandle: TYPE = SegmentDefs.FileSegmentHandle;

  CR: CHARACTER = 15C;
  SP: CHARACTER = ' ;

  AlFontObject: TYPE = RECORD [
    procs: FontObject,
    seg: FileSegmentHandle,
    lockCount: CARDINAL,
    height: CARDINAL];

  AlFontHandle: TYPE = POINTER TO AlFontObject;

  FHptr: TYPE = POINTER TO FontHeader;
  Fptr: TYPE = POINTER TO Font;
  FCDptr: TYPE = POINTER TO FCD;
  FAptr: TYPE = POINTER TO FontArray;
  FontArray: TYPE = ARRAY [0..255] OF FCDptr;

  Font: TYPE = MACHINE DEPENDENT RECORD [
    header: FontHeader,
    FCDptrs: FontArray, -- array of self-relative pointers to
    -- FCD's. Indexed by char value.
    -- font pointer points hear!
    extFCDptrs: FontArray -- array of self-relative pointers to
    -- FCD's for extentions. As large an
    -- array as needed.
    ];

  FontHeader: TYPE = MACHINE DEPENDENT RECORD [
    maxHeight: CARDINAL, -- height of tallest char in font (scan lines)
    variableWidth: BOOLEAN, -- IF TRUE, proportionally spaced font
    blank: [0..177B], -- not used
    maxWidth: [0..377B] -- width of widest char in font (raster units).
    ];

  FCD: TYPE = MACHINE DEPENDENT RECORD [
    widthORext: [0..77777B], -- width or extention index
    hasNoExtension: BOOLEAN, -- TRUE=> no ext.;prevfield=width
    height: [0..377B], -- # scan lines to skip for char
    displacement: [0..377B] -- displacement back to char bitmap
    ];

  CharWidth: PUBLIC PROCEDURE [font: FontHandle, char: CHARACTER]
    RETURNS [w: CARDINAL] =
    BEGIN
    code: CARDINAL;
    cw: FCDptr;
    fontdesc: FAptr; -- checkfor control characters
    IF char = CR THEN char ← SP;
    IF char < SP THEN RETURN[CharWidth[font, '↑] + CharWidth[font, char + 100B]];
    w ← 0;
    fontdesc ← @LockFont[font].FCDptrs;
    code ← LOOPHOLE[char];
    DO
      cw ← LOOPHOLE[fontdesc[code] + LOOPHOLE[fontdesc, CARDINAL] + code];
      IF cw.hasNoExtension THEN EXIT;
      w ← w + 16;
      code ← cw.widthORext;
      ENDLOOP;
    w ← w + cw.widthORext;
    UnlockFont[font];
    RETURN
    END;

  CharHeight: PUBLIC PROCEDURE [font: FontHandle, char: CHARACTER]
    RETURNS [CARDINAL] = BEGIN RETURN[LOOPHOLE[font, AlFontHandle].height] END;

  PaintChar: PROCEDURE [
    font: FontHandle, char: CHARACTER, bmState: POINTER TO BitmapState] =
    BEGIN OPEN BitBltDefs, bmState;
    bba: BBTableSpace;
    bbt: BBptr = AlignedBBTable[@bba];
    cw: FCDptr;
    fontdesc: FAptr = @LockFont[font].FCDptrs;
    code: CARDINAL ← LOOPHOLE[char];
    bbt↑ ←
      [sourcetype: block, function: paint, dbca: origin, dbmr: wordsPerLine,
	dlx: x, dw: 16, sbmr: 1, slx: 0, sty: 0];
    DO
      cw ← LOOPHOLE[fontdesc[code] + LOOPHOLE[fontdesc, CARDINAL] + code];
      bbt.dty ← y + cw.height;
      bbt.dh ← cw.displacement;
      bbt.sbca ← cw - (bbt.dh ← cw.displacement);
      IF cw.hasNoExtension THEN
	BEGIN x ← x + (bbt.dw ← cw.widthORext); BITBLT[bbt]; EXIT END
      ELSE BEGIN BITBLT[bbt]; bbt.dlx ← x ← x + 16; END;
      code ← cw.widthORext;
      ENDLOOP;
    UnlockFont[font];
    RETURN
    END;

  ClearChar: PROCEDURE [
    font: FontHandle, char: CHARACTER, bmState: POINTER TO BitmapState] =
    BEGIN OPEN bmState, InlineDefs;
    bit: [0..15];
    xword: CARDINAL;
    scanLines: CARDINAL = LOOPHOLE[font, AlFontHandle].height;
    start, p: POINTER;
    cwidth: INTEGER ← CharWidth[font, char];
    mask: WORD;
    ones: WORD = 177777B;
    IF x < cwidth THEN BEGIN cwidth ← x; x ← 0 END ELSE x ← x - cwidth;
    xword ← x/16;
    bit ← x MOD 16;
    mask ← BITOR[BITSHIFT[ones, 16 - bit], BITSHIFT[ones, -(bit + cwidth)]];
    start ← origin + xword + y*wordsPerLine - 1;
    cwidth ← cwidth + bit;
    DO
      p ← start ← start + 1;
      THROUGH [0..scanLines) DO
	p↑ ← BITAND[p↑, mask]; p ← p + wordsPerLine; ENDLOOP;
      IF (cwidth ← cwidth - 16) <= 0 THEN EXIT;
      mask ← BITSHIFT[ones, -cwidth];
      ENDLOOP;
    RETURN
    END;

  LockFont: PROCEDURE [font: FontHandle] RETURNS [Fptr] =
    BEGIN OPEN SegmentDefs, af: LOOPHOLE[font, AlFontHandle];
    IF (af.lockCount ← af.lockCount + 1) = 1 THEN SwapIn[af.seg];
    RETURN[FileSegmentAddress[af.seg]]
    END;

  UnlockFont: PROCEDURE [font: FontHandle] =
    BEGIN OPEN SegmentDefs, af: LOOPHOLE[font, AlFontHandle];
    IF (af.lockCount ← af.lockCount - 1) = 0 THEN
      BEGIN Unlock[af.seg]; af.seg.inuse ← TRUE END;
    RETURN
    END;

  DestroyFont: PROCEDURE [font: FontHandle] =
    BEGIN CloseFont[font]; Storage.Free[font]; RETURN END;

  CloseFont: PROCEDURE [font: FontHandle] =
    BEGIN OPEN af: LOOPHOLE[font, AlFontHandle];
    IF af.seg.lock = 0 THEN SegmentDefs.SwapOut[af.seg];
    RETURN
    END;

  CreateFont: PUBLIC PROCEDURE [fontSegment: FileSegmentHandle]
    RETURNS [f: FontHandle] =
    BEGIN
    p: AlFontHandle = Storage.Node[SIZE[AlFontObject]];
    f ← LOOPHOLE[p];
    p↑ ←
      [procs:
       [paintChar: PaintChar, clearChar: ClearChar, charWidth: CharWidth,
	 charHeight: CharHeight, close: CloseFont, destroy: DestroyFont,
	 lock: LockFont, unlock: UnlockFont], seg: fontSegment, lockCount: 0,
	height: 0];
    p.height ← LockFont[f].header.maxHeight;
    UnlockFont[f];
    RETURN
    END;


  END..........