<> <> <> <<>> DIRECTORY Basics USING [BYTE, bytesPerWord], CountedVM USING [Allocate, Handle], FS USING [OpenFile, StreamFromOpenFile], Imager USING [Context, MaskFill], ImagerFont USING [CorrectionType, Extents, nullXChar, XChar], ImagerPath USING [PathProc], ImagerTypeface USING [Register, Typeface, TypefaceClass, TypefaceClassRep, TypefaceRep], IO USING [Close, SetIndex, STREAM, UnsafeGetBlock], PrePressFontFormat USING [CardFromBcpl, DirectoryArray, IntFromBcpl, IXHeader, missingFilePos, missingSpline, NameIndexEntry, RelFilePos, SplineCode, SplineCommand, SplineCoords, SplineData, SplineDataArray, StdIndexEntry], RealConvert USING [BcplToIeee], Vector2 USING [Add, Div, VEC]; ImagerSDTypefaceImpl: CEDAR PROGRAM IMPORTS CountedVM, FS, Imager, ImagerTypeface, IO, PrePressFontFormat, RealConvert, Vector2 ~ BEGIN OPEN ImagerTypeface, ImagerFont; BYTE: TYPE ~ Basics.BYTE; VEC: TYPE ~ Vector2.VEC; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD[ bc, ec: BYTE _ 0, splineData: LONG POINTER TO PrePressFontFormat.SplineDataArray _ NIL, directory: LONG POINTER TO PrePressFontFormat.DirectoryArray _ NIL, vm: CountedVM.Handle _ NIL ]; MalformedSDFont: ERROR ~ CODE; ReadWords: UNSAFE PROC [stream: IO.STREAM, base: LONG POINTER, words: INT] ~ UNCHECKED { count: INT ~ words*Basics.bytesPerWord; IF IO.UnsafeGetBlock[stream, [base: LOOPHOLE[base], count: count]]=count THEN NULL ELSE ERROR MalformedSDFont; -- data too short }; SDCreate: PROC [file: FS.OpenFile] RETURNS [Typeface] ~ { OPEN PrePressFontFormat; stream: IO.STREAM ~ FS.StreamFromOpenFile[file]; data: Data ~ NEW[DataRep _ []]; ix: IXHeader; ixSize: NAT ~ SIZE[IXHeader]; name: NameIndexEntry; index: StdIndexEntry; nameFound, indexFound: BOOL _ FALSE; segmentIndex, segmentWords: INT _ 0; DO -- read the index part TRUSTED { ReadWords[stream, @ix, SIZE[IXHeader]] }; SELECT ix.type FROM end => EXIT; name => { IF nameFound THEN ERROR MalformedSDFont; -- more than one name entry IF (ix.length-ixSize)=SIZE[NameIndexEntry] THEN TRUSTED { ReadWords[stream, @name, SIZE[NameIndexEntry]] } ELSE ERROR MalformedSDFont; -- wrong ix.length <<{ -- convert name to rope>> <> <> <<};>> nameFound _ TRUE; }; spline => { IF indexFound THEN ERROR MalformedSDFont; -- more than one char index entry IF (ix.length-ixSize)=SIZE[StdIndexEntry] THEN TRUSTED { ReadWords[stream, @index, SIZE[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 data.bc _ index.bc; data.ec _ index.ec; segmentIndex _ CardFromBcpl[index.segmentSA]; -- in words! segmentWords _ CardFromBcpl[index.segmentLength]; data.vm _ CountedVM.Allocate[words: segmentWords]; IO.SetIndex[stream, segmentIndex*Basics.bytesPerWord]; TRUSTED { -- read segment base: LONG POINTER ~ data.vm.pointer; ReadWords[stream, base, segmentWords]; data.splineData _ LOOPHOLE[base]; data.directory _ LOOPHOLE[base+SIZE[SplineDataArray[index.ec-index.bc+1]]]; }; IO.Close[stream]; RETURN[NEW[TypefaceRep _ [class: sdClass, data: data]]]; }; SDContains: 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; sd: PrePressFontFormat.SplineData; TRUSTED { sd _ data.splineData[index] }; RETURN[sd.wx#PrePressFontFormat.missingSpline]; }; RETURN[FALSE]; }; SDNextChar: 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]]; }; SDKern: PROC [self: Typeface, char, successor: XChar] RETURNS [VEC] ~ { RETURN[[0, 0]]; }; SDNextKern: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ { RETURN[nullXChar]; }; SDLigature: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ { RETURN[nullXChar]; }; SDNextLigature: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ { RETURN[nullXChar]; }; SDMask: 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; sd: PrePressFontFormat.SplineData; TRUSTED { sd _ data.splineData[index] }; IF sd.wx#PrePressFontFormat.missingSpline THEN { base: LONG POINTER _ NIL; path: ImagerPath.PathProc ~ { next: LONG POINTER _ base; lp: VEC _ [0, 0]; GetCode: PROC RETURNS [PrePressFontFormat.SplineCode] ~ TRUSTED { p: LONG POINTER TO PrePressFontFormat.SplineCommand ~ LOOPHOLE[next]; next _ next+SIZE[PrePressFontFormat.SplineCommand]; RETURN[p.code]; }; GetCoords: PROC RETURNS [VEC] ~ TRUSTED { p: LONG POINTER TO PrePressFontFormat.SplineCoords ~ LOOPHOLE[next]; next _ next+SIZE[PrePressFontFormat.SplineCoords]; RETURN[[RealConvert.BcplToIeee[p.x], RealConvert.BcplToIeee[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; }; TRUSTED { filePos: PrePressFontFormat.RelFilePos ~ data.directory[index]; offset: INT ~ PrePressFontFormat.IntFromBcpl[filePos]; IF filePos=PrePressFontFormat.missingFilePos THEN ERROR MalformedSDFont; base _ LOOPHOLE[data.directory+offset]; }; Imager.MaskFill[context: context, path: path, parity: TRUE]; }; }; }; sdClass: TypefaceClass ~ NEW[TypefaceClassRep _ [ type: $SD, Contains: SDContains, NextChar: SDNextChar, Width: SDWidth, Amplified: SDAmplified, Correction: SDCorrection, BoundingBox: SDBoundingBox, FontBoundingBox: SDFontBoundingBox, Ligature: SDLigature, NextLigature: SDNextLigature, Kern: SDKern, NextKern: SDNextKern, Mask: SDMask ]]; <> <> <> <> <> <<[fullFName: fullFName, cp: cp] _ FS.ExpandName[fullFName];>> <> <> <> <> <> <> <> <<};>> <*.sd!H", proc: DoName];>> <> <> <> <> <> <> <> <<};>> <<>> ImagerTypeface.Register["SD", SDCreate]; END.