-- XTextFns.mesa
-- Mesa 6 version
-- Last changed by Doug Wyatt, September 23, 1980 3:08 PM

DIRECTORY
XGraphicsDefs: FROM "XGraphicsDefs",
DirectoryDefs: FROM "DirectoryDefs",
InlineDefs: FROM "InlineDefs",
BitBltDefs: FROM "BitBltDefs",
XDisplayDefs: FROM "XDisplayDefs",
AltoFileDefs: FROM "AltoFileDefs",
StringDefs: FROM "StringDefs",
SegmentDefs: FROM "SegmentDefs",
SystemDefs: FROM "SystemDefs";

XTextFns: PROGRAM
IMPORTS InlineDefs,DirectoryDefs,SystemDefs,
XDisplayDefs,XGraphicsDefs,StringDefs,SegmentDefs
EXPORTS XGraphicsDefs =
BEGIN
--stuff for screen font manipulation
fontDescriptor: TYPE = RECORD
[link: POINTER TO fontDescriptor,
fp: AltoFileDefs.FP,
name: STRING,
strikeHandle: POINTER TO XGraphicsDefs.StrikeFont
];
fontListHandle: POINTER TO fontDescriptor ← NIL;
SelfRelative: TYPE = SelfRelativeBase RELATIVE POINTER TO ALChar;
SelfRelativeBase: TYPE = BASE POINTER TO SelfRelative;
ALFontHead: TYPE = RECORD
[height: CARDINAL,
proportional: [0..1],
baseline: [0..177B],
maxWidth: [0..377B],
Pointers: ARRAY [0..377B] OF SelfRelative
];
ALChar: TYPE = RECORD
[XW: CARDINAL,
HD: [0..377B],
XH: [0..377B]
];
ALCharHandle: TYPE = BASE POINTER TO ALChar;
RelativeBitmapPointer: TYPE = ALCharHandle RELATIVE POINTER TO ARRAY OF CARDINAL;
Screen: POINTER TO XGraphicsDefs.Bitmap ← XGraphicsDefs.GetDefaultBitmapHandle[];

XM: BOOLEAN ← SegmentDefs.memConfig.useXM;

PutText: PUBLIC PROCEDURE [s: STRING,x,y: CARDINAL,font: POINTER TO XGraphicsDefs.StrikeFont,mode: XGraphicsDefs.textMode] RETURNS [nextX: CARDINAL] =
BEGIN RETURN[SetTextInBitmap[s,x,y,paint,font,mode,Screen]];END;
ReplaceText: PUBLIC PROCEDURE [s: STRING,x,y: CARDINAL,font: POINTER TO XGraphicsDefs.StrikeFont,mode: XGraphicsDefs.textMode] RETURNS [nextX: CARDINAL] =
BEGIN RETURN[SetTextInBitmap[s,x,y,replace,font,mode,Screen]];END;
EraseText: PUBLIC PROCEDURE [s: STRING,x,y: CARDINAL,font: POINTER TO XGraphicsDefs.StrikeFont,mode: XGraphicsDefs.textMode] RETURNS [nextX: CARDINAL] =
BEGIN RETURN[SetTextInBitmap[s,x,y,erase,font,mode,Screen]];END;
XorText: PUBLIC PROCEDURE [s: STRING,x,y: CARDINAL,font: POINTER TO XGraphicsDefs.StrikeFont,mode: XGraphicsDefs.textMode] RETURNS [nextX: CARDINAL] =
BEGIN RETURN[SetTextInBitmap[s,x,y,invert,font,mode,Screen]];END;

