--Maureen Stone April 16, 1984 4:00:46 pm PST
DIRECTORY
StyleDefs,
GriffinFontDefs,
ScreenDefs USING [DrawChar, EraseBox],
Graphics USING [Context],
PointDefs USING [ScrPt,ObjPt, ObjToScr, ObjValToScrVal, X, Y],
Rope USING [ROPE,Equal,Map,ActionType, Cat],
Font,
ImagerTransform,
GriffinDefs USING [AppendNumber, UserMessage],
ControllerMenuDefs USING [AddFontName];
GriffinFont: PROGRAM
IMPORTS Rope, ScreenDefs, Font, ImagerTransform, ControllerMenuDefs, GriffinDefs, PointDefs
EXPORTS GriffinFontDefs =
BEGIN OPEN GriffinFontDefs;
X: CARDINAL = PointDefs.X;
Y: CARDINAL = PointDefs.Y;
fontVersion: CARDINAL = 7;
fontPassword: CARDINAL = 143000B + fontVersion;
GriffinFontHandle: TYPE = REF GriffinFont;
GriffinFont: TYPE = RECORD
[
next: GriffinFontHandle,
fd: FontDescriptorHandle,
maxHeight,maxPosExtent,maxWidth: REAL,  --metrics in object coordinates
font: Font.FONT
];
FontError: PUBLIC SIGNAL = CODE;
StartupFontError: PUBLIC SIGNAL[type: ErrorType] = CODE;
gFontHead, currentFont, lastFont: GriffinFontHandle ← NIL;
DisplayString: PUBLIC PROCEDURE [string: Rope.ROPE, anchorPt: PointDefs.ObjPt, anchor: StyleDefs.Anchor, orientation: StyleDefs.Orientation, fd: FontDescriptorHandle, dc: Graphics.Context] =
BEGIN
DeduceRotation: PROC [t: ImagerTransform.Transformation] RETURNS [rot: REAL ← 0.0] = {
trec: ImagerTransform.TransformationRec ← ImagerTransform.Contents[t];
};
rotation: CARDINAL=fd.rotation;
height, width: REAL;
tl,br: PointDefs.ScrPt;
org: PointDefs.ObjPt;
maxWidth, maxHeight, baseline: REAL;
sr,fr: REAL;
doProc: Rope.ActionType;
dn,dv: RECORD [x,y: REAL];
EasyString: Rope.ActionType = TRUSTED {
ScreenDefs.DrawChar[currentFont.font,PointDefs.ObjToScr[org],c, dc];
org[X] ← org[X]+dv.x*FormatWidth[c];
org[Y] ← org[Y]+dv.y*FormatWidth[c];
};
BackwardString: Rope.ActionType = TRUSTED {
org[X] ← org[X]+dv.x*FormatWidth[c];
org[Y] ← org[Y]+dv.y*FormatWidth[c];
ScreenDefs.DrawChar[currentFont.font,PointDefs.ObjToScr[org],c, dc];
};
Stack: Rope.ActionType = TRUSTED {
showPt: PointDefs.ObjPt;
showPt[X] ← org[X]+dn.x*(maxWidth+FormatWidth[c])/2; --center it
showPt[Y] ← org[Y]+dn.y*(maxWidth+FormatWidth[c])/2;
ScreenDefs.DrawChar[currentFont.font,PointDefs.ObjToScr[showPt],c, dc];
org[X] ← org[X]+dv.x*maxHeight;
org[Y] ← org[Y]+dv.y*maxHeight;
};
BackwardStack: Rope.ActionType = TRUSTED {
showPt: PointDefs.ObjPt;
showPt[X] ← org[X]+dn.x*(maxWidth-FormatWidth[c])/2; --center it
showPt[Y] ← org[Y]+dn.y*(maxWidth-FormatWidth[c])/2;
ScreenDefs.DrawChar[currentFont.font,PointDefs.ObjToScr[showPt],c, dc];
org[X] ← org[X]+dv.x*maxHeight;
org[Y] ← org[Y]+dv.y*maxHeight;
};
SetUpFont [fd];
height ← StringHeight[string, fd, orientation];
width ← StringWidth[string, fd, orientation];
org ← TopLeft[anchorPt, height,width, anchor, orientation, rotation];
tl ← PointDefs.ObjToScr[org];
br ← [tl[X]+PointDefs.ObjValToScrVal[width], tl[Y]+PointDefs.ObjValToScrVal[height]];
ScreenDefs.EraseBox [tl, br, dc];
SELECT orientation FROM
or0 => {dv ← [1,0]; sr ← 0};
or90 => {dv ← [0,1]; org[Y] ← org[Y] - height; sr ← 90};
or180 => {dv ← [-1,0]; org[Y] ← org[Y] - height; org[X] ← org[X] + width; sr ← 180};
or270 => {dv ← [0,-1]; org[X] ← org[X] + width; sr ← 270};
ENDCASE => ERROR;
dn ← [dv.y, -1*dv.x];
fr ← rotation/60.0;
maxWidth ← currentFont.maxWidth;
maxHeight ← currentFont.maxHeight;
baseline ← currentFont.maxPosExtent;
IF fr<sr THEN fr ← fr+360;
SELECT fr-sr FROM
0 => {
org[X] ← org[X]+dn.x*baseline;
org[Y] ← org[Y]+dn.y*baseline;
doProc ← EasyString;
};
90 => {
org[X] ← org[X]+dv.x*baseline;
org[Y] ← org[Y]+dv.y*baseline;
doProc ← Stack;
};
180 => {
org[X] ← org[X]+dn.x*(maxHeight-baseline);
org[Y] ← org[Y]+dn.y*(maxHeight-baseline);
doProc ← BackwardString;
};
270=> {
org[X] ← org[X]+dv.x*(maxHeight-baseline);
org[Y] ← org[Y]+dv.y*(maxHeight-baseline);
doProc ← BackwardStack;
};
ENDCASE => ERROR;
[] ← Rope.Map[action: doProc, base: string];
END;
TopLeft: PUBLIC PROCEDURE [anchorPt: PointDefs.ObjPt,
height, width: REAL, --same coordinates as anchorPt
anchor: StyleDefs.Anchor,
orientation: StyleDefs.Orientation,
rotation: CARDINAL]
RETURNS [tl: PointDefs.ObjPt]=
BEGIN
vertical, aligned, reverse: BOOLEAN;
shift, amount: REAL;
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
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.ObjPt,
fd: FontDescriptorHandle]=
BEGIN
SetUpFont [fd];
tl[Y] ← tl[Y]+currentFont.maxPosExtent;
ScreenDefs.DrawChar[currentFont.font,PointDefs.ObjToScr[tl],char, NIL];
END;
Width: PUBLIC PROCEDURE [c: CHARACTER, fd: FontDescriptorHandle]
RETURNS [REAL] =
BEGIN
SetUpFont [fd];
RETURN [FPWidth[c]];
END;
StringWidth: PUBLIC PROCEDURE [string: Rope.ROPE, fd: FontDescriptorHandle, orientation: StyleDefs.Orientation]
RETURNS [w: REAL] =
BEGIN
DoChar: Rope.ActionType = TRUSTED{ w←w + FPWidth[c]; RETURN[FALSE]};
SetUpFont [fd];
SELECT orientation FROM
or0, or180 =>
BEGIN
IF string=NIL THEN RETURN [0];
w ← 0;
[] ← Rope.Map[base: string, action: DoChar];
END;
or90, or270 => w ← MaxHeight[fd];
ENDCASE;
END;
MaxWidth: PUBLIC PROCEDURE [fd: FontDescriptorHandle]
RETURNS [REAL] =
BEGIN
SetUpFont [fd];
RETURN [SELECT currentFont.fd.rotation FROM
Rot0Degrees, Rot180Degrees => currentFont.maxWidth,
ENDCASE => currentFont.maxHeight];
END;
Height: PUBLIC PROCEDURE [c: CHARACTER, fd: FontDescriptorHandle] RETURNS [REAL] =
BEGIN
SetUpFont [fd];
RETURN [FPHeight[c]];
END;
StringHeight: PUBLIC PROCEDURE[string: Rope.ROPE,
fd:FontDescriptorHandle,
orientation: StyleDefs.Orientation]
RETURNS [h: REAL] =
BEGIN
DoChar: Rope.ActionType = TRUSTED {h ← h + FPHeight[c]; RETURN[FALSE]};
SetUpFont [fd];
SELECT orientation FROM
or0, or180 => h ← MaxHeight[fd];
or90, or270 =>
BEGIN
IF string=NIL THEN RETURN [0];
h ← 0;
[] ← Rope.Map[base: string, action: DoChar];
END;
ENDCASE;
END;
MaxHeight: PUBLIC PROCEDURE [fd: FontDescriptorHandle]
RETURNS [REAL] =
BEGIN
SetUpFont [fd];
RETURN [SELECT currentFont.fd.rotation FROM
Rot0Degrees, Rot180Degrees => currentFont.maxHeight,
ENDCASE => currentFont.maxWidth];
END;
FPWidth: PROCEDURE [char: CHARACTER] RETURNS [REAL] = INLINE
BEGIN -- returns actual x dimension of char
rot: CARDINAL = currentFont.fd.rotation;
RETURN [IF rot = Rot0Degrees OR rot = Rot180Degrees
THEN PointsToMicas[Font.Width[currentFont.font, char]]
ELSE currentFont.maxHeight
];
END;
FormatWidth: PROCEDURE [char: CHARACTER] RETURNS [REAL] =
BEGIN
RETURN [PointsToMicas[Font.Width[currentFont.font, char]]];
END;
FPHeight: PROCEDURE [char: CHARACTER] RETURNS [REAL] = INLINE
BEGIN -- returns actual y dimension of char for the display
rot: CARDINAL = currentFont.fd.rotation;
RETURN [IF rot = Rot0Degrees OR rot = Rot180Degrees
THEN currentFont.maxHeight
ELSE PointsToMicas[Font.Width[currentFont.font, char]]
];
END;
MaxPosExtent: PUBLIC PROCEDURE [fd: FontDescriptorHandle]
RETURNS [REAL] =
BEGIN
SetUpFont [fd];
RETURN [currentFont.maxPosExtent];
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
rover: GriffinFontHandle;
sameface, samerotation: BOOLEAN;
foundFont: BOOLEANFALSE;
IF currentFont=NIL THEN {AddGFont[fd]; RETURN};
IF currentFont.fd.rotation = fd.rotation AND currentFont.fd.points = fd.points AND
currentFont.fd.face= fd.face AND
Rope.Equal[currentFont.fd.name, fd.name, FALSE] THEN RETURN;
rover ← gFontHead;
WHILE rover # NIL DO
IF NOT (Rope.Equal[rover.fd.name, fd.name, FALSE]
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;
IF sameface AND samerotation THEN BEGIN
currentFont ← rover;
foundFont ← TRUE;
EXIT
END;
rover ← rover.next;
ENDLOOP;
IF ~foundFont THEN AddGFont[fd];
END;
AddGFont: PROCEDURE [fd: FontDescriptorHandle] =
BEGIN
font: Font.FONT;
name: Rope.ROPE ← GriffinDefs.AppendNumber[fd.name,fd.points]; --name in default.fontDir
maxHeight,maxPosExtent, maxWidth: REAL ← 0;
angle: REAL ← (SELECT fd.rotation FROM Rot0Degrees => 0,
Rot90Degrees => 90, Rot180Degrees => 180, Rot270Degrees => 270, ENDCASE => 0);
IF fd.face#Regular THEN name ← Rope.Cat[name,SELECT fd.face FROM Italic => "I", Bold => "B", BoldItalic => "BI", ENDCASE =>""];
font ← Font.Create[fontName: name, transformation: ImagerTransform.PreScale[s: fd.points, m: ImagerTransform.Rotate[degrees: angle]], deviceType: $Ideal];
IF font=NIL THEN SIGNAL GriffinDefs.UserMessage[Rope.Cat[name, " not found"]];
IF gFontHead = NIL THEN gFontHead ← lastFont ← NEW[GriffinFont] ELSE
lastFont ← lastFont.next ← NEW[GriffinFont];
currentFont ← lastFont;
currentFont.fd ← fd;
currentFont.font ← font;
currentFont.next ← NIL;
FOR char: CHAR IN [font.bc..font.ec] DO
box: Font.Box ← Font.BoundingBox[font,char];
boxHeight: REALABS[box.ymax] + ABS[box.ymin];
boxWidth: REALABS[box.xmax] + ABS[box.xmin];
IF box.ymax > maxPosExtent THEN maxPosExtent ← box.ymax;
IF boxHeight > maxHeight THEN maxHeight ← boxHeight;
IF boxWidth>maxWidth THEN maxWidth ← boxWidth;
ENDLOOP;
currentFont.maxPosExtent ← PointsToMicas[maxPosExtent];
currentFont.maxHeight ← PointsToMicas[maxHeight];
currentFont.maxWidth ← PointsToMicas[maxWidth];
ControllerMenuDefs.AddFontName[fd,TRUE];
END;
PointsToMicas: PROC [points: REAL] RETURNS [micas: REAL] = {
RETURN[(points*2540)/72.0];
};
END.