DIRECTORY Basics USING [bytesPerWord], CountedVM USING [Allocate, Handle, Pointer], ImagerFont USING [Alias, Char, Class, ClassRep, CorrectionType, Extents, Font, FontRep, nullChar, OptionalReal, Register], FS, Imager USING [ConcatT, Context, DoSave, MaskFillParity], ImagerPath USING [PathProc], ImagerTransformation USING [Concat, Rectangle, Scale, Transformation, TransformRectangle, TransformVec], IO USING [Close, SetIndex, STREAM, UnsafeGetBlock], PrePressFontFormat USING [BCPLREAL, CardFromDouble, DirectoryArray, IXHeader, missingFilePos, missingSpline, NameIndexEntry, SplineCode, SplineCommand, SplineCoords, SplineData, SplineDataArray, StdIndexEntry], RealConvert USING [BcplToIeee], RefText, Rope, Vector2 USING [Add, Div, VEC]; ImagerSDFontImpl: CEDAR PROGRAM IMPORTS CountedVM, ImagerFont, FS, Imager, ImagerTransformation, IO, PrePressFontFormat, RealConvert, RefText, Rope, Vector2 ~ 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: 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]]]; }; SDCreate: PROC[name: ROPE] RETURNS[Font] ~ { file: SDFile ~ Open[name]; charToClient: Transformation ~ ImagerTransformation.Scale[1]; data: Data ~ NEW[DataRep _ [file: file]]; 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: 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: 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 ]]; SDRegister: PROC ~ { scratch: REF TEXT ~ NEW[TEXT[200]]; DoName: FS.NameProc ~ { cp: FS.ComponentPositions; start, stop: INT; text: REF TEXT _ scratch; [fullFName: fullFName, cp: cp] _ FS.ExpandName[fullFName]; start _ cp.subDirs.start; stop _ cp.base.start+cp.base.length; text.length _ 0; text _ RefText.AppendRope[to: text, from: "Xerox/PressFonts/"]; text _ RefText.AppendRope[to: text, from: fullFName, start: start, len: stop-start]; FOR i: NAT IN[0..text.length) DO IF text[i]='> THEN text[i] _ '/ ENDLOOP; ImagerFont.Register[name: Rope.FromRefText[text], file: fullFName, create: SDCreate]; RETURN[continue: TRUE]; }; FS.EnumerateForNames[pattern: "[Indigo]*.sd!H", proc: DoName]; ImagerFont.Alias["Xerox/XC82-0-0/Classic", "Xerox/PressFonts/Classic-MRR"]; ImagerFont.Alias["Xerox/XC82-0-0/Classic-Bold", "Xerox/PressFonts/Classic-BRR"]; ImagerFont.Alias["Xerox/XC82-0-0/Classic-Italic", "Xerox/PressFonts/Classic-MIR"]; ImagerFont.Alias["Xerox/XC82-0-0/Modern", "Xerox/PressFonts/Modern-MRR"]; ImagerFont.Alias["Xerox/XC82-0-0/Modern-Bold", "Xerox/PressFonts/Modern-BRR"]; ImagerFont.Alias["Xerox/XC82-0-0/Modern-Italic", "Xerox/PressFonts/Modern-MIR"]; ImagerFont.Alias["Xerox/XC82-0-0/Logotypes-Xerox", "Xerox/PressFonts/LOGO-MRR"]; }; SDRegister[]; END. ØImagerSDFontImpl.mesa Copyright c 1984, Xerox Corporation. All rights reserved. Doug Wyatt, November 14, 1984 6:18:43 pm PST name: ROPE, transformation: Transformation, class: Class, data: REF, propList: REF Ê ^˜šœ™Jšœ Ïmœ/™:J™,—J™šÏk ˜ Jšœžœ˜Jšœ žœ˜,Jšœ žœj˜zJšžœ˜Jšœžœ,˜8Jšœ žœ ˜JšœžœN˜hJšžœžœžœ˜3Jšœžœžœ°˜ÒJšœ žœ˜Jšœ˜Jšœ˜Jšœžœ žœ˜—J˜Jšœžœž˜Jšžœžœ žœ9˜|Jšœž˜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˜š Ï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šœ=˜=Jšœ žœ˜)šžœžœ0˜:Jšœ/žœ˜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˜šœžœ˜5Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜J˜J˜—š  œžœ˜Jš œ žœžœžœžœ˜#šœžœ ˜Jšœžœ"žœ˜,Jšœžœžœ ˜Jšœ!žœ˜:Jšœ>˜>J˜J˜?JšœT˜TJšžœžœžœžœžœ žœžœ˜IJ˜UJšžœ žœ˜J˜—JšžœH˜JJ˜KJ˜PJ˜RJ˜IJ˜NJ˜PJšœP˜PJ˜J˜—Jšœ ˜ J˜Jšžœ˜—…—+L9‚