PutTextInBitmap: PUBLIC PROCEDURE [s: STRING,x,y: CARDINAL,font: POINTER TO XGraphicsDefs.StrikeFont,mode: XGraphicsDefs.textMode,b: POINTER TO XGraphicsDefs.Bitmap] RETURNS [nextX: CARDINAL] =
BEGIN RETURN[SetTextInBitmap[s,x,y,paint,font,mode,b]];END;
ReplaceTextInBitmap: PUBLIC PROCEDURE [s: STRING,x,y: CARDINAL,font: POINTER TO XGraphicsDefs.StrikeFont,mode: XGraphicsDefs.textMode,b: POINTER TO XGraphicsDefs.Bitmap] RETURNS [nextX: CARDINAL] =
BEGIN RETURN[SetTextInBitmap[s,x,y,replace,font,mode,b]];END;
EraseTextInBitmap: PUBLIC PROCEDURE [s: STRING,x,y: CARDINAL,font: POINTER TO XGraphicsDefs.StrikeFont,mode: XGraphicsDefs.textMode,b: POINTER TO XGraphicsDefs.Bitmap] RETURNS [nextX: CARDINAL] =
BEGIN RETURN[SetTextInBitmap[s,x,y,erase,font,mode,b]];END;
XorTextInBitmap: PUBLIC PROCEDURE [s: STRING,x,y: CARDINAL,font: POINTER TO XGraphicsDefs.StrikeFont,mode: XGraphicsDefs.textMode,b: POINTER TO XGraphicsDefs.Bitmap] RETURNS [nextX: CARDINAL] =
BEGIN RETURN[SetTextInBitmap[s,x,y,invert,font,mode,b]];END;

BmDest: PROCEDURE[bbt: XDisplayDefs.BBPtr,
bm: POINTER TO XGraphicsDefs.Bitmap] =
BEGIN OPEN XDisplayDefs;
bmd: BitmapDescriptor←[base: LP[bm.bits,bm.bank],
raster: bm.nWords, lines: bm.nLines];
BBDest[bbt,@bmd];
END;

SetTextInBitmap: PUBLIC PROCEDURE [s: STRING,x,y: CARDINAL,fn: BitBltDefs.BBoperation,font: POINTER TO XGraphicsDefs.StrikeFont,mode: XGraphicsDefs.textMode,b: POINTER TO XGraphicsDefs.Bitmap] RETURNS [nextX: CARDINAL] =
BEGIN
i: CARDINAL;
bba: XDisplayDefs.BBArray;
bbt: XDisplayDefs.BBPtr ← XDisplayDefs.BBInit[@bba];
fbmd: XDisplayDefs.BitmapDescriptor←[
base: XDisplayDefs.LP[font.bitmap,font.bank],
raster: font.wordsPerScanLine, lines: font.ascent+font.descent];
width: CARDINAL;

nextX ← x;

BmDest[bbt,b]; XDisplayDefs.BBSource[bbt,@fbmd];
bbt.sourcetype←block;
bbt.operation←LOOPHOLE[fn];
bbt.dw←0; bbt.dh←0; bbt.sty←0;
XDisplayDefs.BitBlt[bbt];

IF INTEGER[y+font.descent] < 0 THEN RETURN[nextX];
y ← y - font.ascent;
--the (x,y) coordinate refers to the baseline
IF INTEGER[y] > INTEGER[b.nLines] THEN RETURN[nextX];

