-- TEditFontImpl.mesa; Last Edited by McGregor, January 29, 1982 10:19 am
DIRECTORY
Directory USING [Error, Lookup],
File USING [Capability, GetSize, PageCount],
Inline USING [LowHalf],
LongString USING [AppendDecimal, AppendString],
NodeStyle USING [Dist],
Real USING [RoundC],
Runtime USING [CallDebugger],
Space USING [Create, Handle, LongPointer, Map, PageCount, virtualMemory],
TEditFont,
NameSymbolTable USING [FromName, Name];
TEditFontImpl: PROGRAM
IMPORTS Directory, File, Inline, LongString, NameSymbolTable, Real, Runtime,
TEditFont, Space
EXPORTS TEditFont = BEGIN OPEN TEditFont;
-- declarations for strike format font files
defaultFont: PUBLIC TEditFont.Font ← NIL;
Error: PUBLIC ERROR [code: TEditFont.ErrorCode] = CODE;
Strike: TYPE = LONG POINTER TO StrikeObject;
StrikeObject: TYPE = RECORD [header: StrikeHeader, body: StrikeBody];
StrikeHeader: TYPE = RECORD [
bits: StrikeBits,
min: CARDINAL,
max: CARDINAL,
maxwidth: CARDINAL];
StrikeBits: TYPE = RECORD [
newStyle: BOOLEAN,
indexed: BOOLEAN,
fixed: BOOLEAN,
kerned: BOOLEAN,
pad: [0..7777B]];
BoundingBox: TYPE = RECORD [
FontBBox, FontBBoy, FontBBdx, FontBBDy: INTEGER];
StrikeBody: TYPE = RECORD [
length: CARDINAL,
ascent: CARDINAL,
descent: CARDINAL,
xoffset: CARDINAL,
raster: CARDINAL,
bitmap: ARRAY [0..0) OF WORD];
-- Procedures
StringWidth: PUBLIC PROCEDURE [string: STRING, font: TEditFont.Font ← defaultFont]
RETURNS [width: [0..LAST[INTEGER]]] = BEGIN
i: CARDINAL;
width ← 0;
FOR i IN [0..string.length) DO
width ← width + TEditFont.CharWidth[string[i], font]
ENDLOOP;
END;
Initialize: PROCEDURE [font: TEditFont.Font] =
BEGIN
strike: Strike = font.address;
c: CHARACTER;
bits: StrikeBits = strike.header.bits;
IF ~bits.newStyle THEN ERROR Error[illegalFormat];
IF bits.indexed THEN ERROR Error[illegalFormat];
font.kerned ← bits.kerned;
font.min ← LOOPHOLE[strike.header.min];
font.max ← LOOPHOLE[strike.header.max];
IF font.min ~IN [0C..177C] THEN ERROR Error[illegalFormat];
IF font.max ~IN [0C..177C] THEN ERROR Error[illegalFormat];
font.height ← strike.body.ascent + strike.body.descent;
font.raster ← strike.body.raster;
font.maxWidth ← strike.header.maxwidth;
SetFontAddresses[font];
font.width[40C] ← 0;
FOR c IN [font.min..MIN[font.max, 176C]] DO
font.width[c] ← XInSegment[c+1, font] - XInSegment[c, font]
ENDLOOP;
FOR c IN [0C..font.min) DO font.width[c] ← font.width[40C] ENDLOOP;
FOR c IN (MIN[font.max, 176C]..177C] DO font.width[c] ← font.width[40C] ENDLOOP;
font.width[15C] ← font.width[40C]; -- CR width hack
END;
SetFontAddresses: PROCEDURE [font: Font] = INLINE
BEGIN
strike: Strike = font.address;
font.bitmap ← @strike.body.bitmap + (IF font.kerned THEN SIZE[BoundingBox] ELSE 0);
font.xInSegment ←
LOOPHOLE[font.bitmap, LONG POINTER ] + font.raster*font.height -
LOOPHOLE[font.min, INTEGER];
END;
fontChain: Font ← NIL;
EstablishFont: PUBLIC PROCEDURE [family: NameSymbolTable.Name, size: NodeStyle.Dist]
RETURNS [Font] = BEGIN
myString: REF TEXT;
myFontHandle: Font;
FOR myFontHandle ← fontChain, myFontHandle.next UNTIL myFontHandle=NIL DO
IF family=myFontHandle.family AND size=myFontHandle.size THEN
RETURN [myFontHandle];
ENDLOOP;
myString ← NEW[TEXT[40]];
NameSymbolTable.FromName[family, myString];
IF size#0.0 THEN LongString.AppendDecimal[LOOPHOLE[myString], Real.RoundC[size]];
LongString.AppendString [LOOPHOLE[myString], ".strike"];
myFontHandle ← LoadFont[LOOPHOLE[myString]];
myFontHandle.family ← family;
myFontHandle.size ← size;
RETURN [myFontHandle];
END;
LoadFont: PROCEDURE [name: LONG STRING] RETURNS [myFontHandle: Font] = BEGIN
ENABLE Directory.Error => GOTO Punt;
file: File.Capability ← Directory.Lookup[fileName: name];
pages: File.PageCount ← File.GetSize[file];
size: Space.PageCount ← IF pages<20 THEN Inline.LowHalf[pages] ELSE ERROR;
space: Space.Handle ← Space.Create[size: size, parent: Space.virtualMemory];
Space.Map[space: space, window: [file: file, base: 1]]; -- first page is 1!
myFontHandle ← NEW[FontObject];
myFontHandle.address ← Space.LongPointer[space];
Initialize [myFontHandle];
myFontHandle.next ← fontChain;
fontChain ← myFontHandle;
EXITS Punt => RETURN[defaultFont]
END;
SetDefaultFont: PROCEDURE [font: TEditFont.Font] = INLINE {defaultFont ← font};
SetDefaultFont [LoadFont["TiogaDefault.strike"L] ];
IF defaultFont=NIL THEN -- not on the disk
DO Runtime.CallDebugger["Tioga needs 'TiogaDefault.strike' to start up!"L] ENDLOOP;
END.