-- CGFontImpl.mesa -- Last edit by Doug Wyatt, August 30, 1982 5:16 pm DIRECTORY CGFont USING [ErrorType, Ref, Rep, WidthArray], CGStorage USING [pZone, qZone], KSFonts USING [Gacha10], StrikeFormat USING [Body, Format, Header, KernedStrike, nullWidthEntry, PlainStrike, WidthEntry, WTable, XTable], Ascii USING [CR, SP, TAB], Directory USING [Error, Lookup], File USING [Capability, GetSize, PageCount], Inline USING [LowHalf], Runtime USING [GetTableBase], Space USING [Create, Handle, LongPointer, Map, PageCount, virtualMemory]; CGFontImpl: CEDAR PROGRAM IMPORTS CGStorage, KSFonts, Directory, File, Inline, Runtime, Space EXPORTS CGFont = { OPEN StrikeFormat, CGFont; fontsZone: ZONE = CGStorage.pZone; repZone: ZONE = CGStorage.qZone; widthZone: ZONE = CGStorage.qZone; nameZone: ZONE = CGStorage.pZone; defaultFont: PUBLIC Ref _ NIL; FontArray: TYPE = RECORD[SEQUENCE space: NAT OF Ref]; fonts: REF FontArray _ NIL; nFonts: NAT _ 0; Error: PUBLIC ERROR[type: ErrorType] = CODE; -- Procedures StringWidth: PUBLIC UNSAFE PROC[string: LONG STRING, font: Ref] RETURNS[NAT] = UNCHECKED { width: REF WidthArray _ font.width; w: NAT _ 0; FOR i: NAT IN[0..string.length) DO w _ w + width[string[i]] ENDLOOP; RETURN[w]; }; DefaultFont: PUBLIC PROC RETURNS[Ref] = { RETURN[defaultFont] }; LoadFont: PUBLIC UNSAFE PROC[name: LONG STRING] RETURNS[Ref] = UNCHECKED { address: LONG POINTER _ NIL; self: Ref _ NIL; address _ GetFile[name]; IF address=NIL THEN RETURN[NIL]; self _ New[address]; Register[self]; RETURN[self]; }; Register: PROC[font: Ref] = { space: NAT _ IF fonts=NIL THEN 0 ELSE fonts.space; i: NAT _ nFonts; nFonts _ i + 1; IF nFonts>space THEN { old: REF FontArray _ fonts; fonts _ fontsZone.NEW[FontArray[space+MAX[4,space/2]]]; FOR j: NAT IN[0..i) DO fonts[j] _ old[j] ENDLOOP; }; fonts[i] _ font; }; New: PUBLIC UNSAFE PROC[address: LONG POINTER] RETURNS[Ref] = UNCHECKED { hdr: LONG POINTER TO Header = address; format: Format _ hdr.format; dx,dy,ox,oy: INTEGER _ 0; body: LONG POINTER TO Body _ NIL; raster,height: CARDINAL; bitmap: LONG POINTER _ NIL; kerned: BOOLEAN _ FALSE; self: Ref _ NIL; IF format.oneBit=F THEN ERROR Error[illegalFormat]; IF format.index=T THEN ERROR Error[illegalFormat]; kerned _ (format.kerned=T); IF kerned THEN { ks: LONG POINTER TO KernedStrike _ address; body _ @ks.body; [fbbdx: dx, fbbdy: dy, fbbox: ox, fbboy: oy] _ ks.box } ELSE { ps: LONG POINTER TO PlainStrike _ address; body _ @ps.body; dx _ hdr.maxwidth; dy _ body.ascent+body.descent; ox _ 0; oy _ -body.descent }; height _ body.ascent+body.descent; bitmap _ LOOPHOLE[body + SIZE[Body]]; raster _ body.raster; self _ repZone.NEW[Rep _ [kerned: kerned, height: height, min: hdr.min, max: hdr.max, width: NIL, dx: dx, dy: dy, ox: ox, oy: oy, xtable: NIL, wtable: NIL, bitmap: bitmap, raster: raster, address: address]]; self.xtable _ LOOPHOLE[bitmap+raster*height]; IF kerned THEN self.wtable _ LOOPHOLE[body+body.length]; Initialize[self]; RETURN[self]; }; Initialize: UNSAFE PROC[font: Ref] = UNCHECKED { min: CHARACTER _ font.min; max: CHARACTER _ font.max; width: REF WidthArray _ widthZone.NEW[WidthArray]; IF font.kerned THEN { wtable: LONG POINTER TO WTable _ font.wtable; dummy: [0..377B] _ wtable[max-min+1].width; width^ _ ALL[dummy]; FOR c: CHARACTER IN[min..max] DO i: NAT _ c - min; entry: WidthEntry _ wtable[i]; IF entry#nullWidthEntry THEN width[c] _ entry.width; ENDLOOP; } ELSE { xtable: LONG POINTER TO XTable _ font.xtable; space: [0..377B] _ 0; FOR c: CHARACTER IN[min..max+1] DO i: NAT _ c - min; width[c] _ xtable[i+1] - xtable[i]; ENDLOOP; space _ width[Ascii.SP]; FOR c: CHARACTER IN [0C..min) DO width[c] _ space ENDLOOP; FOR c: CHARACTER IN (max+1..177C] DO width[c] _ space ENDLOOP; width[Ascii.TAB] _ 8*space; -- tab width hack width[Ascii.CR] _ space; -- CR width hack }; font.width _ width; }; GetFile: UNSAFE PROC[name: LONG STRING] RETURNS[LONG POINTER] = UNCHECKED { file: File.Capability; pages: File.PageCount; size: Space.PageCount; space: Space.Handle; file _ Directory.Lookup[fileName: name! Directory.Error => GOTO Punt]; pages _ File.GetSize[file]; IF pages<30 THEN size _ Inline.LowHalf[pages] ELSE ERROR Error[fileTooLarge]; space _ Space.Create[size: size, parent: Space.virtualMemory]; Space.Map[space: space, window: [file: file, base: 1]]; -- first page is 1! RETURN[Space.LongPointer[space]]; EXITS Punt => RETURN[NIL] }; TRUSTED {defaultFont _ New[Runtime.GetTableBase[KSFonts.Gacha10]]}; }.