SELECT mode FROM
XGraphicsDefs.normal,XGraphicsDefs.bold =>
BEGIN
bbt.dh ← MIN[font.ascent+font.descent,MAX[0,INTEGER[b.nLines-y]]];
IF INTEGER[y] < 0 THEN
BEGIN
bbt.dh ← bbt.dh + y;
IF INTEGER[bbt.dh] < 0 THEN RETURN[nextX];
bbt.sty ← bbt.sty - y;
y←0;
END;
FOR i IN [0..s.length) DO
IF INTEGER[nextX] >= INTEGER[b.nBits] THEN RETURN[nextX];
bbt.dlx ← nextX;
bbt.dty ← y;
width ← MIN[font.xInSegment[LOOPHOLE[s[i],CARDINAL]+1] -
font.xInSegment[LOOPHOLE[s[i],CARDINAL]],
MAX[0,INTEGER[b.nBits-nextX]]];
bbt.dw ← width;
bbt.slx ← font.xInSegment[LOOPHOLE[s[i],CARDINAL]];
IF INTEGER[nextX] < 0 THEN
BEGIN
bbt.dw ← MAX[0,INTEGER[bbt.dw+nextX]];
bbt.slx ← bbt.slx - nextX;
bbt.dlx ← 0;
END;
XDisplayDefs.BitBlt[bbt];
IF mode = XGraphicsDefs.bold THEN
BEGIN
bbt.dlx ← bbt.dlx+1;
bbt.dw ← MIN[bbt.dw,MAX[0,INTEGER[b.nBits-nextX]]];
XDisplayDefs.BitBlt[bbt];
END;
nextX ← nextX + width;
ENDLOOP;
END; -- case normal
XGraphicsDefs.italic,XGraphicsDefs.bold+XGraphicsDefs.italic =>
BEGIN
yStep: CARDINAL = 4;
numYSteps: CARDINAL = (font.ascent+font.descent+yStep-1)/yStep;
firstStep: CARDINAL ← font.ascent+font.descent - (numYSteps-1)*yStep;
iMin: INTEGER = -((numYSteps-1)/2);
iMax: INTEGER = numYSteps/2;
italicStep: INTEGER;
FOR i IN [0..s.length) DO
IF INTEGER[nextX] >= INTEGER[b.nBits] THEN RETURN[nextX];
bbt.dty ← y;
width ← MIN[font.xInSegment[LOOPHOLE[s[i],CARDINAL]+1] -
font.xInSegment[LOOPHOLE[s[i],CARDINAL]],
MAX[0,INTEGER[b.nBits-nextX]]];
bbt.dw ← width;
bbt.slx ← font.xInSegment[LOOPHOLE[s[i],CARDINAL]];
bbt.sty ← 0;
bbt.dh ← MIN[MAX[0,INTEGER[b.nLines-y]],firstStep];
FOR italicStep DECREASING IN [iMin..iMax] DO
bbt.dlx ← nextX + italicStep;
bbt.dw ← MIN[bbt.dw,MAX[0,INTEGER[b.nBits-bbt.dlx]]];
IF INTEGER[bbt.dlx] < 0 THEN
BEGIN
bbt.dw ← MAX[0,INTEGER[bbt.dw+bbt.dlx]];
bbt.slx ← bbt.slx - bbt.dlx;
bbt.dlx ← 0;
END;
IF INTEGER[bbt.dty + bbt.dh] > 0 THEN
BEGIN
IF INTEGER[bbt.dty] < 0 THEN
BEGIN
bbt.sty ← bbt.sty - bbt.dty;
bbt.dh ← bbt.dh + bbt.dty;
bbt.dty ← 0;
END;
XDisplayDefs.BitBlt[bbt];
IF mode = XGraphicsDefs.bold+XGraphicsDefs.italic THEN
BEGIN
bbt.dlx ← bbt.dlx+1;
bbt.dw ← MIN[bbt.dw,MAX[0,INTEGER[b.nBits-bbt.dlx]]];
XDisplayDefs.BitBlt[bbt];
END;
END;
bbt.sty ← bbt.sty + bbt.dh;
bbt.dty ← bbt.dty + bbt.dh;
bbt.dh ← MIN[MAX[0,INTEGER[b.nLines-bbt.dty]],yStep];
ENDLOOP;
nextX ← nextX + width;
ENDLOOP;
END;--end of italic case
ENDCASE;
END;

