UFTfmReaderImpl.mesa
Last changed by Michael Plass, February 3, 1983 3:17 pm
Last changed by Doug Wyatt, September 30, 1983 5:54 pm
DIRECTORY
Font,
Real USING [MinusZero, SqRt],
RefText USING [ObtainScratch, ReleaseScratch],
Rope USING [FromRefText, ROPE],
Tfm,
UFFileManager USING [FontFile, GetData, InBounds, InitProc, Open, Pointer],
UFTfmReader;
UFTfmReaderImpl: CEDAR PROGRAM
IMPORTS Font, Real, RefText, Rope, Tfm, UFFileManager
EXPORTS UFTfmReader =
BEGIN OPEN UFTfmReader;
TwoToTheTenth: INT = 2*2*2*2*2 * 2*2*2*2*2;
TwoToTheTwentieth: INT = TwoToTheTenth*TwoToTheTenth;
RealTwoToTheTwentieth: REAL = TwoToTheTwentieth;
FixedToReal: PROCEDURE [x: Tfm.Fixed] RETURNS [REAL] =
{RETURN[Tfm.Long[x]/RealTwoToTheTwentieth]};
Ord: PROCEDURE [c: CHAR] RETURNS [[0..256)] = INLINE {RETURN[LOOPHOLE[c]]};
Data: TYPE = REF DataRec;
DataRec: TYPE = RECORD [
characterCodingScheme: Rope.ROPE,
family: Rope.ROPE,
dirPtr: LONG POINTER TO Tfm.Directory,
headerPtr: LONG POINTER TO Tfm.Header,
fInfoDesc: LONG DESCRIPTOR FOR ARRAY OF Tfm.FInfoEntry,
widthDesc: LONG DESCRIPTOR FOR ARRAY OF Tfm.Fixed,
heightDesc: LONG DESCRIPTOR FOR ARRAY OF Tfm.Fixed,
depthDesc: LONG DESCRIPTOR FOR ARRAY OF Tfm.Fixed,
charIcDesc: LONG DESCRIPTOR FOR ARRAY OF Tfm.Fixed,
ligKernDesc: LONG DESCRIPTOR FOR ARRAY OF Tfm.LigKernEntry,
kernDesc: LONG DESCRIPTOR FOR ARRAY OF Tfm.Fixed,
extenDesc: LONG DESCRIPTOR FOR ARRAY OF Tfm.ExtRecipe,
paramPtr: LONG POINTER TO Tfm.Param
];
OpenInit: UFFileManager.InitProc = TRUSTED {
base: LONG POINTER ← fontFile.Pointer[];
dir: LONG POINTER TO Tfm.Directory ← base;
data: Data ← NEW[DataRec];
curPtr: LONG POINTER ← base;
Next: UNSAFE PROC [size: NAT] RETURNS [p: LONG POINTER] = UNCHECKED {p ← curPtr; curPtr ← curPtr + size};
s: NAT = SIZE[Tfm.Word];
IF NOT fontFile.InBounds[dir, SIZE[Tfm.Directory]] THEN
ERROR Font.BadFontFileFormat;
IF NOT Tfm.ValidDirectory[dir^] THEN
ERROR Font.BadFontFileFormat;
IF NOT fontFile.InBounds[base, dir.lf] THEN
ERROR Font.BadFontFileFormat;
data.dirPtr ← Next[SIZE[Tfm.Directory]];
data.headerPtr ← Next[s*dir.lh];
data.fInfoDesc ← DESCRIPTOR[Next[s*(dir.ec-dir.bc+1)], s*(dir.ec-dir.bc+1)];
data.widthDesc ← DESCRIPTOR[Next[s*dir.nw], s*dir.nw];
data.heightDesc ← DESCRIPTOR[Next[s*dir.nh], s*dir.nh];
data.depthDesc ← DESCRIPTOR[Next[s*dir.nd], s*dir.nd];
data.charIcDesc ← DESCRIPTOR[Next[s*dir.ni], s*dir.ni];
data.ligKernDesc ← DESCRIPTOR[Next[s*dir.nl], s*dir.nl];
data.kernDesc ← DESCRIPTOR[Next[s*dir.nk], s*dir.nk];
data.extenDesc ← DESCRIPTOR[Next[s*dir.ne], s*dir.ne];
data.paramPtr ← Next[s*dir.np];
Make some ropes
BEGIN
temp: REF TEXT ← RefText.ObtainScratch[40];
temp.length ← Ord[data.headerPtr.characterCodingScheme[0]];
FOR i: NAT IN [0..temp.length) DO
temp[i] ← data.headerPtr.characterCodingScheme[i+1];
ENDLOOP;
data.characterCodingScheme ← Rope.FromRefText[temp];
temp.length ← Ord[data.headerPtr.externalFontIdentifier[0]];
FOR i: NAT IN [0..temp.length) DO
temp[i] ← data.headerPtr.externalFontIdentifier[i+1];
ENDLOOP;
data.family ← Rope.FromRefText[temp];
RefText.ReleaseScratch[temp];
END;
RETURN[data];
};
CheckSum: PUBLIC PROCEDURE [key: Key] RETURNS [checkSum: Tfm.Word] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
checkSum ← data.headerPtr.checkSum;
};
CharacterCodingScheme: PUBLIC PROCEDURE [key: Key] RETURNS [characterCodingScheme: Rope.ROPE] = {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
characterCodingScheme ← data.characterCodingScheme;
};
Family: PUBLIC PROCEDURE [key: Key] RETURNS [family: Rope.ROPE] = {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
family ← data.family;
};
DesignSize: PUBLIC PROCEDURE [key: Key] RETURNS [designSize: REAL] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
designSize ← FixedToReal[data.headerPtr.designSize];
};
Face: PUBLIC PROCEDURE [key: Key] RETURNS [face: [0..256)] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
face ← data.headerPtr.extraInfo.parcFaceByte;
};
Range: PUBLIC PROCEDURE [key: Key] RETURNS [bc, ec: CHAR] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
bc ← '\000+data.dirPtr.bc;
ec ← '\000+data.dirPtr.ec;
};
NullFInfoEntry: Tfm.FInfoEntry = [0, 0, 0, 0, none[]];
Contains: PUBLIC PROCEDURE [key: Key, char: CHAR] RETURNS [BOOLEAN] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
IF NOT (Ord[char]>= data.dirPtr.bc AND Ord[char] <= data.dirPtr.ec) THEN RETURN [FALSE];
RETURN[data.fInfoDesc[Ord[char]-data.dirPtr.bc] # NullFInfoEntry];
};
Width: PUBLIC PROCEDURE [key: Key, char: CHAR] RETURNS [width: REAL] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
IF NOT (Ord[char] IN [data.dirPtr.bc..data.dirPtr.ec]) THEN RETURN [Real.MinusZero];
width ← FixedToReal[data.widthDesc[data.fInfoDesc[Ord[char]-data.dirPtr.bc].widthIndex]];
};
Height: PUBLIC PROCEDURE [key: Key, char: CHAR] RETURNS [height: REAL] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
IF NOT (Ord[char] IN [data.dirPtr.bc..data.dirPtr.ec]) THEN RETURN [Real.MinusZero];
height ← FixedToReal[data.heightDesc[data.fInfoDesc[Ord[char]-data.dirPtr.bc].heightIndex]];
};
Depth: PUBLIC PROCEDURE [key: Key, char: CHAR] RETURNS [depth: REAL] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
IF NOT (Ord[char] IN [data.dirPtr.bc..data.dirPtr.ec]) THEN RETURN [Real.MinusZero];
depth ← FixedToReal[data.depthDesc[data.fInfoDesc[Ord[char]-data.dirPtr.bc].depthIndex]];
};
ItalicCorrection: PUBLIC PROCEDURE [key: Key, char: CHAR] RETURNS [italicCorrection: REAL] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
IF NOT (Ord[char] IN [data.dirPtr.bc..data.dirPtr.ec]) THEN RETURN [Real.MinusZero];
italicCorrection ← FixedToReal[data.charIcDesc[data.fInfoDesc[Ord[char]-data.dirPtr.bc].charIcIndex]];
};
LigKern: PUBLIC PROCEDURE [key: Key, char1, char2: CHAR]
RETURNS [ligOrKern: Font.LigatureOrKern] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
IF NOT (Ord[char1] IN [data.dirPtr.bc..data.dirPtr.ec] AND Ord[char2] IN [data.dirPtr.bc..data.dirPtr.ec]) THEN RETURN [[neither[]]];
WITH data.fInfoDesc[Ord[char1]-data.dirPtr.bc] SELECT FROM
ligFInfoEntry: Tfm.FInfoEntry[lig] => {
FOR i: NAT ← ligFInfoEntry.ligKernStart, i+1 DO
ligKernEntry: Tfm.LigKernEntry ← data.ligKernDesc[i];
IF ligKernEntry.nextChar = char2 THEN RETURN[
WITH ligKernEntry SELECT FROM
ligEntry: Tfm.LigKernEntry[lig] => [ligature[ligatureCode: ligEntry.ligCode]],
kernEntry: Tfm.LigKernEntry[kern] => [kern[kernAmount: FixedToReal[data.kernDesc[kernEntry.kernIndex]]]],
ENDCASE => ERROR
];
IF ligKernEntry.stop THEN RETURN[[neither[]]];
ENDLOOP
};
ENDCASE => RETURN[[neither[]]];
};
Slant: PUBLIC PROCEDURE [key: Key] RETURNS [numerator, denominator: INT] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
numerator ← Tfm.Long[data.paramPtr[slant].ValueTimesTwoToTheTwentieth];
denominator ← TwoToTheTwentieth;
};
Parameter: PUBLIC PROCEDURE [key: Key, index: Tfm.ParamIndex] RETURNS [parameterValue: REAL] = TRUSTED {
file: UFFileManager.FontFile ← UFFileManager.Open[key,OpenInit];
data: Data ← NARROW[file.GetData[]];
parameterValue ← IF LOOPHOLE[index, CARDINAL] > data.dirPtr.np THEN 0.0 ELSE FixedToReal[data.paramPtr[index]];
};
FontFormattingClass interface
FONT: TYPE = Font.FONT;
LigatureOrKern: TYPE = Font.LigatureOrKern;
Box: TYPE = Font.Box;
VecMag: PROC [x, y: REAL] RETURNS [REAL] = {RETURN[Real.SqRt[x*x + y*y]]};
TFMLigKern: PROCEDURE [font: FONT, char1, char2: CHAR] RETURNS [ligatureOrKern: LigatureOrKern] = {
ligKern: LigatureOrKern ← LigKern[font.formattingKey, char1, char2];
WITH lg: ligKern SELECT FROM
kern => {
scale: REALIF font.actualTransformation.b = 0 THEN font.actualTransformation.e ELSE VecMag[font.actualTransformation.b, font.actualTransformation.e];
RETURN[[kern[lg.kernAmount*scale]]]
};
ENDCASE => RETURN[ligKern];
};
TFMFormattingBox: PROCEDURE [font: FONT, char: CHAR] RETURNS [box: Box] = {
s: REALIF font.actualTransformation.b = 0 THEN font.actualTransformation.e ELSE VecMag[font.actualTransformation.b, font.actualTransformation.e];
box.xmin ← 0;
box.xmax ← Width[font.formattingKey, char]*s;
box.ymin ← - Depth[font.formattingKey, char]*s;
box.ymax ← Height[font.formattingKey, char]*s;
};
TFMFormattingMetric: PROCEDURE [font: FONT, metric: ATOM, char: CHAR] RETURNS [REAL] = {
RETURN[0.0];
};
TFMObjectInit: PROCEDURE [font: FONT] = {
font.fontFormattingClass ← TFMClass;
};
TFMClass: REF Font.FontFormattingClassRec ← NEW[Font.FontFormattingClassRec ← [
formattingBoxProc: TFMFormattingBox,
ligKernProc: TFMLigKern,
formattingMetricProc: TFMFormattingMetric
]];
Font.RegisterFontFormattingClass[$Tfm, TFMObjectInit];
END.