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]; 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]]; }; 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.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: REAL _ IF 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. ΊUFTfmReaderImpl.mesa Last changed by Michael Plass, February 3, 1983 3:17 pm Last changed by Doug Wyatt, September 30, 1983 5:54 pm Make some ropes FontFormattingClass interface Κ ž˜Jšœ™Jšœ8™8Jšœ6™6unitšΟk ˜ Jšœ˜Jšœœ˜Jšœœ!˜.Jšœœœ˜Jšœ˜Jšœœ8˜KJšœ ˜ —šœ ˜Jšœ.˜5Jšœ˜—Jšœœ ˜Kšœœ˜+Jšœœ˜5Jšœœ˜0šΟn œ œœœ˜6Jšœœ%˜,—Kšžœ œœœœœœ˜KKšœœœ ˜šœ œœ˜Jšœœ˜!Jšœ œ˜Jšœœœœ˜&Jšœ œœœ ˜&Jš œ œ œœœœ˜7Jš œ œ œœœœ ˜2Jš œ œ œœœœ ˜3Jš œ œ œœœœ ˜2Jš œ œ œœœœ ˜3Jš œ œ œœœœ˜;Jš œ œ œœœœ ˜1Jš œ œ œœœœ˜6Jšœ œœœ ˜#Jšœ˜—šœ#œ˜,Jšœœœ˜(Jšœœœœ˜*Jšœ œ ˜Jšœœœ˜Jšžœœœœœœœ œ&˜iJšœœœ ˜šœœœ˜7Jšœ˜—šœœ˜$Jšœ˜—šœœ!˜+Jšœ˜—Jšœœ˜(Jšœ ˜ Jšœ œ1˜LJšœ œ˜6Jšœ œ˜7Jšœ œ˜6Jšœ œ˜7Jšœ œ˜8Jšœ œ˜5Jšœ œ˜6Jšœ˜™Jš˜Jšœœœ˜+Jšœ;˜;šœœœ˜!Jšœ4˜4Jš˜—Jšœ4˜4Jšœ<˜<šœœœ˜!Jšœ5˜5Jš˜—Jšœ%˜%Jšœ˜Jš˜—Jšœ˜ Jšœ˜—š žœœ œ œœ˜NJšœ@˜@Jšœ œ˜$Jšœ#˜#Jšœ˜—š žœœ œ œœ˜aJšœ@˜@Jšœ œ˜$Jšœ3˜3Jšœ˜—š žœœ œ œœ˜CJšœ@˜@Jšœ œ˜$Jšœ˜Jšœ˜—š ž œœ œ œœœ˜NJšœ@˜@Jšœ œ˜$Jšœ4˜4Jšœ˜—š žœœ œ œœ˜FJšœ@˜@Jšœ œ˜$Jšœ-˜-Jšœ˜—š žœœ œ œ œœ˜EJšœ@˜@Jšœ œ˜$Jšœ˜Jšœ˜Jšœ˜—Kšœ8˜8šžœœ œœœœœ˜OJšœ@˜@Jšœ œ˜$Jš œœœœœœ˜XJšœ<˜BJšœ˜—šžœœ œœœ œœ˜PJšœ@˜@Jšœ œ˜$Jš œœ œ#œœ˜TJšœY˜YJšœ˜—šžœœ œœœ œœ˜RJšœ@˜@Jšœ œ˜$Jš œœ œ#œœ˜TJšœ\˜\Jšœ˜—šžœœ œœœ œœ˜PJšœ@˜@Jšœ œ˜$Jš œœ œ#œœ˜TJšœY˜YJšœ˜—šžœœ œœœœœ˜fJšœ@˜@Jšœ œ˜$Jš œœ œ#œœ˜TJšœf˜fJšœ˜—šžœœ œœ˜8šœ$œ˜4Jšœ@˜@Jšœ œ˜$Jšœœ œ"œ œ#œœ˜…šœ+œ˜:šœ'˜'šœœ#˜/Jšœ5˜5šœ œ˜-šœœ˜JšœN˜NJšœi˜iJšœ˜—Jšœ˜—Jšœœœ˜.Jš˜—Jšœ˜—Jšœœ˜—Jšœ˜——š žœœ œ œœœ˜TJšœ@˜@Jšœ œ˜$JšœG˜GJšœ ˜ Jšœ˜—š ž œœ œ#œœœ˜hJšœ@˜@Jšœ œ˜$Jš œœœœœœ#˜oJšœ˜—šΟbž Ÿ™Kšœœœ˜Kšœœ˜+Kšœœ ˜Kš žœœœœœœ˜Jš ž œ œœœœ%˜cJšœD˜Dšœ œ˜šœ ˜ Jš œœœ!œœB˜˜Jšœ˜#Jšœ˜—Jšœœ ˜—Jšœ˜—š žœ œœœœ˜KJš œœœ!œœB˜”J˜ Jšœ-˜-Jšœ/˜/Jšœ.˜.Jšœ˜—šžœ œœ œœœœ˜XJšœ˜ Jšœ˜—šž œ œœ˜)Jšœ$˜$Jšœ˜—šœ œœ ˜OJšœ$˜$Jšœ˜Jšœ)˜)J˜—Kšœ6˜6—Kšœ˜—…—#°/