GetStrikeHandle: PUBLIC PROCEDURE [fontName: STRING] RETURNS [POINTER TO XGraphicsDefs.StrikeFont] =
BEGIN
fileList: POINTER TO fontDescriptor ← fontListHandle;
UNTIL fileList = NIL DO
IF StringDefs.EquivalentString[fileList.name,fontName] THEN
BEGIN
IF fileList.strikeHandle = NIL THEN fileList↑.strikeHandle ← ALtoStrike[@fileList.fp];
RETURN[fileList.strikeHandle];
END;
fileList ← fileList.link;
ENDLOOP;
RETURN[NIL];
END;
GetFontNameArray: PUBLIC PROCEDURE RETURNS [POINTER TO ARRAY [0..0) OF STRING,CARDINAL] =
BEGIN
i: CARDINAL ← 0;
p: POINTER TO ARRAY [0..0) OF STRING;
fileList: POINTER TO fontDescriptor ← fontListHandle;
UNTIL fileList = NIL DO
i←i+1;
fileList ← fileList.link;
ENDLOOP;
p ← SystemDefs.AllocateHeapNode[i];
i←0;
fileList ← fontListHandle;
UNTIL fileList = NIL DO
p[i] ← fileList.name;
i←i+1;
fileList ← fileList.link;
ENDLOOP;
RETURN[p,i];
END;

ReadALFonts: PROCEDURE RETURNS [fontDescriptorHandle: POINTER TO fontDescriptor] =
BEGIN
name: STRING ← [100];
ext: STRING ← [100];
newString: STRING;
firstLinkPointer: POINTER TO fontDescriptor ← NIL;
linkPointer: POINTER TO UNSPECIFIED ← @firstLinkPointer;
i: CARDINAL;
mem: POINTER TO fontDescriptor;
AddALFont: PROCEDURE[fp: POINTER TO AltoFileDefs.FP, filenm: STRING]
RETURNS[BOOLEAN] =
BEGIN
name.length←ext.length←0;
FOR i IN [0..filenm.length)
DO
IF filenm[i] = ’. THEN EXIT;
IF filenm[i] = ’! THEN EXIT;--strip version
StringDefs.AppendChar[name,filenm[i]];
ENDLOOP;
IF filenm[i]=’. THEN--grab
FOR i IN [name.length+1..filenm.length)
DO
IF filenm[i] = ’. THEN EXIT;
IF filenm[i] = ’! THEN EXIT;--strip version
StringDefs.AppendChar[ext,filenm[i]];
ENDLOOP;
IF NOT StringDefs.EquivalentString["AL",ext] THEN RETURN[FALSE]; --not me
mem ← SystemDefs.AllocateHeapNode[SIZE[fontDescriptor]];
newString ← SystemDefs.AllocateHeapString[name.length];
mem↑.link←NIL;
mem↑.fp ← fp↑;
mem↑.name ← newString;
mem↑.strikeHandle ← NIL;
newString.length ← 0;
StringDefs.AppendString[newString,name];
linkPointer↑ ← mem;
linkPointer ← mem;
RETURN[FALSE];
END;
DirectoryDefs.EnumerateDirectory[AddALFont];
RETURN[firstLinkPointer];
END;

ALtoStrike: PUBLIC PROCEDURE [fp: POINTER TO AltoFileDefs.FP] RETURNS [POINTER TO XGraphicsDefs.StrikeFont] =
BEGIN
i: CARDINAL;
strikeWidth: CARDINAL ← 0;
currentWidth: CARDINAL;
strikeWidthMax: CARDINAL ← 0;
ALFileHandle: SegmentDefs.FileHandle ← SegmentDefs.InsertFile[fp,SegmentDefs.Read];
ALSegment: SegmentDefs.FileSegmentHandle ←
SegmentDefs.NewFileSegment[ALFileHandle,SegmentDefs.DefaultBase,
SegmentDefs.DefaultPages,SegmentDefs.Read];
--array big enough for 18 point fonts
ALData: POINTER TO ALFontHead;
XHData: ALCharHandle;
sf: POINTER TO XGraphicsDefs.StrikeFont;
bmd: XDisplayDefs.BitmapDescriptor;
srbase: SelfRelativeBase;
strikeIndexLen: CARDINAL = 256;
xIndex: POINTER TO ARRAY [0..strikeIndexLen) OF CARDINAL ←
SystemDefs.AllocateHeapNode[strikeIndexLen];
bba: XDisplayDefs.BBArray;
bbt: XDisplayDefs.BBPtr ← XDisplayDefs.BBInit[@bba];

