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]; 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]]; }; 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. ΐ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 Make some ropes FontFormattingClass interface Κ ‘˜Jšœ™Jšœ?™?Jšœ6™6unitšΟk ˜ J˜Jšœ˜Jšœœ˜Jšœœ!˜.Jšœœœ˜Jšœ˜Jšœœ8˜KJšœ ˜ —šœ ˜JšœA˜HJšœ˜—Jšœœ ˜Kšœœ˜+Jšœœ˜5Jšœœ˜0šΟn œ œœœ˜8Jšœœ'˜.—Kšžœ œœœœœœ˜KKšœœœ ˜šœ œœ˜Jšœœ˜!Jšœ œ˜Jšœœœœ˜(Jšœ œœœ˜(Jš œ œ œœœœ˜9Jš œ œ œœœœ ˜4Jš œ œ œœœœ ˜5Jš œ œ œœœœ ˜4Jš œ œ œœœœ ˜5Jš œ œ œœœœ˜=Jš œ œ œœœœ ˜3Jš œ œ œœœœ˜8Jšœ œœœ ˜%Jšœ˜—šœ#œ˜,Jšœœœ˜(Jšœœœœ˜,Jšœ œ ˜Jšœœœ˜Jšžœœœœœœœ œ&˜iJšœœœ ˜šœœœ˜9Jšœ˜—šœœ˜&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šœ˜—š žœœ œ œœ˜PJšœ@˜@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šœ7˜7šœ œ˜-šœœ˜JšœP˜PJšœk˜kJšœ˜—Jšœ˜—Jšœœœ˜.Jš˜—Jšœ˜—Jšœœ˜—Jšœ˜——š žœœ œ œœœ˜TJšœ@˜@Jšœ œ˜$JšœI˜IJšœ ˜ Jšœ˜—š ž œœ œ%œœœ˜jJšœ@˜@Jšœ œ˜$Jš œœœœœœ#˜oJšœ˜—šΟbž Ÿ™Kšœœœ˜Kšœœ˜+Kšœœ ˜Kš žœœœœœœ˜Jš ž œ œœœœ%˜cJšœD˜Dšœ œ˜šœ ˜ Jš œœœ*œ&œT˜ΌJšœ˜#Jšœ˜—Jšœœ ˜—Jšœ˜—š žœ œœœœ˜KJš œœœ*œ&œT˜ΈJ˜ Jšœ-˜-Jšœ/˜/Jšœ.˜.Jšœ˜—šžœ œœ œœœœ˜XJšœ˜ Jšœ˜—šž œ œœ˜)Jšœ$˜$Jšœ˜—šœ œœ ˜OJšœ$˜$Jšœ˜Jšœ)˜)J˜—Kšœ6˜6—Kšœ˜—…—$P/±