SDFontImpl.mesa
Copyright © 1984, Xerox Corporation. All rights reserved.
Doug Wyatt, October 9, 1984 3:17:56 pm PDT
DIRECTORY
Basics USING [bytesPerWord],
CountedVM USING [Allocate, Handle, Pointer],
Font USING [Char, Class, ClassRep, CorrectionType, Extents, FONT, FontRep, nullChar, OptionalReal, Register],
FS USING [StreamOpen],
Imager,
ImagerPath,
ImagerTransformation,
IO USING [Close, SetIndex, STREAM, UnsafeGetBlock],
PrePressFontFormat,
RealConvert USING [BcplToIeee],
Rope USING [FromProc, ROPE],
Vector2;
SDFontImpl: CEDAR PROGRAM
IMPORTS CountedVM, Font, FS, Imager, ImagerTransformation, IO, PrePressFontFormat, RealConvert, Rope, Vector2
~ BEGIN
BYTE: TYPE ~ [0..377B];
ROPE: TYPE ~ Rope.ROPE;
VEC: TYPE ~ Vector2.VEC;
Transformation: TYPE ~ ImagerTransformation.Transformation;
FONT: TYPE ~ Font.FONT;
FontRep:
TYPE ~ Font.FontRep;
name: ROPE,
transformation: Transformation,
class: Class,
data: REF,
propList: REF
Char: TYPE ~ Font.Char; -- CARDINAL
nullChar: Char ~ Font.nullChar;
CorrectionType:
TYPE ~ Font.CorrectionType;
-- {none, space, mask};
Extents:
TYPE ~ Font.Extents;
-- RECORD[leftExtent, rightExtent, descent, ascent: REAL];
OptionalReal:
TYPE ~ Font.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: BOOL ← FALSE;
family: ROPE ← NIL;
segmentIndex, segmentWords: INT ← 0;
vm: CountedVM.Handle ← NIL;
splineData, directory: LONG POINTER ← NIL;
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]]];
};
Find:
PROC[name:
ROPE]
RETURNS[
FONT] ~ {
file: SDFile ~ Open[name];
charToClient: Transformation ~ ImagerTransformation.Scale[1];
data: Data ~ NEW[DataRep ← [file: file]];
RETURN[
NEW[Font.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 POINTER ← NIL;
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: Font.Class ~
NEW[Font.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
]];
Font.Register["Xerox/SD", Find];
END.