ImagerStrikeTypefaceImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Doug Wyatt, November 11, 1985 4:37:35 pm PST
DIRECTORY
Basics USING [bytesPerWord],
BasicTime USING [GMT],
CountedVM USING [Allocate, Handle],
ImagerFont USING [BYTE, CorrectionType, Extents, nullXChar, XChar],
ImagerTypeface USING [Register, Typeface, TypefaceClass, TypefaceClassRep, TypefaceRep],
FS USING [OpenFile, StreamFromOpenFile],
Imager USING [Context, MaskBits],
IO USING [Close, EndOfStream, STREAM, UnsafeGetBlock],
Rope USING [ROPE],
StrikeFontFormat USING [Body, BoundingBox, Header, nullWidthEntry, WidthEntry, WTable, XTable],
Vector2 USING [VEC];
ImagerStrikeTypefaceImpl: CEDAR PROGRAM
IMPORTS CountedVM, FS, Imager, ImagerTypeface, IO
~ BEGIN OPEN ImagerTypeface, ImagerFont;
ROPE: TYPE ~ Rope.ROPE;
VEC: TYPE ~ Vector2.VEC;
Data: TYPE ~ REF DataRep;
DataRep:
TYPE ~
RECORD[
min, max: BYTE ← 0,
left, right, ascent, descent: INTEGER ← 0, -- font extents
strike: LONG POINTER ← NIL,
raster, lines: NAT ← 0,
xtable: LONG POINTER TO StrikeFontFormat.XTable ← NIL,
wtable: LONG POINTER TO StrikeFontFormat.WTable ← NIL,
vm: CountedVM.Handle ← NIL
];
MalformedStrikeFont: ERROR ~ CODE;
Assert: PROC [pred: BOOL] ~ { IF pred THEN NULL ELSE ERROR MalformedStrikeFont };
ReadWords:
UNSAFE
PROC [stream:
IO.
STREAM, base:
LONG
POINTER, words:
INT] ~
UNCHECKED {
count: CARDINAL ~ words*Basics.bytesPerWord;
IF IO.UnsafeGetBlock[stream, [base: base, count: count]]=count THEN NULL
ELSE ERROR IO.EndOfStream[stream]; -- file too short
};
StrikeCreate:
PROC [file:
FS.OpenFile]
RETURNS [Typeface] ~ {
OPEN StrikeFontFormat;
stream: IO.STREAM ~ FS.StreamFromOpenFile[file];
data: Data ← NIL;
header: Header;
box: BoundingBox ← [0, 0, 0, 0];
body: Body;
left, right, descent, ascent, lines: INTEGER ← 0;
vm: CountedVM.Handle ← NIL;
strikeWords, xtableWords, wtableWords: NAT ← 0;
vmWords: INT ← 0;
strike, xtable, wtable: LONG POINTER ← NIL;
TRUSTED { ReadWords[stream, @header, SIZE[Header]] };
Assert[header.oneBit=T AND header.index=F AND header.unused=0];
Assert[header.min<=header.max AND header.max<=BYTE.LAST];
IF header.kerned=T THEN TRUSTED { ReadWords[stream, @box, SIZE[BoundingBox]] };
TRUSTED { ReadWords[stream, @body, SIZE[Body]] };
descent ← body.descent; ascent ← body.ascent;
Assert[(lines ← descent+ascent)>0];
IF header.kerned=
T
THEN { left ← -box.fbbox; right ← box.fbbox+box.fbbdx;
Assert[box.fbboy=-descent AND box.fbbdy=lines AND box.fbbdx>0] }
ELSE { left ← 0; right ← header.maxwidth };
strikeWords ← body.raster*lines;
xtableWords ← header.max-header.min+3;
Assert[CARDINAL[SIZE[Body]+strikeWords+xtableWords]<=body.length];
IF header.kerned=T THEN wtableWords ← header.max-header.min+2;
vmWords ← LONG[strikeWords+xtableWords]+wtableWords;
vm ← CountedVM.Allocate[words: vmWords];
IF vm.words<vmWords THEN ERROR -- not enough words ??
ELSE
TRUSTED {
-- read remainder of file: strike, xtable, and wtable
base: LONG POINTER ~ vm.pointer;
ReadWords[stream, base, vmWords];
strike ← base;
xtable ← strike+strikeWords;
IF wtableWords#0 THEN wtable ← xtable+xtableWords;
};
IO.Close[stream];
data ←
NEW[DataRep ← [min: header.min, max: header.max,
left: left, right: right, ascent: body.ascent, descent: body.descent,
strike: strike, raster: body.raster, lines: lines, xtable: xtable, wtable: wtable, vm: vm]];
RETURN[NEW[TypefaceRep ← [class: strikeClass, data: data]]];
};
Index:
PROC [data: Data, char: XChar]
RETURNS [
NAT] ~ {
IF char.set=0
AND char.code
IN[data.min..data.max]
THEN {
index: NAT ~ char.code-data.min;
IF data.wtable=
NIL
THEN
TRUSTED {
x0: INTEGER ~ data.xtable[index];
x1: INTEGER ~ data.xtable[index+1];
IF x1>x0 THEN RETURN[index];
}
ELSE
TRUSTED {
w: StrikeFontFormat.WidthEntry ~ data.wtable[index];
IF w#StrikeFontFormat.nullWidthEntry THEN RETURN[index];
};
};
RETURN[data.max-data.min+1];
};
StrikeContains:
PROC [self: Typeface, char: XChar]
RETURNS [
BOOL] ~ {
data: Data ~ NARROW[self.data];
RETURN[Index[data, char]<=(data.max-data.min)];
};
StrikeNextChar:
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.max THEN start ← char.code+1
ELSE RETURN[nullXChar];
FOR code:
BYTE
IN[
MAX[data.min, start]..data.max]
DO
next: XChar ~ [set: 0, code: code];
IF Index[data, next]<=(data.max-data.min) THEN RETURN[next];
ENDLOOP;
RETURN[nullXChar];
};
StrikeBoundingBox:
PROC [self: Typeface, char: XChar]
RETURNS [Extents] ~ {
data: Data ~ NARROW[self.data];
index: NAT ~ Index[data, char];
IF data.wtable=
NIL
THEN
TRUSTED {
x0: INTEGER ~ data.xtable[index];
x1: INTEGER ~ data.xtable[index+1];
IF x1>x0 THEN RETURN[[leftExtent: 0, rightExtent: (x1-x0),
descent: data.descent, ascent: data.ascent]];
}
ELSE
TRUSTED {
w: StrikeFontFormat.WidthEntry ~ data.wtable[index];
IF w#StrikeFontFormat.nullWidthEntry
THEN {
x0: INTEGER ~ data.xtable[index];
x1: INTEGER ~ data.xtable[index+1];
left: INTEGER ~ data.left-w.offset;
RETURN[[leftExtent: left, rightExtent: (x1-x0)-left,
descent: data.descent, ascent: data.ascent]];
};
};
RETURN[[0, 0, 0, 0]];
};
StrikeFontBoundingBox:
PROC [self: Typeface]
RETURNS [Extents] ~ {
data: Data ~ NARROW[self.data];
RETURN[[leftExtent: data.left, rightExtent: data.right,
descent: data.descent, ascent: data.ascent]];
};
StrikeEscapement:
PROC [self: Typeface, char: XChar]
RETURNS [
VEC] ~ {
data: Data ~ NARROW[self.data];
index: NAT ~ Index[data, char];
IF data.wtable=
NIL
THEN
TRUSTED {
x0: INTEGER ~ data.xtable[index];
x1: INTEGER ~ data.xtable[index+1];
IF x1>x0 THEN RETURN[[x1-x0, 0]];
}
ELSE
TRUSTED {
w: StrikeFontFormat.WidthEntry ~ data.wtable[index];
IF w#StrikeFontFormat.nullWidthEntry THEN RETURN[[w.width, 0]];
};
RETURN[[0, 0]];
};
spaceChar: XChar ~ [set: 0, code: 40B];
StrikeAmplified:
PROC [self: Typeface, char: XChar]
RETURNS [
BOOL] ~ {
RETURN[char=spaceChar];
};
StrikeCorrection:
PROC [self: Typeface, char: XChar]
RETURNS [CorrectionType] ~ {
RETURN[IF char=spaceChar THEN space ELSE mask];
};
StrikeKern:
PROC [self: Typeface, char, successor: XChar]
RETURNS [
VEC] ~ {
RETURN[[0, 0]];
};
StrikeNextKern:
PROC [self: Typeface, char, successor: XChar]
RETURNS [XChar] ~ {
RETURN[nullXChar];
};
StrikeLigature:
PROC [self: Typeface, char, successor: XChar]
RETURNS [XChar] ~ {
RETURN[nullXChar];
};
StrikeNextLigature:
PROC [self: Typeface, char, successor: XChar]
RETURNS [XChar] ~ {
RETURN[nullXChar];
};
StrikeMask:
PROC [self: Typeface, char: XChar, context: Imager.Context] ~
TRUSTED {
data: Data ~ NARROW[self.data];
index: NAT ~ Index[data, char];
x0: INTEGER ~ data.xtable[index];
x1: INTEGER ~ data.xtable[index+1];
IF x0<=x1 AND NAT[x1]<=NAT[data.raster*16] THEN NULL
ELSE ERROR MalformedStrikeFont; -- xtable inconsistent
IF data.wtable=
NIL
THEN {
IF x1>x0 THEN Imager.MaskBits[context: context,
base: data.strike, wordsPerLine: data.raster,
fMin: x0, fSize: x1-x0, sMin: 0, sSize: data.lines,
tx: 0, ty: data.ascent];
}
ELSE {
w: StrikeFontFormat.WidthEntry ~ data.wtable[index];
IF w#StrikeFontFormat.nullWidthEntry AND x1>x0 THEN Imager.MaskBits[context: context,
base: data.strike, wordsPerLine: data.raster,
fMin: x0, fSize: x1-x0, sMin: 0, sSize: data.lines,
tx: w.offset-data.left, ty: data.ascent];
};
};
strikeClass: TypefaceClass ~
NEW[TypefaceClassRep ← [
type: $Strike,
Contains: StrikeContains,
NextChar: StrikeNextChar,
Escapement: StrikeEscapement,
Amplified: StrikeAmplified,
Correction: StrikeCorrection,
BoundingBox: StrikeBoundingBox,
FontBoundingBox: StrikeFontBoundingBox,
Ligature: StrikeLigature,
NextLigature: StrikeNextLigature,
Kern: StrikeKern,
NextKern: StrikeNextKern,
Mask: StrikeMask
]];
ImagerTypeface.Register["strike", StrikeCreate];
ImagerTypeface.Register["ks", StrikeCreate];
END.