ImagerSDTypefaceImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Doug Wyatt, November 11, 1985 5:09:42 pm PST
DIRECTORY
Basics USING [BYTE, bytesPerWord],
CountedVM USING [Allocate, Handle],
FS USING [OpenFile, StreamFromOpenFile],
Imager USING [Context, MaskFill],
ImagerFont USING [CorrectionType, Extents, nullXChar, XChar],
ImagerPath USING [PathProc],
ImagerTypeface USING [Register, Typeface, TypefaceClass, TypefaceClassRep, TypefaceRep],
IO USING [Close, SetIndex, STREAM, UnsafeGetBlock],
PrePressFontFormat USING [CardFromBcpl, DirectoryArray, IntFromBcpl, IXHeader, missingFilePos, missingSpline, NameIndexEntry, RelFilePos, SplineCode, SplineCommand, SplineCoords, SplineData, SplineDataArray, StdIndexEntry],
RealConvert USING [BcplToIeee],
Vector2 USING [Add, Div, VEC];
ImagerSDTypefaceImpl: CEDAR PROGRAM
IMPORTS CountedVM, FS, Imager, ImagerTypeface, IO, PrePressFontFormat, RealConvert, Vector2
~ BEGIN OPEN ImagerTypeface, ImagerFont;
BYTE: TYPE ~ Basics.BYTE;
VEC: TYPE ~ Vector2.VEC;
Data: TYPE ~ REF DataRep;
DataRep: TYPE ~ RECORD[
bc, ec: BYTE ← 0,
splineData: LONG POINTER TO PrePressFontFormat.SplineDataArray ← NIL,
directory: LONG POINTER TO PrePressFontFormat.DirectoryArray ← NIL,
vm: CountedVM.Handle ← NIL
];
MalformedSDFont: ERROR ~ CODE;
ReadWords: UNSAFE PROC [stream: IO.STREAM, base: LONG POINTER, words: INT] ~ UNCHECKED {
count: INT ~ words*Basics.bytesPerWord;
IF IO.UnsafeGetBlock[stream, [base: LOOPHOLE[base], count: count]]=count THEN NULL
ELSE ERROR MalformedSDFont; -- data too short
};
SDCreate: PROC [file: FS.OpenFile] RETURNS [Typeface] ~ {
OPEN PrePressFontFormat;
stream: IO.STREAM ~ FS.StreamFromOpenFile[file];
data: Data ~ NEW[DataRep ← []];
ix: IXHeader;
ixSize: NAT ~ SIZE[IXHeader];
name: NameIndexEntry;
index: StdIndexEntry;
nameFound, indexFound: BOOLFALSE;
segmentIndex, segmentWords: INT ← 0;
DO -- read the index part
TRUSTED { ReadWords[stream, @ix, SIZE[IXHeader]] };
SELECT ix.type FROM
end => EXIT;
name => {
IF nameFound THEN ERROR MalformedSDFont; -- more than one name entry
IF (ix.length-ixSize)=SIZE[NameIndexEntry] THEN TRUSTED {
ReadWords[stream, @name, SIZE[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[StdIndexEntry] THEN TRUSTED {
ReadWords[stream, @index, SIZE[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
data.bc ← index.bc; data.ec ← index.ec;
segmentIndex ← CardFromBcpl[index.segmentSA]; -- in words!
segmentWords ← CardFromBcpl[index.segmentLength];
data.vm ← CountedVM.Allocate[words: segmentWords];
IO.SetIndex[stream, segmentIndex*Basics.bytesPerWord];
TRUSTED { -- read segment
base: LONG POINTER ~ data.vm.pointer;
ReadWords[stream, base, segmentWords];
data.splineData ← LOOPHOLE[base];
data.directory ← LOOPHOLE[base+SIZE[SplineDataArray[index.ec-index.bc+1]]];
};
IO.Close[stream];
RETURN[NEW[TypefaceRep ← [class: sdClass, data: data]]];
};
SDContains: PROC [self: Typeface, char: XChar] RETURNS [BOOL] ~ {
data: Data ~ NARROW[self.data];
IF char.set=0 AND char.code IN[data.bc..data.ec] THEN {
index: NAT ~ char.code-data.bc;
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← data.splineData[index] };
RETURN[sd.wx#PrePressFontFormat.missingSpline];
};
RETURN[FALSE];
};
SDNextChar: PROC [self: Typeface, char: XChar] RETURNS [next: XChar] ~ {
data: Data ~ NARROW[self.data];
start: BYTE ← 0;
IF char=nullXChar THEN NULL
ELSE IF char.set=0 AND char.code<data.ec THEN start ← char.code+1
ELSE RETURN[nullXChar];
FOR code: BYTE IN[MAX[data.bc, start]..data.ec] DO
index: NAT ~ code-data.bc;
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← data.splineData[index] };
IF sd.wx#PrePressFontFormat.missingSpline THEN RETURN[[set: 0, code: code]];
ENDLOOP;
RETURN[nullXChar];
};
SDEscapement: PROC [self: Typeface, char: XChar] RETURNS [VEC] ~ {
data: Data ~ NARROW[self.data];
IF char.set=0 AND char.code IN[data.bc..data.ec] THEN {
index: NAT ~ char.code-data.bc;
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← data.splineData[index] };
IF sd.wx#PrePressFontFormat.missingSpline THEN {
wx: REAL ~ RealConvert.BcplToIeee[sd.wx];
wy: REAL ~ RealConvert.BcplToIeee[sd.wy];
RETURN[[wx, wy]];
};
};
RETURN[[0, 0]];
};
SDAmplified: PROC [self: Typeface, char: XChar] RETURNS [BOOL] ~ {
RETURN[char.set=0 AND char.code=40B];
};
SDCorrection: PROC [self: Typeface, char: XChar] RETURNS [CorrectionType] ~ {
data: Data ~ NARROW[self.data];
IF char.set=0 AND char.code IN[data.bc..data.ec] THEN {
IF char.code=40B THEN RETURN[space] ELSE RETURN[mask];
};
RETURN[none];
};
SDBoundingBox: PROC [self: Typeface, char: XChar] RETURNS [Extents] ~ {
data: Data ~ NARROW[self.data];
IF char.set=0 AND char.code IN[data.bc..data.ec] THEN {
index: NAT ~ char.code-data.bc;
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← data.splineData[index] };
IF sd.wx#PrePressFontFormat.missingSpline THEN {
xmin: REAL ~ RealConvert.BcplToIeee[sd.xmin];
ymin: REAL ~ RealConvert.BcplToIeee[sd.ymin];
xmax: REAL ~ RealConvert.BcplToIeee[sd.xmax];
ymax: REAL ~ RealConvert.BcplToIeee[sd.ymax];
RETURN[[leftExtent: -xmin, rightExtent: xmax, descent: -ymin, ascent: ymax]];
};
};
RETURN[[0, 0, 0, 0]];
};
SDFontBoundingBox: PROC [self: Typeface] RETURNS [Extents] ~ {
data: Data ~ NARROW[self.data];
count: NAT ← 0;
fxmin, fymin, fxmax, fymax: REAL ← 0;
FOR code: BYTE IN[data.bc..data.ec] DO
index: NAT ~ code-data.bc;
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← data.splineData[index] };
IF sd.wx#PrePressFontFormat.missingSpline THEN {
xmin: REAL ~ RealConvert.BcplToIeee[sd.xmin];
ymin: REAL ~ RealConvert.BcplToIeee[sd.ymin];
xmax: REAL ~ RealConvert.BcplToIeee[sd.xmax];
ymax: REAL ~ RealConvert.BcplToIeee[sd.ymax];
IF count=0 THEN { fxmin ← xmin; fymin ← ymin; fxmax ← xmax; fymax ← ymax }
ELSE {
IF xmin<fxmin THEN fxmin ← xmin;
IF ymin<fymin THEN fymin ← ymin;
IF xmax>fxmax THEN fxmax ← xmax;
IF ymax>fymax THEN fymax ← ymax;
};
count ← count+1;
};
ENDLOOP;
RETURN[[leftExtent: -fxmin, rightExtent: fxmax, descent: -fymin, ascent: fymax]];
};
SDKern: PROC [self: Typeface, char, successor: XChar] RETURNS [VEC] ~ {
RETURN[[0, 0]];
};
SDNextKern: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ {
RETURN[nullXChar];
};
SDLigature: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ {
RETURN[nullXChar];
};
SDNextLigature: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ {
RETURN[nullXChar];
};
SDMask: PROC [self: Typeface, char: XChar, context: Imager.Context] ~ {
data: Data ~ NARROW[self.data];
IF char.set=0 AND char.code IN[data.bc..data.ec] THEN {
index: NAT ~ char.code-data.bc;
sd: PrePressFontFormat.SplineData;
TRUSTED { sd ← data.splineData[index] };
IF sd.wx#PrePressFontFormat.missingSpline THEN {
base: LONG POINTERNIL;
path: ImagerPath.PathProc ~ {
next: LONG POINTER ← base;
lp: VEC ← [0, 0];
GetCode: PROC RETURNS [PrePressFontFormat.SplineCode] ~ TRUSTED {
p: LONG POINTER TO PrePressFontFormat.SplineCommand ~ LOOPHOLE[next];
next ← next+SIZE[PrePressFontFormat.SplineCommand];
RETURN[p.code];
};
GetCoords: PROC RETURNS [VEC] ~ TRUSTED {
p: LONG POINTER TO PrePressFontFormat.SplineCoords ~ LOOPHOLE[next];
next ← next+SIZE[PrePressFontFormat.SplineCoords];
RETURN[[RealConvert.BcplToIeee[p.x], RealConvert.BcplToIeee[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;
};
TRUSTED {
filePos: PrePressFontFormat.RelFilePos ~ data.directory[index];
offset: INT ~ PrePressFontFormat.IntFromBcpl[filePos];
IF filePos=PrePressFontFormat.missingFilePos THEN ERROR MalformedSDFont;
base ← LOOPHOLE[data.directory+offset];
};
Imager.MaskFill[context: context, path: path, oddWrap: TRUE];
};
};
};
sdClass: TypefaceClass ~ NEW[TypefaceClassRep ← [
type: $SD,
Contains: SDContains,
NextChar: SDNextChar,
Escapement: SDEscapement,
Amplified: SDAmplified,
Correction: SDCorrection,
BoundingBox: SDBoundingBox,
FontBoundingBox: SDFontBoundingBox,
Ligature: SDLigature,
NextLigature: SDNextLigature,
Kern: SDKern,
NextKern: SDNextKern,
Mask: SDMask
]];
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;
Register[name: Rope.FromRefText[text], fileName: fullFName, create: SDCreate];
RETURN[continue: TRUE];
};
FS.EnumerateForNames[pattern: "[Indigo]<PressFonts>*.sd!H", proc: DoName];
Alias["Xerox/XC82-0-0/Classic", "Xerox/PressFonts/Classic-MRR"];
Alias["Xerox/XC82-0-0/Classic-Bold", "Xerox/PressFonts/Classic-BRR"];
Alias["Xerox/XC82-0-0/Classic-Italic", "Xerox/PressFonts/Classic-MIR"];
Alias["Xerox/XC82-0-0/Modern", "Xerox/PressFonts/Modern-MRR"];
Alias["Xerox/XC82-0-0/Modern-Bold", "Xerox/PressFonts/Modern-BRR"];
Alias["Xerox/XC82-0-0/Modern-Italic", "Xerox/PressFonts/Modern-MIR"];
Alias["Xerox/XC82-0-0/Logotypes-Xerox", "Xerox/PressFonts/LOGO-MRR"];
};
ImagerTypeface.Register["SD", SDCreate];
END.