SegmentDefs.SwapIn[ALSegment];
ALData ← SegmentDefs.FileSegmentAddress[ALSegment];

--calculate width of strike raster
FOR i IN [0..377B] DO
xIndex[i] ← strikeWidth;
srbase ← @ALData.Pointers[i];
XHData ← @srbase[srbase↑];
currentWidth←0;
UNTIL InlineDefs.BITAND[XHData.XW,1] = 1 DO--Read extension characters
currentWidth ← currentWidth+16;
srbase ← @ALData.Pointers[XHData.XW/2];
XHData ← @srbase[srbase↑];
ENDLOOP;
currentWidth ← currentWidth + XHData.XW/2;
strikeWidth ← strikeWidth + currentWidth;
IF currentWidth > strikeWidthMax THEN strikeWidthMax ← currentWidth;
ENDLOOP;
xIndex[377B] ← strikeWidth;

sf ← SystemDefs.AllocateHeapNode[SIZE[XGraphicsDefs.StrikeFont]];
XDisplayDefs.BMSize[@bmd,strikeWidth,ALData↑.height];
XDisplayDefs.AllocBitmap[@bmd];
sf↑ ← [oneBit: 1, bank: XDisplayDefs.LPBank[bmd.base],
index: 0,fixed: 1-ALData↑.proportional,
minCode: 0,maxCode: strikeIndexLen-1,maxWidth: strikeWidthMax,
strikeBodyWordLength: ((strikeWidth+15)/16)*ALData↑.height,
ascent: ALData↑.baseline,descent: ALData↑.height - ALData↑.baseline,
wordsPerScanLine: bmd.raster, bitmap: XDisplayDefs.LPPtr[bmd.base],
xInSegment: LOOPHOLE[xIndex]];

XDisplayDefs.BBDest[bbt,@bmd];
bbt.dw←strikeWidth; bbt.dh←sf.ascent+sf.descent;
XDisplayDefs.BitBlt[bbt]; -- clear the bitmap
bbt.sourcetype←block;

--now, slam in all the characters
FOR i IN [0..377B] DO
BEGIN
offset: RelativeBitmapPointer;
cbmd: XDisplayDefs.BitmapDescriptor←[base: , raster: 1, lines: ];
srbase ← @ALData.Pointers[i];
XHData ← @srbase[srbase↑];
bbt.dlx ← xIndex[i];
bbt.dty ← XHData.HD;
cbmd.lines ← bbt.dh ← XHData.XH;
offset ← LOOPHOLE[-XHData.XH];
cbmd.base ← @XHData[offset];
XDisplayDefs.BBSource[bbt,@cbmd];
UNTIL InlineDefs.BITAND[XHData.XW,1] = 1 DO
bbt.dw ← 16;
XDisplayDefs.BitBlt[bbt];
srbase ← @ALData.Pointers[XHData.XW/2];
XHData ← @srbase[srbase↑];
bbt.dlx ← bbt.dlx + 16;
bbt.dty ← XHData.HD;
cbmd.lines ← bbt.dh ← XHData.XH;
offset ← LOOPHOLE[-XHData.XH];
cbmd.base ← @XHData[offset];
XDisplayDefs.BBSource[bbt,@cbmd];
ENDLOOP;
bbt.dw ← XHData.XW/2;
XDisplayDefs.BitBlt[bbt];

END;
ENDLOOP;

SegmentDefs.Unlock[ALSegment];
SegmentDefs.DeleteFileSegment[ALSegment];

RETURN[sf];
END;

TurnOnText: PUBLIC PROCEDURE =
BEGIN
fontListHandle ← ReadALFonts[];
END;

END.