ImagerSDFontImpl.mesa
Copyright © 1984, Xerox Corporation. All rights reserved.
Doug Wyatt, November 14, 1984 6:18:43 pm PST
DIRECTORY
Basics USING [bytesPerWord],
CountedVM USING [Allocate, Handle, Pointer],
ImagerFont USING [Alias, Char, Class, ClassRep, CorrectionType, Extents, Font, FontRep, nullChar, OptionalReal, Register],
FS,
Imager USING [ConcatT, Context, DoSave, MaskFillParity],
ImagerPath USING [PathProc],
ImagerTransformation USING [Concat, Rectangle, Scale, Transformation, TransformRectangle, TransformVec],
IO USING [Close, SetIndex, STREAM, UnsafeGetBlock],
PrePressFontFormat USING [BCPLREAL, CardFromDouble, DirectoryArray, IXHeader, missingFilePos, missingSpline, NameIndexEntry, SplineCode, SplineCommand, SplineCoords, SplineData, SplineDataArray, StdIndexEntry],
RealConvert USING [BcplToIeee],
RefText,
Rope,
Vector2 USING [Add, Div, VEC];
ImagerSDFontImpl: CEDAR PROGRAM
IMPORTS CountedVM, ImagerFont, FS, Imager, ImagerTransformation, IO, PrePressFontFormat, RealConvert, RefText, Rope, Vector2
~ BEGIN
BYTE: TYPE ~ [0..377B];
ROPE: TYPE ~ Rope.ROPE;
VEC: TYPE ~ Vector2.VEC;
Transformation: TYPE ~ ImagerTransformation.Transformation;
Font: TYPE ~ ImagerFont.Font;
FontRep: TYPE ~ ImagerFont.FontRep;
name: ROPE,
transformation: Transformation,
class: Class,
data: REF,
propList: REF
Char: TYPE ~ ImagerFont.Char; -- CARDINAL
nullChar: Char ~ ImagerFont.nullChar;
CorrectionType: TYPE ~ ImagerFont.CorrectionType; -- {none, space, mask};
Extents: TYPE ~ ImagerFont.Extents; -- RECORD[leftExtent, rightExtent, descent, ascent: REAL];
OptionalReal: TYPE ~ ImagerFont.OptionalReal; -- RECORD[exists: BOOLEAN, value: REAL];
Data: TYPE ~ REF DataRep;
DataRep: TYPE ~ RECORD[
file: SDFile
];
SDFile: TYPE ~ REF SDFileRep;
SDFileRep: TYPE ~ RECORD[
bc, ec: BYTE,
splineData: LONG POINTER TO PrePressFontFormat.SplineDataArray,
directory: LONG POINTER TO PrePressFontFormat.DirectoryArray,
vm: CountedVM.Handle
];
MalformedSDFont: ERROR ~ CODE;
RealFromBcpl: PROC[x: PrePressFontFormat.BCPLREAL] RETURNS[REAL] ~ INLINE {
RETURN[RealConvert.BcplToIeee[LOOPHOLE[x]]];
};
ReadWords: UNSAFE PROC[stream: IO.STREAM, base: LONG POINTER, words: INT] ~ UNCHECKED {
count: INT ~ words*Basics.bytesPerWord;
IF IO.UnsafeGetBlock[stream, [base: base, count: count]]=count THEN NULL
ELSE ERROR MalformedSDFont; -- file too short
};
SetWordIndex: PROC[stream: IO.STREAM, wordIndex: INT] ~ {
index: CARDINAL ~ wordIndex*Basics.bytesPerWord;
IO.SetIndex[stream, index];
};
Open: PROC[fileName: ROPE] RETURNS[SDFile] ~ {
stream: IO.STREAM ~ FS.StreamOpen[fileName];
ix: PrePressFontFormat.IXHeader;
ixSize: NAT ~ SIZE[PrePressFontFormat.IXHeader];
name: PrePressFontFormat.NameIndexEntry;
index: PrePressFontFormat.StdIndexEntry;
nameFound, indexFound: BOOLFALSE;
family: ROPENIL;
segmentIndex, segmentWords: INT ← 0;
vm: CountedVM.Handle ← NIL;
splineData, directory: LONG POINTERNIL;
DO -- read the index part
TRUSTED { ReadWords[stream, @ix, SIZE[PrePressFontFormat.IXHeader]] };
SELECT ix.type FROM
end => EXIT;
name => {
IF nameFound THEN ERROR MalformedSDFont; -- more than one name entry
IF (ix.length-ixSize)=SIZE[PrePressFontFormat.NameIndexEntry] THEN TRUSTED {
ReadWords[stream, @name, SIZE[PrePressFontFormat.NameIndexEntry]] }
ELSE ERROR MalformedSDFont; -- wrong ix.length
{ -- convert name to rope
i: NAT ← 0; p: PROC RETURNS[CHAR] ~ { RETURN[VAL[name.chars[i ← i+1]]] };
family ← Rope.FromProc[len: name.chars[0], p: p];
};
nameFound ← TRUE;
};
spline => {
IF indexFound THEN ERROR MalformedSDFont; -- more than one char index entry
IF (ix.length-ixSize)=SIZE[PrePressFontFormat.StdIndexEntry] THEN TRUSTED {
ReadWords[stream, @index, SIZE[PrePressFontFormat.StdIndexEntry]] }
ELSE ERROR MalformedSDFont; -- wrong ix.length
indexFound ← TRUE;
};
ENDCASE => ERROR MalformedSDFont; -- unexpected ix type
ENDLOOP;
IF nameFound AND indexFound AND name.code=index.family THEN NULL
ELSE ERROR MalformedSDFont; -- index part has wrong form
IF index.bc>index.ec THEN ERROR MalformedSDFont; -- bc exceeds ec
segmentIndex ← PrePressFontFormat.CardFromDouble[index.segmentSA]; -- in words!
segmentWords ← PrePressFontFormat.CardFromDouble[index.segmentLength];
vm ← CountedVM.Allocate[words: segmentWords];
SetWordIndex[stream, segmentIndex];
TRUSTED { -- read segment
base: LONG POINTER ~ CountedVM.Pointer[vm];
ReadWords[stream, base, segmentWords];
splineData ← base;
directory ← splineData+SIZE[PrePressFontFormat.SplineDataArray[index.ec-index.bc+1]];
};
IO.Close[stream];
RETURN[NEW[SDFileRep ← [bc: index.bc, ec: index.ec,
splineData: splineData, directory: directory, vm: vm]]];
};
SDCreate: PROC[name: ROPE] RETURNS[Font] ~ {
file: SDFile ~ Open[name];
charToClient: Transformation ~ ImagerTransformation.Scale[1];
data: Data ~ NEW[DataRep ← [file: file]];
RETURN[NEW[ImagerFont.FontRep ← [class: class, data: data,
name: name, charToClient: charToClient, props: NIL]]];
};
Modify: PROC[font: Font, m: Transformation] RETURNS[Font] ~ {
data: Data ~ NARROW[font.data];
file: SDFile ~ data.file;
charToClient: Transformation ~ font.charToClient.Concat[m];
newData: Data ~ NEW[DataRep ← [file: file]];
RETURN[NEW[FontRep ← [class: class, data: newData,
name: font.name, charToClient: charToClient, props: NIL]]];
};
Contains: PROC[font: Font, char: Char] RETURNS[BOOL] ~ {
data: Data ~ NARROW[font.data];
file: SDFile ~ data.file;
IF char IN[file.bc..file.ec] THEN {
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← file.splineData[char-file.bc] };
RETURN[sd.wx#PrePressFontFormat.missingSpline];
};
RETURN[FALSE];
};
NextChar: PROC[font: Font, char: Char] RETURNS[next: Char] ~ {
data: Data ~ NARROW[font.data];
file: SDFile ~ data.file;
start: Char;
SELECT char FROM
=nullChar => start ← file.bc;
<file.bc => start ← file.bc;
<file.ec => start ← char+1;
ENDCASE => RETURN[nullChar];
FOR probe: Char IN[start..file.ec] DO
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← file.splineData[probe-file.bc] };
IF sd.wx#PrePressFontFormat.missingSpline THEN RETURN[probe];
ENDLOOP;
RETURN[nullChar];
};
BoundingBox: PROC[font: Font, char: Char] RETURNS[Extents] ~ {
data: Data ~ NARROW[font.data];
file: SDFile ~ data.file;
IF char IN[file.bc..file.ec] THEN {
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← file.splineData[char-file.bc] };
IF sd.wx#PrePressFontFormat.missingSpline THEN {
xmin: REAL ~ RealFromBcpl[sd.xmin];
ymin: REAL ~ RealFromBcpl[sd.ymin];
xmax: REAL ~ RealFromBcpl[sd.xmax];
ymax: REAL ~ RealFromBcpl[sd.ymax];
r: ImagerTransformation.Rectangle ~ ImagerTransformation.TransformRectangle[
font.charToClient, [x: xmin, y: ymin, w: xmax-xmin, h: ymax-ymin]];
RETURN[[leftExtent: -r.x, rightExtent: r.x+r.w, descent: -r.y, ascent: r.y+r.h]];
};
};
RETURN[[0, 0, 0, 0]];
};
Width: PROC[font: Font, char: Char] RETURNS[VEC] ~ {
data: Data ~ NARROW[font.data];
file: SDFile ~ data.file;
IF char IN[file.bc..file.ec] THEN {
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← file.splineData[char-file.bc] };
IF sd.wx#PrePressFontFormat.missingSpline THEN {
wx: REAL ~ RealFromBcpl[sd.wx];
wy: REAL ~ RealFromBcpl[sd.wy];
RETURN[font.charToClient.TransformVec[[wx, wy]]];
};
};
RETURN[[0, 0]];
};
Amplified: PROC[font: Font, char: Char] RETURNS[BOOL] ~ {
RETURN[char=40B];
};
Correction: PROC[font: Font, char: Char] RETURNS[CorrectionType] ~ {
data: Data ~ NARROW[font.data];
file: SDFile ~ data.file;
IF char IN[file.bc..file.ec] THEN {
IF char=40B THEN RETURN[space] ELSE RETURN[mask];
};
RETURN[none];
};
Kern: PROC[font: Font, char, successor: Char] RETURNS[VEC] ~ {
RETURN[[0, 0]];
};
NextKern: PROC[font: Font, char, successor: Char] RETURNS[Char] ~ {
RETURN[nullChar];
};
Ligature: PROC[font: Font, char, successor: Char] RETURNS[Char] ~ {
RETURN[nullChar];
};
NextLigature: PROC[font: Font, char, successor: Char] RETURNS[Char] ~ {
RETURN[nullChar];
};
CharInfo: PROC[font: Font, char: Char, key: ATOM] RETURNS[OptionalReal] ~ {
RETURN[[FALSE, 0]];
};
missingOffset: LONG CARDINAL ~
PrePressFontFormat.CardFromDouble[PrePressFontFormat.missingFilePos];
MaskChar: PROC[font: Font, char: Char, imager: REF] ~ {
context: Imager.Context ~ NARROW[imager];
data: Data ~ NARROW[font.data];
file: SDFile ~ data.file;
IF char IN[file.bc..file.ec] THEN {
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← file.splineData[char-file.bc] };
IF sd.wx#PrePressFontFormat.missingSpline THEN {
base: LONG POINTERNIL;
SDPath: ImagerPath.PathProc ~ {
next: LONG POINTER ← base;
lp: VEC ← [0, 0];
GetCode: PROC RETURNS[PrePressFontFormat.SplineCode] ~ TRUSTED {
p: LONG POINTER TO PrePressFontFormat.SplineCommand ~ next;
next ← next+SIZE[PrePressFontFormat.SplineCommand];
RETURN[p.code];
};
GetCoords: PROC RETURNS[VEC] ~ TRUSTED {
p: LONG POINTER TO PrePressFontFormat.SplineCoords ~ next;
next ← next+SIZE[PrePressFontFormat.SplineCoords];
RETURN[[RealFromBcpl[p.x], RealFromBcpl[p.y]]];
};
DO SELECT GetCode[] FROM
$moveTo => {
p: VEC ~ GetCoords[];
moveTo[p];
lp ← p;
};
$drawTo => {
p: VEC ~ GetCoords[];
lineTo[p];
lp ← p;
};
$drawCurve => {
c1: VEC ~ GetCoords[];
c2: VEC ~ GetCoords[];
c3: VEC ~ GetCoords[];
b1: VEC ~ lp.Add[c1.Div[3]];
b2: VEC ~ b1.Add[c1.Add[c2].Div[3]];
b3: VEC ~ lp.Add[c1].Add[c2].Add[c3];
curveTo[b1, b2, b3];
lp ← b3;
};
$endDefinition => EXIT;
$newObject => ERROR MalformedSDFont; -- not implemented
ENDCASE => ERROR MalformedSDFont; -- undefined
ENDLOOP;
};
action: PROC ~ {
Imager.ConcatT[context, font.charToClient];
Imager.MaskFillParity[context, SDPath];
};
TRUSTED {
fp: LONG CARDINAL ~ PrePressFontFormat.CardFromDouble[file.directory[char-file.bc]];
IF fp#missingOffset THEN base ← LOOPHOLE[file.directory+fp]
ELSE ERROR MalformedSDFont;
};
Imager.DoSave[context, action];
};
};
};
class: ImagerFont.Class ~ NEW[ImagerFont.ClassRep ← [
Modify: Modify,
Contains: Contains,
NextChar: NextChar,
Width: Width,
Amplified: Amplified,
Correction: Correction,
BoundingBox: BoundingBox,
Ligature: Ligature,
NextLigature: NextLigature,
Kern: Kern,
NextKern: NextKern,
CharInfo: CharInfo,
MaskChar: MaskChar
]];
SDRegister: PROC ~ {
scratch: REF TEXT ~ NEW[TEXT[200]];
DoName: FS.NameProc ~ {
cp: FS.ComponentPositions; start, stop: INT;
text: REF TEXT ← scratch;
[fullFName: fullFName, cp: cp] ← FS.ExpandName[fullFName];
start ← cp.subDirs.start; stop ← cp.base.start+cp.base.length;
text.length ← 0;
text ← RefText.AppendRope[to: text, from: "Xerox/PressFonts/"];
text ← RefText.AppendRope[to: text, from: fullFName, start: start, len: stop-start];
FOR i: NAT IN[0..text.length) DO IF text[i]='> THEN text[i] ← '/ ENDLOOP;
ImagerFont.Register[name: Rope.FromRefText[text], file: fullFName, create: SDCreate];
RETURN[continue: TRUE];
};
FS.EnumerateForNames[pattern: "[Indigo]<PressFonts>*.sd!H", proc: DoName];
ImagerFont.Alias["Xerox/XC82-0-0/Classic", "Xerox/PressFonts/Classic-MRR"];
ImagerFont.Alias["Xerox/XC82-0-0/Classic-Bold", "Xerox/PressFonts/Classic-BRR"];
ImagerFont.Alias["Xerox/XC82-0-0/Classic-Italic", "Xerox/PressFonts/Classic-MIR"];
ImagerFont.Alias["Xerox/XC82-0-0/Modern", "Xerox/PressFonts/Modern-MRR"];
ImagerFont.Alias["Xerox/XC82-0-0/Modern-Bold", "Xerox/PressFonts/Modern-BRR"];
ImagerFont.Alias["Xerox/XC82-0-0/Modern-Italic", "Xerox/PressFonts/Modern-MIR"];
ImagerFont.Alias["Xerox/XC82-0-0/Logotypes-Xerox", "Xerox/PressFonts/LOGO-MRR"];
};
SDRegister[];
END.