-- Compiler Font/nb
-- Stone December 2, 1981 9:30 PM
-- Stone+Tiberi, February 7, 1980 11:40 AM
-- implementing module for griffin fonts
DIRECTORY
GriffinMemoryDefs: FROM "GriffinMemoryDefs",
StringDefs: FROM "StringDefs" USING [AppendString, EquivalentString, LowerCase],
MiscDefs: FROM "MiscDefs" USING [Zero, SetBlock],
AltoDefs: FROM "AltoDefs" USING [BytesPerPage],
StyleDefs: FROM "StyleDefs",
InlineDefs: FROM "InlineDefs"
USING [BITOR, BITAND, LongMult, LongDiv,
LongDivMod, LongNumber],
GriffinFontDefs: FROM "GriffinFontDefs",
IxDefs: FROM "IxDefs",
GriffinFileDefs: FROM "GriffinFileDefs",
AltoFileDefs: FROM "AltoFileDefs" USING [FA],
DirectoryDefs: FROM "DirectoryDefs"
USING [EnumerateDirectory],
SegmentDefs: FROM "SegmentDefs"
USING [FileNameError],
ScreenDefs: FROM "ScreenDefs"
USING [Bitmap, Block, BLTBlockInScreen, EraseBox],
PointDefs: FROM "PointDefs"
USING [ScrPt, ObjPt, X, Y, ObjToScr, ScrToObj,
ObjValToScrVal, ScrValToObjVal],
Real: FROM "Real" USING [RoundI,RoundC],
StreamDefs: FROM "StreamDefs"
USING [NewWordStream, Read, Append, Write,
DiskHandle, ReadBlock, WriteBlock, GetFA,
JumpToFA, FileLength, CleanupDiskStream,
TruncateDiskStream, CreateWordStream, StreamIndex,
SetIndex];
Font: PROGRAM
IMPORTS GriffinMemoryDefs, StreamDefs, StringDefs,
MiscDefs, InlineDefs, ScreenDefs, GriffinFileDefs,
DirectoryDefs, PointDefs, Real, SegmentDefs
EXPORTS GriffinFontDefs =
BEGIN OPEN GriffinFontDefs, InlineDefs;
X: CARDINAL = PointDefs.X;
Y: CARDINAL = PointDefs.Y;
StrikeHeader: TYPE = MACHINE DEPENDENT RECORD
[
ignore1: [0 .. 4), fixed: BOOLEAN, ignore2: [0 .. 8192),
minascii: CARDINAL,
maxascii: CARDINAL,
maxwidth: CARDINAL,
length: CARDINAL, -- wrong
ascent: CARDINAL,
descent: CARDINAL,
xoffset: CARDINAL,
raster: CARDINAL
];
lStrikeHeader: CARDINAL = SIZE [StrikeHeader];
indexSize: CARDINAL = 128;
nameSize: CARDINAL = 19;
fontVersion: CARDINAL = 6;
fontPassword: CARDINAL = 143000B + fontVersion;
GriffinFontHeader: TYPE = MACHINE DEPENDENT RECORD
[
rotation: CARDINAL, -- in degrees
face: CARDINAL, -- face code as in Fonts.Widths
points: CARDINAL,
name: PACKED ARRAY [0 .. nameSize] OF CHARACTER,
height: CARDINAL, -- or width, if rotated
maxwidth: CARDINAL, -- or height, if rotated
ascent: CARDINAL,
raster: CARDINAL,
bitmapwords: CARDINAL,
offset: ARRAY [0 .. indexSize+2] OF CARDINAL,
displaywidth: ARRAY [0 .. indexSize+2] OF CARDINAL,
presswidth: ARRAY [0 .. indexSize+2] OF CARDINAL
]; -- followed by bitmap
--Width philosophy: width and height routines return
--physical height and width, as used in BitBlt. The width table
--contains the logical width of the character; i.e., for 90 degree
--rotation, it contains the physical height.
lGriffinFontHeader: CARDINAL = SIZE [GriffinFontHeader];
GriffinFont: TYPE = RECORD
[
next: GriffinFontHandle,
fd: FontDescriptor,
fa: AltoFileDefs.FA
];
lGriffinFont: CARDINAL = SIZE [GriffinFont];
GriffinFontHandle: TYPE = POINTER TO GriffinFont;
-- -----------------------------------------------------------------
FontError: PUBLIC SIGNAL = CODE;
StartupFontError: PUBLIC SIGNAL[type: ErrorType] = CODE;
-- -----------------------------------------------------------------
gFontHead, currentFont, lastFont: GriffinFontHandle ← NIL;
fontHeader: GriffinFontHeader;
bitMap: ScreenDefs.Bitmap ← [0, 0, 0, 0, NIL]; -- because it mustn't go away
gHandle: StreamDefs.DiskHandle ← StreamDefs.NewWordStream ["Griffin.Fonts",
StreamDefs.Read + StreamDefs.Write + StreamDefs.Append];
fwHandle: StreamDefs.DiskHandle = StreamDefs.NewWordStream ["Fonts.Widths",
StreamDefs.Read ! SegmentDefs.FileNameError => StartupFontError[nowidths]];
-- -----------------------------------------------------------------
DisplayString: PUBLIC PROCEDURE [string: STRING, screenpt: PointDefs.ScrPt, anchor: StyleDefs.Anchor, orientation: StyleDefs.Orientation, fd: FontDescriptorHandle] =
BEGIN
j: CARDINAL;
twiddle: REAL;
rotation: CARDINAL=fd.rotation;
bltpt: PointDefs.ObjPt;
char: CHARACTER;
block: ScreenDefs.Block;
height, width: CARDINAL;
aligned, vertical: BOOLEAN;
tl,br: PointDefs.ScrPt;
SetUpFont [fd];
block.bitmap ← @bitMap;
height ← StringHeight[string, fd, orientation];
width ← StringWidth[string, fd, orientation];
tl ← PointDefs.ObjToScr[TopLeft[PointDefs.ScrToObj[screenpt], height,
width, anchor, orientation, fontHeader.rotation]];
bltpt ← PointDefs.ScrToObj[tl];
br ← [tl[X]+PointDefs.ObjValToScrVal[width]-1,
tl[Y]+PointDefs.ObjValToScrVal[height]-1];
ScreenDefs.EraseBox [tl, br];
vertical ← orientation = or90 OR orientation = or270;
aligned ← IF vertical
THEN rotation = Rot0Degrees OR rotation = Rot180Degrees
ELSE rotation = Rot90Degrees OR rotation = Rot270Degrees;
SELECT orientation FROM
or180 => bltpt[X] ← bltpt[X]+width;
or90 => bltpt[Y] ← bltpt[Y]-height;
ENDCASE;
FOR j IN [0 .. string.length)
DO
char ← string [j];
block.h ← FDHeight [char];
block.w ← FDWidth [char];
block.ty ← 0;
block.lx ← FLeft [char] ;
twiddle ← IF vertical THEN (MaxWidth[fd] - FPWidth[char])/2
ELSE (MaxHeight[fd] - FPHeight[char])/2;
IF aligned THEN IF vertical
THEN bltpt[X] ← bltpt[X] + twiddle
ELSE bltpt[Y] ← bltpt[Y] - twiddle;
SELECT orientation FROM
or90 => bltpt[Y] ← bltpt[Y] + FPHeight[char];
or180 => bltpt[X] ← bltpt[X] - FPWidth[char];
ENDCASE;
ScreenDefs.BLTBlockInScreen [@block,
PointDefs.ObjToScr[bltpt], paint];
SELECT orientation FROM
or0 => bltpt[X] ← bltpt[X] + FPWidth[char];
or270 => bltpt[Y] ← bltpt[Y] - FPHeight[char];
ENDCASE;
IF aligned THEN IF vertical
THEN bltpt[X] ← bltpt[X] - twiddle
ELSE bltpt[Y] ← bltpt[Y] + twiddle;
ENDLOOP;
END;
-- -----------------------------------------------------------------
TopLeft: PUBLIC PROCEDURE [anchorPt: PointDefs.ObjPt,
height, width: CARDINAL,
anchor: StyleDefs.Anchor,
orientation: StyleDefs.Orientation,
rotation: CARDINAL]
RETURNS [tl: PointDefs.ObjPt]=
BEGIN
vertical, aligned, reverse: BOOLEAN;
shift, amount: INTEGER;
tl ← anchorPt;
vertical ← orientation = or90 OR orientation = or270;
reverse ← orientation=or90 OR orientation=or180;
aligned ← IF vertical
THEN rotation = Rot0Degrees OR rotation = Rot180Degrees
ELSE rotation = Rot90Degrees OR rotation = Rot270Degrees;
amount ← IF vertical THEN height ELSE width;
shift ← SELECT anchor FROM
right => IF reverse THEN 0 ELSE amount,
left => IF reverse THEN amount ELSE 0,
ENDCASE --center-- => amount/2;
IF vertical --adjust for Anchor:
THEN tl [Y] ← tl [Y] + shift
ELSE tl [X] ← tl [X] - shift;
IF aligned THEN
-- here, if characters are rotated 90 degrees to the line, we must
-- center around the narrow amount
BEGIN
shift ← (IF vertical THEN width ELSE height)/2;
IF vertical
THEN tl [X] ← tl [X] - shift
ELSE tl [Y] ← tl [Y] + shift;
END;
END;
-- -----------------------------------------------------------------
BltChar: PUBLIC PROCEDURE [char: CHARACTER, tl: PointDefs.ScrPt,
fd: FontDescriptorHandle]=
BEGIN
block: ScreenDefs.Block;
SetUpFont [fd];
block.bitmap ← @bitMap;
block.h ← FDHeight[char];
block.w ← FDWidth [char];
block.ty ← 0;
block.lx ← FLeft [char] ;
ScreenDefs.BLTBlockInScreen [@block, tl, replace];
END;
-- -----------------------------------------------------------------
Width: PUBLIC PROCEDURE [c: CHARACTER, fd: FontDescriptorHandle]
RETURNS [CARDINAL] =
BEGIN
SetUpFont [fd];
RETURN [FPWidth [c]];
END;
-- -----------------------------------------------------------------
StringWidth: PUBLIC PROCEDURE [string: STRING, fd: FontDescriptorHandle, orientation: StyleDefs.Orientation]
RETURNS [w: CARDINAL] =
BEGIN
j: CARDINAL;
SetUpFont [fd];
SELECT orientation FROM
or0, or180 =>
BEGIN
IF string=NIL THEN RETURN [0];
w ← 0;
FOR j IN [0 .. string.length)
DO w ← w + FPWidth [string[j]] ENDLOOP;
END;
or90, or270 => w ← MaxWidth[fd];
ENDCASE;
IF w#0 THEN w←w-1;
END;
-- -----------------------------------------------------------------
MaxWidth: PUBLIC PROCEDURE [fd: FontDescriptorHandle]
RETURNS [CARDINAL] =
BEGIN
SetUpFont [fd];
RETURN [SELECT fontHeader.rotation FROM
Rot0Degrees, Rot180Degrees =>
Real.RoundI[PointDefs.ScrValToObjVal[fontHeader.maxwidth]],
ENDCASE => Real.RoundI[PointDefs.ScrValToObjVal[fontHeader.height]]];
END;
-- -----------------------------------------------------------------
Height: PUBLIC PROCEDURE [c: CHARACTER, fd: FontDescriptorHandle] RETURNS [CARDINAL] =
BEGIN
SetUpFont [fd];
RETURN [FPHeight [c]];
END;
-- -----------------------------------------------------------------
StringHeight: PUBLIC PROCEDURE[string: STRING,
fd:FontDescriptorHandle,
orientation: StyleDefs.Orientation]
RETURNS [h: CARDINAL] =
BEGIN
j: CARDINAL;
SetUpFont [fd];
SELECT orientation FROM
or0, or180 => h ← MaxHeight[fd];
or90, or270 =>
BEGIN
IF string=NIL THEN RETURN [0];
h ← 0;
FOR j IN [0 .. string.length)
DO h ← h + FPHeight [string[j]] ENDLOOP;
END;
ENDCASE;
IF h#0 THEN h←h-1;
END;
-- -----------------------------------------------------------------
MaxHeight: PUBLIC PROCEDURE [fd: FontDescriptorHandle]
RETURNS [CARDINAL] =
BEGIN
SetUpFont [fd];
RETURN [SELECT fontHeader.rotation FROM
Rot0Degrees, Rot180Degrees =>
Real.RoundI[PointDefs.ScrValToObjVal[fontHeader.height]],
ENDCASE => Real.RoundI[PointDefs.ScrValToObjVal[fontHeader.maxwidth]]];
END;
-- -----------------------------------------------------------------
FDWidth: PROCEDURE [char: CHARACTER] RETURNS [CARDINAL] = INLINE
BEGIN -- returns actual x dimension of char
rot: CARDINAL = fontHeader.rotation;
RETURN [IF rot = Rot0Degrees OR rot = Rot180Degrees
THEN fontHeader.displaywidth[LOOPHOLE[char, CARDINAL]]
ELSE fontHeader.height
];
END;
-- -----------------------------------------------------------------
FDHeight: PROCEDURE [char: CHARACTER] RETURNS [CARDINAL] = INLINE
BEGIN -- returns actual y dimension of char for the display
rot: CARDINAL = fontHeader.rotation;
RETURN [IF rot = Rot0Degrees OR rot = Rot180Degrees
THEN fontHeader.height
ELSE fontHeader.displaywidth[LOOPHOLE[char,CARDINAL]]
];
END;
-- -----------------------------------------------------------------
FPWidth: PROCEDURE [char: CHARACTER] RETURNS [CARDINAL] = INLINE
BEGIN -- returns actual x dimension of char
rot: CARDINAL = fontHeader.rotation;
RETURN [IF rot = Rot0Degrees OR rot = Rot180Degrees
THEN fontHeader.presswidth[LOOPHOLE[char, CARDINAL]]
ELSE Real.RoundI[PointDefs.ScrValToObjVal[fontHeader.height]]
];
END;
-- -----------------------------------------------------------------
FPHeight: PROCEDURE [char: CHARACTER] RETURNS [CARDINAL] = INLINE
BEGIN -- returns actual y dimension of char for the display
rot: CARDINAL = fontHeader.rotation;
RETURN [IF rot = Rot0Degrees OR rot = Rot180Degrees
THEN Real.RoundI[PointDefs.ScrValToObjVal[fontHeader.height]]
ELSE fontHeader.presswidth[LOOPHOLE[char,CARDINAL]]
];
END;
-- -----------------------------------------------------------------
BaseLine: PUBLIC PROCEDURE [fd: FontDescriptorHandle]
RETURNS [CARDINAL] =
BEGIN
SetUpFont [fd];
RETURN [Real.RoundI[PointDefs.ScrValToObjVal[fontHeader.ascent]]];
END;
-- -----------------------------------------------------------------
FLeft: PROCEDURE [c: CHARACTER] RETURNS [CARDINAL] = INLINE
BEGIN
RETURN [fontHeader.offset [LOOPHOLE [c, CARDINAL]]];
END;
-- -----------------------------------------------------------------
ForAllFonts: PUBLIC PROCEDURE[do: PROCEDURE[font: FontDescriptorHandle]] =
BEGIN
rover: GriffinFontHandle;
FOR rover ← gFontHead, rover.next UNTIL rover = NIL
DO do[@rover.fd] ENDLOOP;
END;
-- -----------------------------------------------------------------
SetUpFont: PROCEDURE [fd: FontDescriptorHandle] =
BEGIN
OPEN GriffinMemoryDefs;
rover, precursor: GriffinFontHandle;
sameface, samerotation, faceprecursor: BOOLEAN;
rprecursor, fprecursor, rfprecursor: GriffinFontHandle ← NIL;
IF currentFont.fd.rotation = fd.rotation AND currentFont.fd.points = fd.points AND
currentFont.fd.face= fd.face AND
StringDefs.EquivalentString [currentFont.fd.name, fd.name] THEN RETURN;
rover ← gFontHead;
WHILE rover # NIL DO
IF NOT (StringDefs.EquivalentString [rover.fd.name, fd.name]
AND rover.fd.points = fd.points)
THEN BEGIN rover ← rover.next; LOOP END;
sameface ← rover.fd.face = fd.face;
samerotation ← rover.fd.rotation = fd.rotation;
faceprecursor ← rover.fd.face = 0 OR rover.fd.face = fd.face OR fd.face = 3;
IF sameface AND samerotation THEN BEGIN
currentFont ← rover; ReadGFont [currentFont]; EXIT END;
IF sameface AND rover.fd.rotation = Rot0Degrees THEN rprecursor ← rover;
IF samerotation AND faceprecursor THEN fprecursor ←rover;
IF faceprecursor THEN rfprecursor ← rover;
rover ← rover.next;
REPEAT FINISHED => BEGIN
precursor ← gFontHead;
IF rfprecursor # NIL THEN precursor ← rfprecursor;
IF fprecursor # NIL THEN precursor ← fprecursor;
IF rprecursor # NIL THEN precursor ← rprecursor;
IF precursor = NIL THEN SIGNAL FontError;
ReadGFont [precursor];
SELECT fd.rotation - fontHeader.rotation FROM
Rot0Degrees => NULL;
Rot90Degrees => BEGIN Rotate180D; Rotate90D END;
Rot180Degrees => Rotate180D;
Rot270Degrees => Rotate90D;
ENDCASE => SIGNAL FontError;
IF (fd.face = 2 OR fd.face = 3) AND
(fontHeader.face # 2 AND fontHeader.face # 3) THEN Bolden;
IF (fd.face = 1 OR fd.face =3) AND
(fontHeader.face # 1 AND fontHeader.face # 3) THEN Italicize;
AddGFont [fd];
END;
ENDLOOP;
END;
-- -----------------------------------------------------------------
ReadGFont: PROCEDURE [gfh: GriffinFontHandle] =
BEGIN
StreamDefs.JumpToFA [gHandle, @gfh.fa];
IF StreamDefs.ReadBlock [gHandle, @fontHeader, lGriffinFontHeader] #lGriffinFontHeader THEN
SIGNAL FontError;
GriffinMemoryDefs.FreeSegment [bitMap.bits];
bitMap ← [0, fontHeader.raster, fontHeader.raster*16, fontHeader.height,
GriffinMemoryDefs.AllocateSegment [fontHeader.bitmapwords]];
IF StreamDefs.ReadBlock [gHandle, bitMap.bits, fontHeader.bitmapwords] #
fontHeader.bitmapwords THEN SIGNAL FontError;
END;
-- -----------------------------------------------------------------
AddGFont: PROCEDURE [fd: FontDescriptorHandle] =
BEGIN OPEN GriffinMemoryDefs;
[] ← StreamDefs.FileLength [gHandle];
IF gFontHead = NIL THEN gFontHead ← lastFont ← Allocate [lGriffinFont] ELSE
lastFont ← lastFont.next ← Allocate [lGriffinFont];
currentFont ← lastFont;
currentFont.fd.rotation ← fd.rotation;
currentFont.fd.points ← fd.points;
currentFont.fd.face ← fd.face;
currentFont.fd.name ← AllocateString [fd.name.length];
currentFont.next ← NIL;
StringDefs.AppendString [currentFont.fd.name, fd.name];
StreamDefs.GetFA [gHandle, @currentFont.fa];
IF StreamDefs.WriteBlock [gHandle, @fontHeader, lGriffinFontHeader] # lGriffinFontHeader THEN SIGNAL FontError;
IF StreamDefs.WriteBlock [gHandle, bitMap.bits, fontHeader.bitmapwords] # fontHeader.bitmapwords THEN SIGNAL FontError;
StreamDefs.CleanupDiskStream [gHandle]
END;
-- -----------------------------------------------------------------
Rotate90D: PROCEDURE =
BEGIN
goodchars, newjindex, j, x, y, width, begin, end, oldraster: CARDINAL;
oldbitmap: POINTER;
SELECT fontHeader.rotation FROM
Rot0Degrees => fontHeader.rotation ← Rot270Degrees;
Rot180Degrees => fontHeader.rotation ← Rot90Degrees;
ENDCASE => FontError;
oldraster ← fontHeader.raster;
goodchars ← 0;
FOR j IN [0 .. indexSize + 1] DO
IF fontHeader.offset [j+1] # fontHeader.offset [j] THEN goodchars ← goodchars + 1;
ENDLOOP;
fontHeader.raster ← (goodchars*fontHeader.height+15)/16;
fontHeader.bitmapwords ← fontHeader.raster*fontHeader.maxwidth;
oldbitmap ← bitMap.bits;
bitMap ← [0, fontHeader.raster, fontHeader.raster*16, fontHeader.maxwidth,
GriffinMemoryDefs.AllocateSegment [fontHeader.bitmapwords]];
MiscDefs.Zero [bitMap.bits, fontHeader.bitmapwords];
newjindex ← 0;
FOR j IN [0 .. indexSize]
DO
begin ← fontHeader.offset [j];
end ← fontHeader.offset [j + 1];
fontHeader.offset [j] ← newjindex;
width ← end - begin;
IF width = 0 THEN LOOP; -- illegal character
FOR x IN [0 .. width)
DO FOR y IN [0 .. fontHeader.height)
DO
IF IsOneBit [oldbitmap, x+begin, y, oldraster]
THEN SetBit [bitMap.bits, newjindex+fontHeader.height-1-y, x, fontHeader.raster];
ENDLOOP;
ENDLOOP; -- done with this character
newjindex ← newjindex + fontHeader.height; -- end of the current character
ENDLOOP; -- this is the end of the character loop
GriffinMemoryDefs.FreeSegment [oldbitmap];
END;
-- -----------------------------------------------------------------
Rotate180D: PROCEDURE =
BEGIN
j, x, y, width, begin, end: CARDINAL;
newbitmap: POINTER;
SELECT fontHeader.rotation FROM
Rot0Degrees => fontHeader.rotation ← Rot180Degrees;
ENDCASE => FontError;
newbitmap ← GriffinMemoryDefs.AllocateSegment [fontHeader.bitmapwords];
MiscDefs.Zero [newbitmap, fontHeader.bitmapwords];
FOR j IN [0 .. indexSize]
DO
begin ← fontHeader.offset [j];
end ← fontHeader.offset [j + 1];
width ← end - begin;
IF width # 0
THEN FOR x IN [0 .. width)
DO
FOR y IN [0 .. fontHeader.height)
DO
IF IsOneBit [bitMap.bits, x+begin, y, fontHeader.raster]
THEN SetBit [newbitmap, end-1-x, fontHeader.height-1-y, fontHeader.raster];
ENDLOOP;
ENDLOOP; -- done with this character
ENDLOOP; -- this is the end of the character loop
GriffinMemoryDefs.FreeSegment [bitMap.bits];
bitMap.bits ← newbitmap;
END;
oneBits: ARRAY [0 .. 15] OF WORD = [100000B, 40000B, 20000B, 10000B, 4000B, 2000B, 1000B,
400B, 200B, 100B, 40B, 20B, 10B, 4B, 2B, 1B];
-- -----------------------------------------------------------------
SetBit: PROCEDURE [base: POINTER, x, y, raster: CARDINAL] = INLINE
BEGIN
WHILE x > 15 DO base ← base + 1; x ← x - 16; ENDLOOP;
WHILE y > 0 DO base ← base + raster; y ← y - 1; ENDLOOP;
base↑ ← InlineDefs.BITOR [base↑, oneBits [x]];
END;
-- -----------------------------------------------------------------
IsOneBit: PROCEDURE [base: POINTER, x, y, raster: CARDINAL] RETURNS [BOOLEAN] = INLINE
BEGIN
WHILE x > 15 DO base ← base + 1; x ← x - 16; ENDLOOP;
WHILE y > 0 DO base ← base + raster; y ← y - 1; ENDLOOP;
RETURN [InlineDefs.BITAND [base↑, oneBits [x]] # 0];
END;
-- -----------------------------------------------------------------
Bolden, Italicize: PROCEDURE = BEGIN SIGNAL FontError END;
-- -----------------------------------------------------------------
ReadStrike: PUBLIC PROCEDURE [fp: POINTER, s: STRING]
RETURNS [false: BOOLEAN] =
BEGIN
fonthandle: StreamDefs.DiskHandle;
strikeheader: StrikeHeader;
strikebits: POINTER;
rover: GriffinFontHandle ← gFontHead;
fd: FontDescriptor ← [NIL,0,0,0];
j, numoffsets, oldlen, newlen: CARDINAL;
false ← FALSE;
newlen ← GriffinFileDefs.IsTail[s, ".Strike."];
IF newlen = 0 THEN RETURN;
IF s [newlen-1] = 'I OR s[newlen-1] = 'i THEN { fd.face ← fd.face + 1; newlen ← newlen - 1};
IF s [newlen-1] = 'B OR s[newlen-1] = 'b THEN { fd.face ← fd.face + 2; newlen ← newlen - 1};
IF s [newlen -1] IN ['0 .. '9] THEN
{fd.points ← s [newlen-1] - '0; newlen ← newlen - 1};
IF s [newlen -1] IN ['0 .. '9] THEN
{fd.points ← fd.points + 10*(s [newlen-1]-'0); newlen ← newlen - 1};
oldlen ← s.length; -- strip junk off s for scan through prev fonts
s.length ← newlen;
--have we already stored this one?
UNTIL rover = NIL DO IF rover.fd.points = fd.points AND rover.fd.face = fd.face AND
rover.fd.rotation = fd.rotation AND StringDefs.EquivalentString [rover.fd.name, s]
THEN RETURN ELSE rover ← rover.next; ENDLOOP;
--is new to Griffin.fonts
fd.name ← GriffinMemoryDefs.AllocateString [newlen];
StringDefs.AppendString [fd.name, s];
--now check if it is in Fonts.widths and RETURN if not
IF ~ReadHWidths [@fd] THEN {GriffinMemoryDefs.FreeString[fd.name]; RETURN};
--is a good font, put it in
s.length ← oldlen; -- restore s
fonthandle ← StreamDefs.NewWordStream [s, StreamDefs.Read ];
IF StreamDefs.ReadBlock [fonthandle, @strikeheader, lStrikeHeader] # lStrikeHeader
THEN SIGNAL FontError;
fontHeader.height ← strikeheader.ascent + strikeheader.descent;
fontHeader.ascent ← strikeheader.ascent;
fontHeader.raster ← strikeheader.raster;
fontHeader.bitmapwords ← fontHeader.raster*fontHeader.height;
fontHeader.rotation ← fd.rotation;
fontHeader.face ← fd.face;
fontHeader.points ← fd.points;
fontHeader.maxwidth ← strikeheader.maxwidth;
fd.name.length ← MIN [nameSize, fd.name.length];
fontHeader.name [0] ← LOOPHOLE [fd.name.length, CHARACTER];
FOR j IN [0 .. fd.name.length) DO fontHeader.name [j+1] ← fd.name [j]; ENDLOOP;
strikebits ← GriffinMemoryDefs.AllocateSegment [fontHeader.bitmapwords];
IF StreamDefs.ReadBlock [fonthandle, strikebits, fontHeader.bitmapwords] # fontHeader.bitmapwords THEN SIGNAL FontError;
MiscDefs.Zero [@fontHeader.offset, indexSize+2];
MiscDefs.Zero [@fontHeader.displaywidth, indexSize+2];
numoffsets ← strikeheader.maxascii+3 - strikeheader.minascii;
IF StreamDefs.ReadBlock [fonthandle, @fontHeader.offset + strikeheader.minascii, numoffsets]
# numoffsets THEN SIGNAL FontError;
FOR j IN [strikeheader.minascii+numoffsets .. indexSize+2)
DO
fontHeader.offset [j] ← fontHeader.offset [strikeheader.minascii + numoffsets - 1];
ENDLOOP;
FOR j IN [strikeheader.minascii .. MIN[indexSize+1,strikeheader.maxascii+1]]
DO
fontHeader.displaywidth[j] ←
fontHeader.offset[j+1] - fontHeader.offset[j];
ENDLOOP;
fonthandle.destroy [fonthandle];
GriffinMemoryDefs.FreeSegment [bitMap.bits];
bitMap ← [0, fontHeader.raster, fontHeader.raster*16, fontHeader.height, strikebits];
AddGFont [@fd];
END;
-- -----------------------------------------------------------------
ReadHWidths: PROCEDURE [fd: FontDescriptorHandle] RETURNS [BOOLEAN]=
BEGIN OPEN IxDefs;
j: CARDINAL;
ix,best: IX;
size: CARDINAL ← PointsToMicas[fd.points];
family: WORD;
fwHandle.reset [fwHandle];
DO
ReadIX[@ix];
SELECT ix.header.type FROM
IXTypeEnd => RETURN[FALSE];
IXTypeName => FOR j IN [0 .. fd.name.length)
DO OPEN StringDefs;
IF LowerCase[fd.name[j]]
# LowerCase[ix.name [j+1]] THEN EXIT;
REPEAT FINISHED => EXIT; --from the outer loop
ENDLOOP;
ENDCASE;
ENDLOOP;
--now we've found the family, look for the right widths
family ← ix.code;
best.header.type ← IXTypeEnd;
DO
ReadIX[@ix];
SELECT ix.header.type FROM
IXTypeEnd => EXIT;
IXTypeWidths =>
IF ix.fam = family
AND ix.face = fd.face
AND (ix.siz = 0 --splines--
OR (fd.points=MicasToPoints[ix.siz]
AND ix.rotation = fd.rotation))
THEN BEGIN
best ← ix;
IF ix.siz # 0 THEN EXIT;
--may be non-spline later
END;
ENDCASE;
ENDLOOP;
IF best.header.type = IXTypeEnd THEN RETURN[FALSE] ;
CalculateWidths[@best, fd, size];
RETURN[TRUE];
END;
-- -----------------------------------------------------------------
CalculateWidths: PROCEDURE [best: POINTER TO IxDefs.IX,
font: FontDescriptorHandle, size: CARDINAL] =
BEGIN OPEN IxDefs, MiscDefs, AltoDefs, InlineDefs;
sa: LongNumber;
index: StreamDefs.StreamIndex;
wt: WTB;
bufl: CARDINAL = LENGTH[fontHeader.presswidth];
i: CARDINAL;
SetBlock[@fontHeader.presswidth, 0, bufl];
[sa.highbits, sa.lowbits] ← best.sa; --Bcpl to Mesa LONG
[index.page, index.byte] ← LongDivMod[sa.lc*2, BytesPerPage];
StreamDefs.SetIndex[fwHandle, index];
[] ← StreamDefs.ReadBlock[fwHandle, @wt, SIZE[WTB]];
-- now read either one word or many for the widths
IF font.rotation#Rot0Degrees THEN FontError;
IF best.ec>bufl THEN FontError;
IF wt.XWidthFixed
THEN BEGIN
w: CARDINAL ← fwHandle.get[fwHandle];
SetBlock[@fontHeader.presswidth, w, bufl];
END
ELSE [] ← StreamDefs.ReadBlock[fwHandle,
@fontHeader.presswidth[best.bc], best.ec-best.bc+1];
--IF wt.YWidthFixed
-- THEN fontHeader.height ← fwHandle.get[fwHandle]
-- ELSE FontError;
-- now scale, if necessary
IF best.siz = 0 THEN
BEGIN
FOR i IN [best.bc..best.ec]
DO fontHeader.presswidth[i] ← LongDiv[
LongMult[fontHeader.presswidth[i],size], 1000];
ENDLOOP;
-- fontHeader.height ← LongDiv[LongMult[fontHeader.height,
-- size], 1000]
END;
END;
-- -----------------------------------------------------------------
ReadIX: PROCEDURE[ ix: POINTER TO IxDefs.IX] =
BEGIN
ix.header ← fwHandle.get[fwHandle];
IF ix.header.length>0
THEN IF StreamDefs.ReadBlock[fwHandle, ix+1, ix.header.length-1]+1
# ix.header.length THEN FontError;
END;
-- -----------------------------------------------------------------
PointsToMicas: PROCEDURE[points: CARDINAL] RETURNS[CARDINAL] =
BEGIN OPEN InlineDefs;
RETURN [LongDiv[LongMult[points,635],18]]
END;
-- -----------------------------------------------------------------
mtp: REAL ← 18.0/635.0;
MicasToPoints: PROCEDURE[micas: CARDINAL] RETURNS[CARDINAL] =
BEGIN
RETURN [Real.RoundC[mtp*micas]]
END;
-- -----------------------------------------------------------------
EachFile: PROCEDURE [fp: POINTER, s: STRING]
RETURNS [BOOLEAN] =
BEGIN
IF GriffinFileDefs.IsTail[s, ".Strike."] # 0
THEN []←ReadStrike[fp,s];
RETURN[FALSE];
END;
-- -----------------------------------------------------------------
foo, baz: CARDINAL;
IF gHandle.endof [gHandle]
THEN gHandle.put[gHandle, fontPassword]
ELSE IF gHandle.get[gHandle] # fontPassword THEN
BEGIN OPEN StreamDefs;
old: DiskHandle←gHandle;
gHandle←CreateWordStream[old.file, Read+Append];
old.reset[old];
old.put[old, fontPassword];
TruncateDiskStream [old]; --destroys stream
[]←FileLength[gHandle]; --position to end
END;
bitMap.bits ← GriffinMemoryDefs.AllocateSegment [256];
UNTIL gHandle.endof [gHandle] DO
IF gFontHead = NIL THEN
gFontHead←lastFont←GriffinMemoryDefs.Allocate [lGriffinFont]
ELSE lastFont←lastFont.next←GriffinMemoryDefs.Allocate [lGriffinFont];
StreamDefs.GetFA [gHandle, @lastFont.fa];
IF StreamDefs.ReadBlock [gHandle, @fontHeader, lGriffinFontHeader]
#lGriffinFontHeader THEN SIGNAL FontError;
foo ← fontHeader.bitmapwords;
UNTIL foo =0 DO -- skip bitmap
IF StreamDefs.ReadBlock [gHandle, bitMap.bits, MIN [foo, 256]] #
MIN [foo, 256] THEN SIGNAL FontError;
IF foo < 256 THEN foo ← 0 ELSE foo ← foo - 256;
ENDLOOP;
lastFont.fd.rotation ← fontHeader.rotation;
lastFont.fd.points ← fontHeader.points;
lastFont.fd.face ← fontHeader.face;
lastFont.next ← NIL;
foo ← LOOPHOLE [fontHeader.name [0], CARDINAL];
lastFont.fd.name ← GriffinMemoryDefs.AllocateString [foo];
FOR baz IN [ 1 .. foo] DO
lastFont.fd.name [baz-1] ← fontHeader.name [baz]; ENDLOOP;
lastFont.fd.name.length ← foo;
ENDLOOP;
IF gFontHead # NIL THEN ReadGFont [gFontHead];
currentFont ← gFontHead;
DirectoryDefs.EnumerateDirectory [EachFile];
IF gFontHead = NIL THEN StartupFontError[nofonts];
END.