DIRECTORY Basics USING [BYTE, bytesPerWord], CountedVM USING [Allocate, Handle], FS USING [OpenFile, StreamFromOpenFile], Imager USING [ConcatT, Context, DoSave, MaskBits, RotateT], ImagerFont USING [CorrectionType, Extents, nullXChar, XChar], ImagerTransformation USING [ApplyPreRotate, Rectangle, Scale2, Transformation, TransformRectangle, TransformVec], ImagerTypeface USING [Register, Typeface, TypefaceClass, TypefaceClassRep, TypefaceRep], IO USING [Close, SetIndex, STREAM, UnsafeGetBlock], PrePressFontFormat USING [CardFromBcpl, CharacterData, CharacterIndexEntry, CharDataArray, DirectoryArray, IntFromBcpl, IXHeader, missingCharacter, missingFilePos, NameIndexEntry, RasterDefn, RelFilePos], Real USING [FScale], Vector2 USING [VEC]; ImagerACTypefaceImpl: CEDAR PROGRAM IMPORTS CountedVM, FS, Imager, ImagerTransformation, ImagerTypeface, IO, PrePressFontFormat, Real ~ BEGIN OPEN ImagerTypeface, ImagerFont; BYTE: TYPE ~ [0..377B]; VEC: TYPE ~ Vector2.VEC; Transformation: TYPE ~ ImagerTransformation.Transformation; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD[ bc, ec: BYTE _ 0, charData: LONG POINTER TO PrePressFontFormat.CharDataArray _ NIL, directory: LONG POINTER TO PrePressFontFormat.DirectoryArray _ NIL, pixelToChar: Transformation _ NIL, vm: CountedVM.Handle _ NIL ]; 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]; }; ACCreate: PROC [file: FS.OpenFile] RETURNS [Typeface] ~ { data: Data ~ NEW[DataRep _ []]; stream: IO.STREAM ~ FS.StreamFromOpenFile[file]; ix: PrePressFontFormat.IXHeader; ixSize: NAT ~ SIZE[PrePressFontFormat.IXHeader]; name: PrePressFontFormat.NameIndexEntry; index: PrePressFontFormat.CharacterIndexEntry; nameFound, indexFound: BOOL _ FALSE; segmentIndex, segmentWords: INT _ 0; 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 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 data.bc _ index.bc; data.ec _ index.ec; segmentIndex _ PrePressFontFormat.CardFromBcpl[index.segmentSA]; -- in words! segmentWords _ PrePressFontFormat.CardFromBcpl[index.segmentLength]; data.vm _ CountedVM.Allocate[words: segmentWords]; SetWordIndex[stream, segmentIndex]; TRUSTED { -- read segment base: LONG POINTER ~ data.vm.pointer; ReadWords[stream, base, segmentWords]; data.charData _ base; data.directory _ base+SIZE[PrePressFontFormat.CharDataArray[index.ec-index.bc+1]]; }; IO.Close[stream]; charUnitsPerResolutionUnit _ 25400.0/index.size; -- units of resolution are dots per 10 inches data.pixelToChar _ ImagerTransformation.Scale2[[ charUnitsPerResolutionUnit/index.resolutionX, charUnitsPerResolutionUnit/index.resolutionY ]]; IF index.rotation#0 THEN data.pixelToChar.ApplyPreRotate[-index.rotation/60.0]; RETURN[NEW[TypefaceRep _ [class: acClass, data: data]]]; }; ACContains: PROC [self: Typeface, char: XChar] RETURNS [BOOL] ~ { data: Data ~ NARROW[self.data]; IF char.set=0 AND char.code IN[data.bc..data.ec] THEN { index: NAT ~ char.code-data.bc; cd: PrePressFontFormat.CharacterData; TRUSTED { cd _ data.charData[index] }; RETURN[cd.bbdy#PrePressFontFormat.missingCharacter]; }; RETURN[FALSE]; }; ACNextChar: PROC [self: Typeface, char: XChar] RETURNS [next: XChar] ~ { data: Data ~ NARROW[self.data]; start: BYTE _ 0; IF char=nullXChar THEN NULL ELSE IF char.set=0 AND char.codefxmax THEN fxmax _ xmax; IF ymax>fymax THEN fymax _ ymax; }; count _ count+1; }; ENDLOOP; RETURN[[leftExtent: -fxmin, rightExtent: fxmax, descent: -fymin, ascent: fymax]]; }; ACKern: PROC [self: Typeface, char, successor: XChar] RETURNS [VEC] ~ { RETURN[[0, 0]]; }; ACNextKern: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ { RETURN[nullXChar]; }; ACLigature: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ { RETURN[nullXChar]; }; ACNextLigature: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ { RETURN[nullXChar]; }; ACMask: PROC [self: Typeface, char: XChar, context: Imager.Context] ~ { data: Data ~ NARROW[self.data]; IF char.set=0 AND char.code IN[data.bc..data.ec] THEN { index: NAT ~ char.code-data.bc; cd: PrePressFontFormat.CharacterData; TRUSTED { cd _ data.charData[index] }; IF cd.bbdy#PrePressFontFormat.missingCharacter THEN { raster, lines: NAT; base: LONG POINTER _ NIL; TRUSTED { defn: LONG POINTER TO PrePressFontFormat.RasterDefn _ NIL; filePos: PrePressFontFormat.RelFilePos ~ data.directory[index]; offset: INT ~ PrePressFontFormat.IntFromBcpl[filePos]; IF filePos=PrePressFontFormat.missingFilePos THEN ERROR MalformedACFont; defn _ LOOPHOLE[data.directory+offset]; [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.RotateT[context, 90]; Imager.ConcatT[context, data.pixelToChar]; Imager.MaskBits[context: context, base: base, wordsPerLine: raster, sMin: 0, fMin: 0, sSize: cd.bbdx, fSize: cd.bbdy, tx: cd.bboy, ty: -cd.bbox]; }; Imager.DoSave[context, action]; }; }; }; }; acClass: TypefaceClass ~ NEW[TypefaceClassRep _ [ type: $AC, Contains: ACContains, NextChar: ACNextChar, Width: ACWidth, Amplified: ACAmplified, Correction: ACCorrection, BoundingBox: ACBoundingBox, FontBoundingBox: ACFontBoundingBox, Ligature: ACLigature, NextLigature: ACNextLigature, Kern: ACKern, NextKern: ACNextKern, Mask: ACMask ]]; ImagerTypeface.Register["AC", ACCreate]; END. ˆImagerACTypefaceImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Doug Wyatt, May 29, 1985 10:58:54 am PDT Κ Έ˜codešœ™Kšœ Οmœ1™Kšœ žœ ˜Kšœžœ˜Kšœžœ˜%šžœžœžœž˜&Kšœžœ˜Kšœ%˜%Kšžœ˜&šžœ-žœ˜5Kšœ{˜{Kšœžœžœ ˜'Kšœžœžœ ˜'Kšžœ žœ;˜Jšžœ˜Kšžœ žœ˜ Kšžœ žœ˜ Kšžœ žœ˜ Kšžœ žœ˜ K˜—K˜K˜—Kšžœ˜—KšžœK˜QK˜K˜—š œžœ*žœžœ˜GKšžœ ˜K˜K˜—š  œžœ*žœ ˜MKšžœ ˜K˜K˜—š  œžœ*žœ ˜MKšžœ ˜K˜K˜—š œžœ*žœ ˜QKšžœ ˜K˜K˜—š œžœ;˜GKšœ žœ ˜šžœ žœ žœžœ˜7Kšœžœ˜Kšœ%˜%Kšžœ˜&šžœ-žœ˜5Kšœžœ˜Kšœžœžœžœ˜šžœ˜ Kš œžœžœžœ!žœ˜:Kšœ?˜?Kšœžœ+˜6Kšžœ+žœžœ˜HKšœžœ˜'Kšœ'˜'Kšœ žœ ˜0K˜—Kšžœžœžœž˜5Kšžœžœ‘'˜Cšžœ žœ žœ˜!šœžœ˜Kšœ˜Kšœ*˜*Kšœ’˜’K˜—Kšœ˜K˜—K˜—K˜—K˜K˜—šœžœ˜1K˜ Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ#˜#Kšœ˜Kšœ˜Kšœ ˜ Kšœ˜Kšœ ˜ K˜K˜—Kšœ(˜(K˜Kšžœ˜—…—#ό/<