DIRECTORY Basics USING [bytesPerWord], CountedVM USING [Allocate, Handle, Pointer], ImagerFont USING [Char, Class, ClassRep, CorrectionType, Extents, Font, FontRep, nullChar, OptionalReal], FS USING [StreamOpen], Imager USING [Class, ConcatT, Context, DoSave, MaskBits], ImagerTransformation USING [Concat, PreRotate, Rectangle, Scale, Scale2, Transformation, TransformRectangle, TransformVec], IO USING [Close, SetIndex, STREAM, UnsafeGetBlock], PrePressFontFormat USING [CardFromDouble, CharacterData, CharacterIndexEntry, CharDataArray, DirectoryArray, FractionFromDouble, IXHeader, missingCharacter, missingFilePos, NameIndexEntry, RasterDefn], Rope USING [FromProc, ROPE], Scaled USING [Float, Value], Vector2 USING [VEC]; ImagerACFontImpl: CEDAR PROGRAM IMPORTS CountedVM, FS, Imager, ImagerTransformation, IO, PrePressFontFormat, Rope, Scaled ~ BEGIN BYTE: TYPE ~ [0..377B]; ROPE: TYPE ~ Rope.ROPE; VEC: TYPE ~ Vector2.VEC; Transformation: TYPE ~ ImagerTransformation.Transformation; Font: TYPE ~ ImagerFont.Font; FontRep: TYPE ~ ImagerFont.FontRep; Char: TYPE ~ ImagerFont.Char; -- CARDINAL nullChar: Char ~ ImagerFont.nullChar; CorrectionType: TYPE ~ ImagerFont.CorrectionType; -- {none, space, mask}; Extents: TYPE ~ ImagerFont.Extents; -- RECORD[leftExtent, rightExtent, descent, ascent: REAL]; OptionalReal: TYPE ~ ImagerFont.OptionalReal; -- RECORD[exists: BOOLEAN, value: REAL]; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD[ file: ACFile, pixelToClient: Transformation ]; ACFile: TYPE ~ REF ACFileRep; ACFileRep: TYPE ~ RECORD[ bc, ec: BYTE, charData: LONG POINTER TO PrePressFontFormat.CharDataArray, directory: LONG POINTER TO PrePressFontFormat.DirectoryArray, pixelToChar: Transformation, vm: CountedVM.Handle ]; MalformedACFont: ERROR ~ CODE; ReadWords: UNSAFE PROC[stream: IO.STREAM, base: LONG POINTER, words: INT] ~ UNCHECKED { count: INT ~ words*Basics.bytesPerWord; IF IO.UnsafeGetBlock[stream, [base: base, count: count]]=count THEN NULL ELSE ERROR MalformedACFont; -- file too short }; SetWordIndex: PROC[stream: IO.STREAM, wordIndex: INT] ~ { index: CARDINAL ~ wordIndex*Basics.bytesPerWord; IO.SetIndex[stream, index]; }; Open: PROC[fileName: ROPE] RETURNS[ACFile] ~ { stream: IO.STREAM ~ FS.StreamOpen[fileName]; ix: PrePressFontFormat.IXHeader; ixSize: NAT ~ SIZE[PrePressFontFormat.IXHeader]; name: PrePressFontFormat.NameIndexEntry; index: PrePressFontFormat.CharacterIndexEntry; nameFound, indexFound: BOOL _ FALSE; family: ROPE _ NIL; segmentIndex, segmentWords: INT _ 0; vm: CountedVM.Handle _ NIL; charData, directory: LONG POINTER _ NIL; charUnitsPerResolutionUnit: REAL _ 0; pixelToChar: Transformation _ NIL; DO -- read the index part TRUSTED { ReadWords[stream, @ix, SIZE[PrePressFontFormat.IXHeader]] }; SELECT ix.type FROM end => EXIT; name => { IF nameFound THEN ERROR MalformedACFont; -- more than one name entry IF (ix.length-ixSize)=SIZE[PrePressFontFormat.NameIndexEntry] THEN TRUSTED { ReadWords[stream, @name, SIZE[PrePressFontFormat.NameIndexEntry]] } ELSE ERROR MalformedACFont; -- wrong ix.length { -- convert name to rope i: NAT _ 0; p: PROC RETURNS[CHAR] ~ { RETURN[VAL[name.chars[i _ i+1]]] }; family _ Rope.FromProc[len: name.chars[0], p: p]; }; nameFound _ TRUE; }; character => { IF indexFound THEN ERROR MalformedACFont; -- more than one char index entry IF (ix.length-ixSize)=SIZE[PrePressFontFormat.CharacterIndexEntry] THEN TRUSTED { ReadWords[stream, @index, SIZE[PrePressFontFormat.CharacterIndexEntry]] } ELSE ERROR MalformedACFont; -- wrong ix.length indexFound _ TRUE; }; ENDCASE => ERROR MalformedACFont; -- unexpected ix type ENDLOOP; IF nameFound AND indexFound AND name.code=index.family THEN NULL ELSE ERROR MalformedACFont; -- index part has wrong form IF index.bc>index.ec THEN ERROR MalformedACFont; -- bc exceeds ec segmentIndex _ PrePressFontFormat.CardFromDouble[index.segmentSA]; -- in words! segmentWords _ PrePressFontFormat.CardFromDouble[index.segmentLength]; vm _ CountedVM.Allocate[words: segmentWords]; SetWordIndex[stream, segmentIndex]; TRUSTED { -- read segment base: LONG POINTER ~ CountedVM.Pointer[vm]; ReadWords[stream, base, segmentWords]; charData _ base; directory _ charData+SIZE[PrePressFontFormat.CharDataArray[index.ec-index.bc+1]]; }; IO.Close[stream]; charUnitsPerResolutionUnit _ 25400.0/index.size; -- units of resolution are dots per 10 inches pixelToChar _ ImagerTransformation.Scale2[[ charUnitsPerResolutionUnit/index.resolutionX, charUnitsPerResolutionUnit/index.resolutionY ]]; IF index.rotation#0 THEN pixelToChar.PreRotate[-index.rotation/60.0]; RETURN[NEW[ACFileRep _ [bc: index.bc, ec: index.ec, charData: charData, directory: directory, pixelToChar: pixelToChar, vm: vm]]]; }; Find: PROC[name: ROPE] RETURNS[Font] ~ { file: ACFile ~ Open[name]; charToClient: Transformation ~ ImagerTransformation.Scale[1]; data: Data ~ NEW[DataRep _ [file: file, pixelToClient: file.pixelToChar]]; RETURN[NEW[ImagerFont.FontRep _ [class: class, data: data, name: name, charToClient: charToClient, props: NIL]]]; }; Modify: PROC[font: Font, m: Transformation] RETURNS[Font] ~ { data: Data ~ NARROW[font.data]; file: ACFile ~ data.file; charToClient: Transformation ~ font.charToClient.Concat[m]; pixelToClient: Transformation ~ file.pixelToChar.Concat[charToClient]; newData: Data ~ NEW[DataRep _ [file: file, pixelToClient: pixelToClient]]; RETURN[NEW[FontRep _ [class: class, data: newData, name: font.name, charToClient: charToClient, props: NIL]]]; }; Contains: PROC[font: Font, char: Char] RETURNS[BOOL] ~ { data: Data ~ NARROW[font.data]; file: ACFile ~ data.file; IF char IN[file.bc..file.ec] THEN { cd: PrePressFontFormat.CharacterData; TRUSTED { cd _ file.charData[char-file.bc] }; RETURN[cd.bbdy#PrePressFontFormat.missingCharacter]; }; RETURN[FALSE]; }; NextChar: PROC[font: Font, char: Char] RETURNS[next: Char] ~ { data: Data ~ NARROW[font.data]; file: ACFile ~ data.file; start: Char; SELECT char FROM =nullChar => start _ file.bc; start _ file.bc; start _ char+1; ENDCASE => RETURN[nullChar]; FOR probe: Char IN[start..file.ec] DO cd: PrePressFontFormat.CharacterData; TRUSTED { cd _ file.charData[probe-file.bc] }; IF cd.bbdy#PrePressFontFormat.missingCharacter THEN RETURN[probe]; ENDLOOP; RETURN[nullChar]; }; BoundingBox: PROC[font: Font, char: Char] RETURNS[Extents] ~ { data: Data ~ NARROW[font.data]; file: ACFile ~ data.file; IF char IN[file.bc..file.ec] THEN { cd: PrePressFontFormat.CharacterData; TRUSTED { cd _ file.charData[char-file.bc] }; IF cd.bbdy#PrePressFontFormat.missingCharacter THEN { r: ImagerTransformation.Rectangle ~ ImagerTransformation.TransformRectangle[ data.pixelToClient, [x: cd.bbox, y: cd.bboy, w: cd.bbdx, h: cd.bbdy]]; RETURN[[leftExtent: -r.x, rightExtent: r.x+r.w, descent: -r.y, ascent: r.y+r.h]]; }; }; RETURN[[0, 0, 0, 0]]; }; Width: PROC[font: Font, char: Char] RETURNS[VEC] ~ { data: Data ~ NARROW[font.data]; file: ACFile ~ data.file; IF char IN[file.bc..file.ec] THEN { cd: PrePressFontFormat.CharacterData; TRUSTED { cd _ file.charData[char-file.bc] }; IF cd.bbdy#PrePressFontFormat.missingCharacter THEN { wx: Scaled.Value ~ PrePressFontFormat.FractionFromDouble[cd.wx]; wy: Scaled.Value ~ PrePressFontFormat.FractionFromDouble[cd.wy]; RETURN[data.pixelToClient.TransformVec[[Scaled.Float[wx], Scaled.Float[wy]]]]; }; }; RETURN[[0, 0]]; }; Amplified: PROC[font: Font, char: Char] RETURNS[BOOL] ~ { RETURN[char=40B]; }; Correction: PROC[font: Font, char: Char] RETURNS[CorrectionType] ~ { data: Data ~ NARROW[font.data]; file: ACFile ~ data.file; IF char IN[file.bc..file.ec] THEN { IF char=40B THEN RETURN[space] ELSE RETURN[mask]; }; RETURN[none]; }; Kern: PROC[font: Font, char, successor: Char] RETURNS[VEC] ~ { RETURN[[0, 0]]; }; NextKern: PROC[font: Font, char, successor: Char] RETURNS[Char] ~ { RETURN[nullChar]; }; Ligature: PROC[font: Font, char, successor: Char] RETURNS[Char] ~ { RETURN[nullChar]; }; NextLigature: PROC[font: Font, char, successor: Char] RETURNS[Char] ~ { RETURN[nullChar]; }; CharInfo: PROC[font: Font, char: Char, key: ATOM] RETURNS[OptionalReal] ~ { RETURN[[FALSE, 0]]; }; missingOffset: LONG CARDINAL ~ PrePressFontFormat.CardFromDouble[PrePressFontFormat.missingFilePos]; MaskChar: PROC[font: Font, char: Char, imager: REF] ~ { context: Imager.Context ~ NARROW[imager]; data: Data ~ NARROW[font.data]; file: ACFile ~ data.file; IF char IN[file.bc..file.ec] THEN { cd: PrePressFontFormat.CharacterData; TRUSTED { cd _ file.charData[char-file.bc] }; IF cd.bbdy#PrePressFontFormat.missingCharacter THEN { raster, lines: NAT; base: LONG POINTER _ NIL; TRUSTED { defn: LONG POINTER TO PrePressFontFormat.RasterDefn _ NIL; fp: LONG CARDINAL ~ PrePressFontFormat.CardFromDouble[file.directory[char-file.bc]]; IF fp#missingOffset THEN defn _ LOOPHOLE[file.directory+fp] ELSE ERROR MalformedACFont; [raster: raster, lines: lines] _ defn^; base _ defn+SIZE[PrePressFontFormat.RasterDefn]; }; IF lines=cd.bbdx AND raster=(cd.bbdy+15)/16 THEN NULL ELSE ERROR MalformedACFont; -- raster and bounding box inconsistent IF cd.bbdx>0 AND cd.bbdy>0 THEN { action: PROC ~ { Imager.ConcatT[context, data.pixelToClient]; Imager.MaskBits[context: context, base: base, wordsPerLine: raster, sMin: 0, fMin: 0, sSize: cd.bbdx, fSize: cd.bbdy, sOffset: cd.bbox, fOffset: cd.bboy]; }; Imager.DoSave[context, action]; }; }; }; }; class: ImagerFont.Class ~ NEW[ImagerFont.ClassRep _ [ Modify: Modify, Contains: Contains, NextChar: NextChar, Width: Width, Amplified: Amplified, Correction: Correction, BoundingBox: BoundingBox, Ligature: Ligature, NextLigature: NextLigature, Kern: Kern, NextKern: NextKern, CharInfo: CharInfo, MaskChar: MaskChar ]]; END. ImagerACFontImpl.mesa Copyright c 1984, Xerox Corporation. All rights reserved. Doug Wyatt, November 30, 1984 2:14:56 pm PST name: ROPE, transformation: Transformation, class: Class, data: REF, propList: REF ImagerFont.Register["Xerox/AC", Find]; Ê „˜Jšœ™šœ Ïmœ/™:J™,—J™šÏk ˜ Jšœžœ˜Jšœ žœ˜,Jšœ žœY˜iJšžœžœ˜Jšœžœ-˜9Jšœžœa˜{Jšžœžœžœ˜3Jšœžœ±˜ÉJšœžœ žœ˜Jšœžœ˜Jšœžœžœ˜—J˜Jšœžœž˜Jšžœ žœ žœ"˜YJšœž˜J˜Jšžœžœ ˜J˜Jšžœžœžœ˜Jšžœžœ žœ˜Jšœžœ'˜;J˜Jšœžœ˜šœ žœ˜#Jšœžœ™ Jšœ™J™ Jšœžœ™ Jšœ ž™ J˜—JšœžœÏc ˜)šœ%˜%J˜—šœžœŸ˜IJ˜—šœ žœŸ:˜^J˜—šœžœŸ(˜VJ˜—Jšœžœžœ ˜šœ žœžœ˜Jšœ ˜ Jšœ˜J˜J˜—Jšœžœžœ ˜šœ žœžœ˜Jšœžœ˜ Jšœ žœžœžœ"˜;Jšœ žœžœžœ#˜=Jšœ˜J˜J˜J˜—Jšœžœžœ˜J˜šÏn œžœžœ žœžœžœžœ žœž œ˜WJšœžœ˜'Jšžœžœ:žœž˜HJšžœžœŸ˜-J˜J˜—š   œžœ žœžœ žœ˜9Jšœžœ!˜0Jšžœ˜J˜J˜—š œžœ žœžœ ˜.Jšœžœžœžœ˜,J˜ Jšœžœžœ˜0Jšœ(˜(Jšœ.˜.Jšœžœžœ˜$Jšœžœžœ˜Jšœžœ˜$Jšœžœ˜Jšœžœžœžœ˜(Jšœžœ˜%Jšœžœ˜"šžœŸ˜Jšžœžœ!˜Fšžœ ž˜Jšœžœ˜ šœ ˜ Jšžœ žœžœŸ˜Dšžœžœ$žœžœ˜LJšœžœ&˜C—JšžœžœŸ˜.šœŸ˜Jš œžœ žœžœžœžœžœ˜IJšœ1˜1J˜—Jšœ žœ˜J˜—šœ˜Jšžœ žœžœŸ!˜Kšžœžœ)žœžœ˜QJšœžœ+˜I—JšžœžœŸ˜.Jšœ žœ˜J˜—JšžœžœŸ˜7—Jšžœ˜—Jš žœ žœ žœžœž˜@JšžœžœŸ˜8JšžœžœžœŸ˜AJšœCŸ ˜OJšœF˜FJšœ-˜-Jšœ#˜#šžœŸ˜Jšœžœžœ˜+Jšœ&˜&J˜Jšœžœ8˜QJ˜—Jšžœ˜Jšœ1Ÿ-˜^šœ+˜+Jšœ-˜-Jšœ,˜,Jšœ˜—Jšžœžœ-˜Ešžœžœ)˜3JšœN˜N—J˜J˜—š œžœžœžœ ˜(J˜Jšœ=˜=Jšœ žœ:˜Jšžœžœ0˜:Jšœ/žœ˜6—J˜J˜—š œžœ žœ ˜=Jšœ žœ ˜Jšœ˜Jšœ;˜;JšœF˜FJšœžœ7˜Jšžœžœ(˜2Jšœ4žœ˜;—J˜J˜—š œžœžœžœ˜8Jšœ žœ ˜Jšœ˜šžœžœžœ˜#Jšœ%˜%Jšžœ&˜-Jšžœ.˜4J˜—Jšžœžœ˜J˜J˜—š œžœžœ˜>Jšœ žœ ˜Jšœ˜J˜ šžœž˜Jšœ˜Jšœ˜Jšœ˜Jšžœžœ ˜—šžœ žœž˜%Jšœ%˜%Jšžœ'˜.Jšžœ-žœžœ˜BJšžœ˜—Jšžœ ˜J˜J˜—š  œžœžœ ˜>Jšœ žœ ˜Jšœ˜šžœžœžœ˜#Jšœ%˜%Jšžœ&˜-šžœ-žœ˜5šœL˜LJšœF˜F—JšžœK˜QJ˜—J˜—Jšžœ˜J˜J˜—š œžœžœžœ˜4Jšœ žœ ˜Jšœ˜šžœžœžœ˜#Jšœ%˜%Jšžœ&˜-šžœ-žœž˜5Jšœ@˜@Jšœ@˜@JšžœH˜NJ˜—J˜—Jšžœ ˜J˜J˜—š  œžœžœžœ˜9Jšžœ ˜J˜J˜—š  œžœžœ˜DJšœ žœ ˜Jšœ˜šžœžœžœ˜#Jš žœ žœžœžœžœ˜1J˜—Jšžœ˜ J˜J˜—š œžœ$žœžœ˜>Jšžœ ˜J˜J˜—š œžœ$žœ ˜CJšžœ ˜J˜J˜—š œžœ$žœ ˜CJšžœ ˜J˜J˜—š  œžœ$žœ ˜GJšžœ ˜J˜J˜—š œžœžœžœ˜KJšžœžœ˜J˜J˜—šœžœžœ˜JšœE˜EJ˜—š œžœ!žœ˜7Jšœžœ ˜)Jšœ žœ ˜Jšœ˜šžœžœžœ˜#Jšœ%˜%Jšžœ&˜-šžœ-žœž˜5Jšœžœ˜Jšœžœžœžœ˜šžœ˜ Jš œžœžœžœ!žœ˜:JšœžœžœC˜TJšžœžœžœ˜;Jšžœžœ˜Jšœ'˜'Jšœ žœ ˜0J˜—Jšžœžœžœž˜5JšžœžœŸ'˜Cšžœ žœ žœ˜!šœžœ˜Jšœ,˜,šœC˜CJšœV˜V—J˜—Jšœ˜J˜—J˜—J˜—J˜J˜—šœžœ˜5Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜J˜J˜—Jšœ&™&J˜Jšžœ˜—…—%Ò2V