DIRECTORY Basics USING [bytesPerWord], CountedVM USING [Allocate, Handle, Pointer, Words], ImagerFont USING [Char, Class, ClassRep, CorrectionType, Extents, Font, FontRep, nullChar, OptionalReal], FS USING [StreamOpen], Imager, ImagerTransformation, IO USING [Close, STREAM, UnsafeGetBlock], Rope USING [ROPE], StrikeFontFormat USING [Body, BoundingBox, Header, nullWidthEntry, WidthEntry, WTable, XTable], Vector2 USING [VEC]; ImagerStrikeFontImpl: CEDAR PROGRAM IMPORTS CountedVM, FS, Imager, ImagerTransformation, IO ~ BEGIN 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: StrikeFile, pixelToClient: Transformation ]; StrikeFile: TYPE ~ REF StrikeFileRep; StrikeFileRep: TYPE ~ RECORD[ min, max: CARDINAL, foffset: INTEGER, ascent, descent: INTEGER, strike: LONG POINTER, raster, lines: NAT, xtable: LONG POINTER TO StrikeFontFormat.XTable, wtable: LONG POINTER TO StrikeFontFormat.WTable, pixelToChar: Transformation, vm: CountedVM.Handle ]; MalformedStrikeFont: ERROR ~ CODE; ReadWords: UNSAFE PROC[stream: IO.STREAM, base: LONG POINTER, words: INT] ~ UNCHECKED { count: CARDINAL ~ words*Basics.bytesPerWord; IF IO.UnsafeGetBlock[stream, [base: base, count: count]]=count THEN NULL ELSE ERROR MalformedStrikeFont; -- file too short }; Open: PROC[fileName: ROPE, size: NAT] RETURNS[StrikeFile] ~ { stream: IO.STREAM ~ FS.StreamOpen[fileName]; header: StrikeFontFormat.Header; box: StrikeFontFormat.BoundingBox _ [0, 0, 0, 0]; body: StrikeFontFormat.Body; lines: NAT _ 0; vm: CountedVM.Handle _ NIL; strikeWords, xtableWords, wtableWords: NAT _ 0; vmWords: INT _ 0; strike, xtable, wtable: LONG POINTER _ NIL; pixelToChar: Transformation _ NIL; TRUSTED { -- read header ReadWords[stream, @header, SIZE[StrikeFontFormat.Header]]; }; IF header.oneBit=T AND header.index=F AND header.unused=0 AND header.min<=header.max AND header.max<256 THEN NULL ELSE ERROR MalformedStrikeFont; -- invalid header IF header.kerned=T THEN TRUSTED { -- if kerned, read font bounding box ReadWords[stream, @box, SIZE[StrikeFontFormat.BoundingBox]]; }; TRUSTED { -- read body prefix ReadWords[stream, @body, SIZE[StrikeFontFormat.Body]]; }; IF (body.ascent+body.descent)>0 THEN lines _ body.ascent+body.descent ELSE ERROR MalformedStrikeFont; -- nonpositive height IF header.kerned=T THEN { IF box.fbboy=-body.descent AND box.fbbdx>0 AND box.fbbdy=lines THEN NULL ELSE ERROR MalformedStrikeFont; -- font box is inconsistent }; strikeWords _ body.raster*lines; xtableWords _ header.max-header.min+3; IF body.length=CARDINAL[SIZE[StrikeFontFormat.Body]+strikeWords+xtableWords] THEN NULL ELSE ERROR MalformedStrikeFont; -- inconsistent lengths IF header.kerned=T THEN wtableWords _ header.max-header.min+2; vmWords _ LONG[strikeWords+xtableWords]+wtableWords; vm _ CountedVM.Allocate[words: vmWords]; TRUSTED { -- read remainder of file: strike, xtable, and wtable base: LONG POINTER ~ CountedVM.Pointer[vm]; IF vmWords<=CountedVM.Words[vm] THEN ReadWords[stream, base, vmWords] ELSE ERROR; -- CountedVM didn't allocate enough words!? strike _ base; xtable _ strike+strikeWords; IF wtableWords#0 THEN wtable _ xtable+xtableWords; }; IO.Close[stream]; pixelToChar _ ImagerTransformation.Rotate[-90]; pixelToChar.PreScale[1.0/size]; RETURN[NEW[StrikeFileRep _ [min: header.min, max: header.max, foffset: box.fbbox, ascent: body.ascent, descent: body.descent, strike: strike, raster: body.raster, lines: lines, xtable: xtable, wtable: wtable, pixelToChar: pixelToChar, vm: vm]]]; }; Find: PROC[name: ROPE] RETURNS[Font] ~ { file: StrikeFile ~ Open[name, 10 -- **** fix this ***** --]; 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: StrikeFile ~ 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: StrikeFile ~ data.file; w: StrikeFontFormat.WidthEntry _ StrikeFontFormat.nullWidthEntry; IF char IN[file.min..file.max] THEN TRUSTED { w _ file.wtable[char-file.min] }; RETURN[w#StrikeFontFormat.nullWidthEntry]; }; NextChar: PROC[font: Font, char: Char] RETURNS[next: Char] ~ { data: Data ~ NARROW[font.data]; file: StrikeFile ~ data.file; start: Char; SELECT char FROM =nullChar => start _ file.min; start _ file.min; start _ char+1; ENDCASE => RETURN[nullChar]; FOR probe: Char IN[start..file.max] DO w: StrikeFontFormat.WidthEntry; TRUSTED { w _ file.wtable[probe-file.min] }; IF w#StrikeFontFormat.nullWidthEntry THEN RETURN[probe]; ENDLOOP; RETURN[nullChar]; }; BoundingBox: PROC[font: Font, char: Char] RETURNS[Extents] ~ { data: Data ~ NARROW[font.data]; file: StrikeFile ~ data.file; IF char IN[file.min..file.max] THEN { index: NAT ~ char-file.min; w: StrikeFontFormat.WidthEntry; TRUSTED { w _ file.wtable[index] }; IF w#StrikeFontFormat.nullWidthEntry THEN { f0, f1: CARDINAL; r: ImagerTransformation.Rectangle; TRUSTED { f0 _ file.xtable[index]; f1 _ file.xtable[index+1] }; r _ ImagerTransformation.TransformRectangle[data.pixelToClient, [x: -file.ascent, y: file.foffset+w.offset, w: file.lines, h: f1-f0]]; 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: StrikeFile ~ data.file; IF char IN[file.min..file.max] THEN { w: StrikeFontFormat.WidthEntry; TRUSTED { w _ file.wtable[char-file.min] }; IF w#StrikeFontFormat.nullWidthEntry THEN { RETURN[data.pixelToClient.TransformVec[[0, w.width]]]; }; }; 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: StrikeFile ~ data.file; IF char IN[file.min..file.max] 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]]; }; MaskChar: PROC[font: Font, char: Char, imager: REF] ~ { context: Imager.Context ~ NARROW[imager]; data: Data ~ NARROW[font.data]; file: StrikeFile ~ data.file; IF char IN[file.min..file.max] THEN { index: CARDINAL ~ char-file.min; w: StrikeFontFormat.WidthEntry; TRUSTED { w _ file.wtable[index] }; IF w#StrikeFontFormat.nullWidthEntry THEN { f0, f1: CARDINAL; TRUSTED { f0 _ file.xtable[index]; f1 _ file.xtable[index+1] }; IF f0<=f1 AND f1<=CARDINAL[file.raster*16] THEN NULL ELSE ERROR MalformedStrikeFont; -- xtable inconsistent IF f1>f0 THEN { action: PROC ~ { Imager.ConcatT[context, data.pixelToClient]; Imager.MaskBits[context: context, base: file.strike, wordsPerLine: file.raster, sMin: 0, fMin: f0, sSize: file.lines, fSize: f1-f0, sOffset: -file.ascent, fOffset: file.foffset+w.offset]; }; 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. ÜImagerStrikeFontImpl.mesa Copyright c 1984, Xerox Corporation. All rights reserved. Doug Wyatt, October 26, 1984 1:14:44 pm PDT name: ROPE, transformation: Transformation, class: Class, data: REF, propList: REF Ê |˜šœ™Jšœ Ïmœ/™:J™+—J™šÏk ˜ Jšœžœ˜Jšœ žœ$˜3Jšœ žœY˜iJšžœžœ˜Jšœ˜Jšœ˜Jšžœžœ žœ˜)Jšœžœžœ˜JšœžœI˜_Jšœžœžœ˜—J˜Jšœžœž˜#Jšžœ žœ ž˜7Jšœž˜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šœžœžœžœ˜0Jšœžœžœžœ˜0Jšœ˜J˜J˜J˜—Jšœžœžœ˜"J˜šÏn œžœžœ žœžœžœžœ žœž œ˜WJšœžœ˜,Jšžœžœ:žœž˜HJšžœžœŸ˜1J˜J˜—š  œžœ žœžœžœ˜=Jšœžœžœžœ˜,Jšœ ˜ Jšœ1˜1Jšœ˜Jšœžœ˜Jšœžœ˜Jšœ'žœ˜/Jšœ žœ˜Jšœžœžœžœ˜+Jšœžœ˜"šžœŸ˜Jšœžœ˜:J˜—Jš žœžœžœžœžœ˜:Jšžœžœžœž˜7JšžœžœŸ˜1š žœžœžœžœŸ$˜FJšœžœ ˜Jšœ žœ&˜4Jšœ(˜(šžœŸ5˜?Jšœžœžœ˜+Jšžœžœ!˜EJšžœžœŸ+˜7J˜Jšœ˜Jšžœžœ˜2J˜—Jšžœ˜Jšœ/˜/Jšœ˜šžœžœ3˜=Jšœ?˜?Jšœ2˜2JšœD˜D—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šœA˜AJšžœžœžœžœ$˜OJšžœ$˜*J˜J˜—š œžœžœ˜>Jšœ žœ ˜Jšœ˜J˜ šžœž˜Jšœ˜Jšœ˜Jšœ˜Jšžœžœ ˜—šžœ žœž˜&Jšœ˜Jšžœ%˜,Jšžœ#žœžœ˜8Jšžœ˜—Jšžœ ˜J˜J˜—š  œžœžœ ˜>Jšœ žœ ˜Jšœ˜šžœžœžœ˜%Jšœžœ˜Jšœ˜Jšžœ˜#šžœ#žœ˜+Jšœžœ˜Jšœ"˜"Jšžœ8˜?šœ?˜?JšœF˜F—JšžœK˜QJ˜—J˜—Jšžœ˜J˜J˜—š œžœžœžœ˜4Jšœ žœ ˜Jšœ˜šžœžœžœ˜%Jšœ˜Jšžœ$˜+šžœ#žœ˜+Jšžœ0˜6J˜—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˜—š œžœ!žœ˜7Jšœžœ ˜)Jšœ žœ ˜Jšœ˜šžœžœžœ˜%Jšœžœ˜ Jšœ˜Jšžœ˜#šžœ#žœ˜+Jšœžœ˜Jšžœ8˜?Jš žœžœžœžœž˜4JšžœžœŸ˜6šžœžœ˜šœžœ˜Jšœ,˜,˜OJšœ3˜3Jšœ7˜7—J˜—J˜J˜—J˜—J˜—J˜J˜—šœžœ˜5Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜J˜J˜—Jšžœ˜—…—!p,È