UFTfmReaderImpl.mesa
Last changed by Michael Plass, February 15, 1984 8:48:33 am PST
Last changed by Doug Wyatt, September 30, 1983 5:54 pm
DIRECTORY
ImagerTransform,
Font,
Real USING [MinusZero, SqRt],
RefText USING [ObtainScratch, ReleaseScratch],
Rope USING [FromRefText, ROPE],
UFTfm,
UFFileManager USING [FontFile, GetData, InBounds, InitProc, Open, Pointer],
UFTfmReader;
UFTfmReaderImpl:
CEDAR PROGRAM
IMPORTS ImagerTransform, Font, Real, RefText, Rope, UFTfm, 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: UFTfm.Fixed]
RETURNS [
REAL] =
{RETURN[UFTfm.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 UFTfm.Directory,
headerPtr: LONG POINTER TO UFTfm.Header,
fInfoDesc: LONG DESCRIPTOR FOR ARRAY OF UFTfm.FInfoEntry,
widthDesc: LONG DESCRIPTOR FOR ARRAY OF UFTfm.Fixed,
heightDesc: LONG DESCRIPTOR FOR ARRAY OF UFTfm.Fixed,
depthDesc: LONG DESCRIPTOR FOR ARRAY OF UFTfm.Fixed,
charIcDesc: LONG DESCRIPTOR FOR ARRAY OF UFTfm.Fixed,
ligKernDesc: LONG DESCRIPTOR FOR ARRAY OF UFTfm.LigKernEntry,
kernDesc: LONG DESCRIPTOR FOR ARRAY OF UFTfm.Fixed,
extenDesc: LONG DESCRIPTOR FOR ARRAY OF UFTfm.ExtRecipe,
paramPtr: LONG POINTER TO UFTfm.Param
];
OpenInit: UFFileManager.InitProc =
TRUSTED {
base: LONG POINTER ← fontFile.Pointer[];
dir: LONG POINTER TO UFTfm.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[UFTfm.Word];
IF
NOT fontFile.InBounds[dir,
SIZE[UFTfm.Directory]]
THEN
ERROR Font.BadFontFileFormat;
IF
NOT UFTfm.ValidDirectory[dir^]
THEN
ERROR Font.BadFontFileFormat;
IF
NOT fontFile.InBounds[base, dir.lf]
THEN
ERROR Font.BadFontFileFormat;
data.dirPtr ← Next[SIZE[UFTfm.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: UFTfm.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: UFTfm.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: UFTfm.FInfoEntry[lig] => {
FOR i:
NAT ← ligFInfoEntry.ligKernStart, i+1
DO
ligKernEntry: UFTfm.LigKernEntry ← data.ligKernDesc[i];
IF ligKernEntry.nextChar = char2
THEN RETURN[
WITH ligKernEntry
SELECT
FROM
ligEntry: UFTfm.LigKernEntry[lig] => [ligature[ligatureCode: ligEntry.ligCode]],
kernEntry: UFTfm.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 ← UFTfm.Long[data.paramPtr[slant].ValueTimesTwoToTheTwentieth];
denominator ← TwoToTheTwentieth;
};
Parameter:
PUBLIC
PROCEDURE [key: Key, index: UFTfm.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: REAL ← IF font.actualTransformation.Contents.b = 0 THEN font.actualTransformation.Contents.e ELSE VecMag[font.actualTransformation.Contents.b, font.actualTransformation.Contents.e];
RETURN[[kern[lg.kernAmount*scale]]]
};
ENDCASE => RETURN[ligKern];
};
TFMFormattingBox:
PROCEDURE [font:
FONT, char:
CHAR]
RETURNS [box: Box] = {
s: REAL ← IF font.actualTransformation.Contents.b = 0 THEN font.actualTransformation.Contents.e ELSE VecMag[font.actualTransformation.Contents.b, font.actualTransformation.Contents.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.