DIRECTORY Basics USING [bytesPerWord], CountedVM USING [Allocate, Handle, Pointer], Font USING [Char, Class, ClassRep, CorrectionType, Extents, FONT, FontRep, nullChar, OptionalReal, Register], FS USING [StreamOpen], Imager, ImagerPath, ImagerTransformation, IO USING [Close, SetIndex, STREAM, UnsafeGetBlock], PrePressFontFormat, RealConvert USING [BcplToIeee], Rope USING [FromProc, ROPE], Vector2; SDFontImpl: CEDAR PROGRAM IMPORTS CountedVM, Font, FS, Imager, ImagerTransformation, IO, PrePressFontFormat, RealConvert, Rope, Vector2 ~ BEGIN BYTE: TYPE ~ [0..377B]; ROPE: TYPE ~ Rope.ROPE; VEC: TYPE ~ Vector2.VEC; Transformation: TYPE ~ ImagerTransformation.Transformation; FONT: TYPE ~ Font.FONT; FontRep: TYPE ~ Font.FontRep; Char: TYPE ~ Font.Char; -- CARDINAL nullChar: Char ~ Font.nullChar; CorrectionType: TYPE ~ Font.CorrectionType; -- {none, space, mask}; Extents: TYPE ~ Font.Extents; -- RECORD[leftExtent, rightExtent, descent, ascent: REAL]; OptionalReal: TYPE ~ Font.OptionalReal; -- RECORD[exists: BOOLEAN, value: REAL]; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD[ file: SDFile ]; SDFile: TYPE ~ REF SDFileRep; SDFileRep: TYPE ~ RECORD[ bc, ec: BYTE, splineData: LONG POINTER TO PrePressFontFormat.SplineDataArray, directory: LONG POINTER TO PrePressFontFormat.DirectoryArray, vm: CountedVM.Handle ]; MalformedSDFont: ERROR ~ CODE; RealFromBcpl: PROC[x: PrePressFontFormat.BCPLREAL] RETURNS[REAL] ~ INLINE { RETURN[RealConvert.BcplToIeee[LOOPHOLE[x]]]; }; 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 MalformedSDFont; -- file too short }; SetWordIndex: PROC[stream: IO.STREAM, wordIndex: INT] ~ { index: CARDINAL ~ wordIndex*Basics.bytesPerWord; IO.SetIndex[stream, index]; }; Open: PROC[fileName: ROPE] RETURNS[SDFile] ~ { stream: IO.STREAM ~ FS.StreamOpen[fileName]; ix: PrePressFontFormat.IXHeader; ixSize: NAT ~ SIZE[PrePressFontFormat.IXHeader]; name: PrePressFontFormat.NameIndexEntry; index: PrePressFontFormat.StdIndexEntry; nameFound, indexFound: BOOL _ FALSE; family: ROPE _ NIL; segmentIndex, segmentWords: INT _ 0; vm: CountedVM.Handle _ NIL; splineData, directory: LONG POINTER _ NIL; DO -- read the index part TRUSTED { ReadWords[stream, @ix, SIZE[PrePressFontFormat.IXHeader]] }; SELECT ix.type FROM end => EXIT; name => { IF nameFound THEN ERROR MalformedSDFont; -- more than one name entry IF (ix.length-ixSize)=SIZE[PrePressFontFormat.NameIndexEntry] THEN TRUSTED { ReadWords[stream, @name, SIZE[PrePressFontFormat.NameIndexEntry]] } ELSE ERROR MalformedSDFont; -- 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; }; spline => { IF indexFound THEN ERROR MalformedSDFont; -- more than one char index entry IF (ix.length-ixSize)=SIZE[PrePressFontFormat.StdIndexEntry] THEN TRUSTED { ReadWords[stream, @index, SIZE[PrePressFontFormat.StdIndexEntry]] } ELSE ERROR MalformedSDFont; -- wrong ix.length indexFound _ TRUE; }; ENDCASE => ERROR MalformedSDFont; -- unexpected ix type ENDLOOP; IF nameFound AND indexFound AND name.code=index.family THEN NULL ELSE ERROR MalformedSDFont; -- index part has wrong form IF index.bc>index.ec THEN ERROR MalformedSDFont; -- 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]; splineData _ base; directory _ splineData+SIZE[PrePressFontFormat.SplineDataArray[index.ec-index.bc+1]]; }; IO.Close[stream]; RETURN[NEW[SDFileRep _ [bc: index.bc, ec: index.ec, splineData: splineData, directory: directory, vm: vm]]]; }; Find: PROC[name: ROPE] RETURNS[FONT] ~ { file: SDFile ~ Open[name]; charToClient: Transformation ~ ImagerTransformation.Scale[1]; data: Data ~ NEW[DataRep _ [file: file]]; RETURN[NEW[Font.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: SDFile ~ data.file; charToClient: Transformation ~ font.charToClient.Concat[m]; newData: Data ~ NEW[DataRep _ [file: file]]; 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: SDFile ~ data.file; IF char IN[file.bc..file.ec] THEN { sd: PrePressFontFormat.SplineData; TRUSTED { sd _ file.splineData[char-file.bc] }; RETURN[sd.wx#PrePressFontFormat.missingSpline]; }; RETURN[FALSE]; }; NextChar: PROC[font: FONT, char: Char] RETURNS[next: Char] ~ { data: Data ~ NARROW[font.data]; file: SDFile ~ 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 sd: PrePressFontFormat.SplineData; TRUSTED { sd _ file.splineData[probe-file.bc] }; IF sd.wx#PrePressFontFormat.missingSpline THEN RETURN[probe]; ENDLOOP; RETURN[nullChar]; }; BoundingBox: PROC[font: FONT, char: Char] RETURNS[Extents] ~ { data: Data ~ NARROW[font.data]; file: SDFile ~ data.file; IF char IN[file.bc..file.ec] THEN { sd: PrePressFontFormat.SplineData; TRUSTED { sd _ file.splineData[char-file.bc] }; IF sd.wx#PrePressFontFormat.missingSpline THEN { xmin: REAL ~ RealFromBcpl[sd.xmin]; ymin: REAL ~ RealFromBcpl[sd.ymin]; xmax: REAL ~ RealFromBcpl[sd.xmax]; ymax: REAL ~ RealFromBcpl[sd.ymax]; r: ImagerTransformation.Rectangle ~ ImagerTransformation.TransformRectangle[ font.charToClient, [x: xmin, y: ymin, w: xmax-xmin, h: ymax-ymin]]; 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: SDFile ~ data.file; IF char IN[file.bc..file.ec] THEN { sd: PrePressFontFormat.SplineData; TRUSTED { sd _ file.splineData[char-file.bc] }; IF sd.wx#PrePressFontFormat.missingSpline THEN { wx: REAL ~ RealFromBcpl[sd.wx]; wy: REAL ~ RealFromBcpl[sd.wy]; RETURN[font.charToClient.TransformVec[[wx, 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: SDFile ~ 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: SDFile ~ data.file; IF char IN[file.bc..file.ec] THEN { sd: PrePressFontFormat.SplineData; TRUSTED { sd _ file.splineData[char-file.bc] }; IF sd.wx#PrePressFontFormat.missingSpline THEN { base: LONG POINTER _ NIL; SDPath: ImagerPath.PathProc ~ { next: LONG POINTER _ base; lp: VEC _ [0, 0]; GetCode: PROC RETURNS[PrePressFontFormat.SplineCode] ~ TRUSTED { p: LONG POINTER TO PrePressFontFormat.SplineCommand ~ next; next _ next+SIZE[PrePressFontFormat.SplineCommand]; RETURN[p.code]; }; GetCoords: PROC RETURNS[VEC] ~ TRUSTED { p: LONG POINTER TO PrePressFontFormat.SplineCoords ~ next; next _ next+SIZE[PrePressFontFormat.SplineCoords]; RETURN[[RealFromBcpl[p.x], RealFromBcpl[p.y]]]; }; DO SELECT GetCode[] FROM $moveTo => { p: VEC ~ GetCoords[]; moveTo[p]; lp _ p; }; $drawTo => { p: VEC ~ GetCoords[]; lineTo[p]; lp _ p; }; $drawCurve => { c1: VEC ~ GetCoords[]; c2: VEC ~ GetCoords[]; c3: VEC ~ GetCoords[]; b1: VEC ~ lp.Add[c1.Div[3]]; b2: VEC ~ b1.Add[c1.Add[c2].Div[3]]; b3: VEC ~ lp.Add[c1].Add[c2].Add[c3]; curveTo[b1, b2, b3]; lp _ b3; }; $endDefinition => EXIT; $newObject => ERROR MalformedSDFont; -- not implemented ENDCASE => ERROR MalformedSDFont; -- undefined ENDLOOP; }; action: PROC ~ { Imager.ConcatT[context, font.charToClient]; Imager.MaskFillParity[context, SDPath]; }; TRUSTED { fp: LONG CARDINAL ~ PrePressFontFormat.CardFromDouble[file.directory[char-file.bc]]; IF fp#missingOffset THEN base _ LOOPHOLE[file.directory+fp] ELSE ERROR MalformedSDFont; }; Imager.DoSave[context, action]; }; }; }; class: Font.Class ~ NEW[Font.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 ]]; Font.Register["Xerox/SD", Find]; END. ÐSDFontImpl.mesa Copyright c 1984, Xerox Corporation. All rights reserved. Doug Wyatt, October 9, 1984 3:17:56 pm PDT name: ROPE, transformation: Transformation, class: Class, data: REF, propList: REF Ê ·˜šœ™Jšœ Ïmœ/™:J™*—J™šÏk ˜ Jšœžœ˜Jšœ žœ˜,Jšœžœ2žœ-˜mJšžœžœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšžœžœžœ˜3Jšœ˜Jšœ žœ˜Jšœžœ žœ˜Jšœ˜—J˜Jšœ žœž˜Jšžœžœ žœ0˜mJšœž˜J˜Jšžœžœ ˜J˜Jšžœžœžœ˜Jšžœžœ žœ˜Jšœžœ'˜;J˜Jšžœžœžœ˜šœ žœ˜Jšœžœ™ Jšœ™J™ Jšœžœ™ Jšœ ž™ J˜—JšœžœÏc ˜#šœ˜J˜—šœžœŸ˜CJ˜—šœ žœŸ:˜XJ˜—šœžœŸ(˜PJ˜—Jšœžœžœ ˜šœ žœžœ˜Jšœ ˜ J˜J˜—Jšœžœžœ ˜šœ žœžœ˜Jšœžœ˜ Jšœ žœžœžœ$˜?Jšœ žœžœžœ#˜=J˜J˜J˜—Jšœžœžœ˜J˜š Ïn œžœžœžœžœžœ˜KJšžœžœ˜,J˜J˜—š  œžœžœ žœžœžœžœ žœž œ˜WJšœžœ˜'Jšžœžœ:žœž˜HJšžœžœŸ˜-J˜J˜—š   œžœ žœžœ žœ˜9Jšœžœ!˜0Jšžœ˜J˜J˜—š œžœ žœžœ ˜.Jšœžœžœžœ˜,J˜ Jšœžœžœ˜0Jšœ(˜(Jšœ(˜(Jšœžœžœ˜$Jšœžœžœ˜Jšœžœ˜$Jšœžœ˜Jšœžœžœžœ˜*šžœŸ˜Jšžœžœ!˜Fšžœ ž˜Jšœžœ˜ šœ ˜ Jšžœ žœžœŸ˜Dšžœžœ$žœžœ˜LJšœžœ&˜C—JšžœžœŸ˜.šœŸ˜Jš œžœ žœžœžœžœžœ˜IJšœ1˜1J˜—Jšœ žœ˜J˜—šœ ˜ Jšžœ žœžœŸ!˜Kšžœžœ#žœžœ˜KJšœžœ%˜C—JšžœžœŸ˜.Jšœ žœ˜J˜—JšžœžœŸ˜7—Jšžœ˜—Jš žœ žœ žœžœž˜@JšžœžœŸ˜8JšžœžœžœŸ˜AJšœCŸ ˜OJšœF˜FJšœ-˜-Jšœ#˜#šžœŸ˜Jšœžœžœ˜+Jšœ&˜&J˜Jšœžœ:˜UJ˜—Jšžœ˜šžœžœ)˜3Jšœ8˜8—J˜J˜—š  œžœžœžœžœ˜(Jšœ˜Jšœ=˜=Jšœ žœ˜)šžœžœ*˜4Jšœ/žœ˜6—J˜J˜—š  œžœžœžœžœ˜=Jšœ žœ ˜Jšœ˜Jšœ;˜;Jšœžœ˜,šžœžœ(˜2Jšœ4žœ˜;—J˜J˜—š  œžœžœžœžœ˜8Jšœ žœ ˜Jšœ˜šžœžœžœ˜#Jšœ"˜"Jšžœ(˜/Jšžœ)˜/J˜—Jšžœžœ˜J˜J˜—š œžœžœžœ˜>Jšœ žœ ˜Jšœ˜J˜ šžœž˜Jšœ˜Jšœ˜Jšœ˜Jšžœžœ ˜—šžœ žœž˜%Jšœ"˜"Jšžœ)˜0Jšžœ(žœžœ˜=Jšžœ˜—Jšžœ ˜J˜J˜—š  œžœžœžœ ˜>Jšœ žœ ˜Jšœ˜šžœžœžœ˜#Jšœ"˜"Jšžœ(˜/šžœ(žœ˜0Jšœžœ˜#Jšœžœ˜#Jšœžœ˜#Jšœžœ˜#šœL˜LJšœC˜C—JšžœK˜QJ˜—J˜—Jšžœ˜J˜J˜—š  œžœžœžœžœ˜4Jšœ žœ ˜Jšœ˜šžœžœžœ˜#Jšœ"˜"Jšžœ(˜/šžœ(žœ˜0Jšœžœ˜Jšœžœ˜Jšžœ+˜1J˜—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šžœ(˜/šžœ(žœž˜0Jšœžœžœžœ˜š œ˜Jšœžœžœ˜Jšœžœ ˜š œžœžœ"žœ˜@Jšœžœžœžœ)˜;Jšœ žœ#˜3Jšžœ ˜J˜—š   œžœžœžœžœ˜(Jšœžœžœžœ(˜:Jšœ žœ"˜2Jšžœ)˜/J˜—šžœžœ ž˜˜ Jšœžœ˜J˜ J˜J˜—˜ Jšœžœ˜J˜ J˜J˜—šœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜$Jšœžœ˜%J˜J˜J˜—Jšœžœ˜JšœžœŸ˜7JšžœžœŸ ˜.Jšžœ˜—J˜—šœžœ˜Jšœ+˜+Jšœ'˜'J˜—šžœ˜ JšœžœžœC˜TJšžœžœžœ˜;Jšžœžœ˜J˜—J˜J˜—J˜—J˜J˜—šœžœ˜)Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜J˜J˜—J˜ J˜Jšžœ˜—…—$Ä2K