DIRECTORY Basics USING [bitsPerWord, bytesPerWord, LongMult], CountedVM USING [Allocate, Handle], FEPressFontFormat USING [bcplLONGCARDINAL, BoundingBox, FontCode, Fraction, IndexHeader, MesaToBcplFraction, MesaToBcplLongCardinal, RawIndex], FS USING [StreamOpen], ImagerPixelMap USING [Clear, Create, CreateFrameBuffer, DeviceRectangle, Fill, PixelMap, Reflect, Rotate, ShiftMap, Transfer, Trim, Window], IO USING [Close, GetIndex, GetLength, PutChar, PutRope, SetIndex, STREAM, UnsafeGetBlock, UnsafePutBlock], PrePressFontFormat USING [CardFromBcpl, CharacterData, CharacterIndexEntry, CharDataArray, DirectoryArray, IntFromBcpl, IXHeader, missingCharacter, missingFilePos, NameIndexEntry, RasterDefn], RasterFontIO USING [InternalCharRep, InternalFont, InternalFontRep], Real USING [FScale, RoundLI], Rope USING [FromProc, Length, ROPE, Substr], StrikeFontFormat USING [Body, BoundingBox, Header, nullWidthEntry, WidthEntry]; RasterFontIOImpl: CEDAR PROGRAM IMPORTS FS, CountedVM, ImagerPixelMap, IO, Real, Rope, PrePressFontFormat, FEPressFontFormat EXPORTS RasterFontIO ~ BEGIN OPEN RasterFontIO; ROPE: TYPE ~ Rope.ROPE; FormatError: PUBLIC ERROR [byteIndex: INT] ~ CODE; Create: PUBLIC PROC [defaultBoxBounds: ImagerPixelMap.DeviceRectangle, defaultWidth: INTEGER] RETURNS [internalFont: InternalFont] ~ { defaultPixels: ImagerPixelMap.PixelMap _ ImagerPixelMap.Create[0, defaultBoxBounds]; defaultPixels.Clear; defaultPixels.Fill[defaultBoxBounds, 1]; internalFont _ NEW [InternalFontRep]; internalFont.defaultChar _ [fWidth: defaultWidth, sWidth: 0, pixels: defaultPixels]; FOR char: CHAR IN CHAR DO internalFont.charRep[char] _ internalFont.defaultChar; ENDLOOP; }; SetWordIndex: PROC[stream: IO.STREAM, wordIndex: INT] ~ { index: CARDINAL ~ wordIndex*Basics.bytesPerWord; IO.SetIndex[stream, index]; }; 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 FormatError[IO.GetIndex[stream]]; -- file too short }; missingOffset: INT ~ PrePressFontFormat.IntFromBcpl[PrePressFontFormat.missingFilePos]; LoadAC: PROC [fileName: ROPE] RETURNS [internalFont: InternalFont] ~ { stream: IO.STREAM ~ FS.StreamOpen[fileName]; Bad: PROC [backoff: INT] ~ {ERROR FormatError[IO.GetIndex[stream]-backoff]}; ix: PrePressFontFormat.IXHeader; ixSize: NAT ~ SIZE[PrePressFontFormat.IXHeader]; name: PrePressFontFormat.NameIndexEntry; index: PrePressFontFormat.CharacterIndexEntry; nameFound, indexFound: BOOL _ FALSE; family: ROPE _ NIL; segmentIndex, segmentWords: INT _ 0; vm: CountedVM.Handle _ NIL; charData: LONG POINTER TO PrePressFontFormat.CharDataArray _ NIL; directory: LONG POINTER TO PrePressFontFormat.DirectoryArray _ NIL; bitsPerMica: REAL _ 1.0; DO -- read the index part TRUSTED { ReadWords[stream, @ix, SIZE[PrePressFontFormat.IXHeader]] }; SELECT ix.type FROM end => EXIT; name => { IF nameFound THEN Bad[SIZE[PrePressFontFormat.IXHeader]]; -- more than one name entry IF (ix.length-ixSize)=SIZE[PrePressFontFormat.NameIndexEntry] THEN TRUSTED { ReadWords[stream, @name, SIZE[PrePressFontFormat.NameIndexEntry]] } ELSE Bad[SIZE[PrePressFontFormat.IXHeader]]; -- 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; }; character => { IF indexFound THEN Bad[SIZE[PrePressFontFormat.IXHeader]]; -- more than one char index entry IF (ix.length-ixSize)=SIZE[PrePressFontFormat.CharacterIndexEntry] THEN TRUSTED { ReadWords[stream, @index, SIZE[PrePressFontFormat.CharacterIndexEntry]] } ELSE Bad[SIZE[PrePressFontFormat.IXHeader]]; -- wrong ix.length indexFound _ TRUE; }; ENDCASE => Bad[SIZE[PrePressFontFormat.IXHeader]]; -- unexpected ix type ENDLOOP; IF nameFound AND indexFound AND name.code=index.family THEN NULL ELSE Bad[0]; -- index part has wrong form IF index.bc>index.ec THEN Bad[0]; -- bc exceeds ec segmentIndex _ PrePressFontFormat.CardFromBcpl[index.segmentSA]; -- in words! segmentWords _ PrePressFontFormat.CardFromBcpl[index.segmentLength]; vm _ CountedVM.Allocate[words: segmentWords]; SetWordIndex[stream, segmentIndex]; TRUSTED { -- read segment base: LONG POINTER ~ vm.pointer; ReadWords[stream, base, segmentWords]; charData _ base; directory _ base+SIZE[PrePressFontFormat.CharDataArray[index.ec-index.bc+1]]; }; IO.Close[stream]; internalFont _ Create[defaultBoxBounds: [-8, 1, 8, 8], defaultWidth: 10]; internalFont.family _ family; internalFont.face _ index.face; internalFont.bitsPerInch _ index.resolutionX/10.0; bitsPerMica _ internalFont.bitsPerInch/2540.0; internalFont.bitsPerEmQuad _ index.size*bitsPerMica; FOR c: CHAR IN [VAL[index.bc]..VAL[index.ec]] DO charIndex: NAT ~ ORD[c]-index.bc; GetDefn: PROC RETURNS [LONG POINTER TO PrePressFontFormat.RasterDefn] ~ TRUSTED { fp: INT ~ PrePressFontFormat.IntFromBcpl[directory[charIndex]]; IF fp#missingOffset THEN RETURN [LOOPHOLE[directory+fp]] ELSE FormatError[0]; }; cd: PrePressFontFormat.CharacterData; TRUSTED { cd _ charData[charIndex] }; IF cd.bbdy#PrePressFontFormat.missingCharacter THEN TRUSTED { defn: LONG POINTER TO PrePressFontFormat.RasterDefn ~ GetDefn[]; raster: NAT ~ defn^.raster; lines: NAT ~ defn^.lines; IF lines=cd.bbdx AND raster=(cd.bbdy+15)/16 THEN TRUSTED { base: LONG POINTER ~ defn+SIZE[PrePressFontFormat.RasterDefn]; pixelsA: ImagerPixelMap.PixelMap _ ImagerPixelMap.CreateFrameBuffer[pointer: base, words: Basics.LongMult[raster, lines], lgBitsPerPixel: 0, rast: raster, lines: lines, ref: vm].ShiftMap[cd.bbox, cd.bboy]; pixelsB: ImagerPixelMap.PixelMap _ pixelsA.Reflect; pixelsA _ pixelsB.Rotate[scratch: pixelsA.refRep]; pixelsB _ pixelsA.Reflect[scratch: pixelsB.refRep]; internalFont.charRep[c] _ [ fWidth: Real.FScale[PrePressFontFormat.IntFromBcpl[cd.wx], -16], sWidth: -Real.FScale[PrePressFontFormat.IntFromBcpl[cd.wy], -16], pixels: pixelsB ]; } ELSE Bad[0]; -- raster and bounding box inconsistent }; ENDLOOP; }; paranoid: BOOL _ TRUE; Load: PUBLIC PROC [fileName: Rope.ROPE] RETURNS [internalFont: InternalFont] ~ TRUSTED { file: IO.STREAM _ FS.StreamOpen[fileName]; ReadBlock: UNSAFE PROC [dest: LONG POINTER, words: CARDINAL, wordOffset: INT _ -1] ~ UNCHECKED { IF wordOffset >= 0 THEN file.SetIndex[wordOffset*Basics.bytesPerWord]; [] _ file.UnsafeGetBlock[[dest, 0, words*Basics.bytesPerWord]]; }; CurWordOffset: PROC RETURNS [wordOffset: INT] ~ CHECKED { wordOffset _ file.GetIndex/Basics.bytesPerWord; }; strike: ImagerPixelMap.PixelMap; header: StrikeFontFormat.Header; internalFont _ NEW[InternalFontRep]; ReadBlock[@header, SIZE[StrikeFontFormat.Header], 0]; IF header.oneBit # T AND header.unused # 0 THEN { IO.Close[file]; RETURN [LoadAC[fileName]]; }; IF header.oneBit # T THEN ERROR FormatError[0]; IF header.index # F THEN ERROR FormatError[0]; IF header.unused # 0 THEN ERROR FormatError[1]; IF header.kerned = T THEN { boundingBox: StrikeFontFormat.BoundingBox; body: StrikeFontFormat.Body; xInSegment, prevXInSegment: CARDINAL; xInSegmentOffset: INT; widthEntryOffset: INT; widthEntry: StrikeFontFormat.WidthEntry; bodyOffset: INT; ReadBlock[@boundingBox, SIZE[StrikeFontFormat.BoundingBox]]; bodyOffset _ CurWordOffset[]; ReadBlock[@body, SIZE[StrikeFontFormat.Body]]; strike _ ImagerPixelMap.Create[0, [-body.ascent, 0, body.ascent+body.descent, body.raster*Basics.bitsPerWord]]; ReadBlock[strike.refRep.pointer, strike.refRep.words]; widthEntryOffset _ CurWordOffset[] + (header.max-header.min+3)*SIZE[CARDINAL]; IF widthEntryOffset # bodyOffset + body.length THEN ERROR FormatError[bodyOffset*SIZE[CARDINAL]]; ReadBlock[@prevXInSegment, SIZE[CARDINAL]]; xInSegmentOffset _ CurWordOffset[]; FOR char: CHAR IN [VAL[header.min]..VAL[header.max]] DO charPixels: ImagerPixelMap.PixelMap _ strike; ReadBlock[@xInSegment, SIZE[CARDINAL], xInSegmentOffset]; xInSegmentOffset _ xInSegmentOffset + SIZE[CARDINAL]; ReadBlock[@widthEntry, SIZE[StrikeFontFormat.WidthEntry], widthEntryOffset]; widthEntryOffset _ widthEntryOffset + SIZE[StrikeFontFormat.WidthEntry]; IF widthEntry # StrikeFontFormat.nullWidthEntry THEN { IF widthEntry.width > header.maxwidth THEN ERROR FormatError[(widthEntryOffset-SIZE[StrikeFontFormat.WidthEntry])*Basics.bytesPerWord]; charPixels.fOrigin _ widthEntry.offset+boundingBox.fbbox-prevXInSegment; charPixels.fMin _ prevXInSegment; charPixels.fSize _ xInSegment-prevXInSegment; internalFont.charRep[char] _ [ sWidth: 0, fWidth: widthEntry.width, pixels: charPixels ]; }; prevXInSegment _ xInSegment; ENDLOOP; ReadBlock[@xInSegment, SIZE[CARDINAL], xInSegmentOffset]; xInSegmentOffset _ xInSegmentOffset + SIZE[CARDINAL]; ReadBlock[@widthEntry, SIZE[StrikeFontFormat.WidthEntry], widthEntryOffset]; widthEntryOffset _ widthEntryOffset + SIZE[StrikeFontFormat.WidthEntry]; IF widthEntry # StrikeFontFormat.nullWidthEntry THEN { strike.fOrigin _ widthEntry.offset+boundingBox.fbbox-prevXInSegment; strike.fMin _ prevXInSegment; strike.fSize _ xInSegment-prevXInSegment; internalFont.defaultChar _ [ sWidth: 0, fWidth: widthEntry.width, pixels: strike ]; } ELSE ERROR FormatError[file.GetIndex]; } ELSE { body: StrikeFontFormat.Body; xInSegment, prevXInSegment: CARDINAL; ReadBlock[@body, SIZE[StrikeFontFormat.Body]]; strike _ ImagerPixelMap.Create[0, [-body.ascent, 0, body.ascent+body.descent, body.raster*Basics.bitsPerWord]]; ReadBlock[strike.refRep.pointer, strike.refRep.words]; ReadBlock[@prevXInSegment, SIZE[CARDINAL]]; FOR char: CHAR IN [VAL[header.min]..VAL[header.max]] DO charPixels: ImagerPixelMap.PixelMap _ strike; ReadBlock[@xInSegment, SIZE[CARDINAL]]; IF xInSegment>prevXInSegment THEN { charPixels.fOrigin _ -prevXInSegment; charPixels.fMin _ prevXInSegment; charPixels.fSize _ xInSegment-prevXInSegment; IF paranoid AND charPixels.fSize > header.maxwidth THEN ERROR FormatError[file.GetIndex-2]; internalFont.charRep[char] _ [ sWidth: 0, fWidth: charPixels.fSize, pixels: charPixels ]; }; prevXInSegment _ xInSegment; ENDLOOP; ReadBlock[@xInSegment, SIZE[CARDINAL]]; strike.fOrigin _ -prevXInSegment; strike.fMin _ prevXInSegment; strike.fSize _ xInSegment-prevXInSegment; internalFont.defaultChar _ [ sWidth: 0, fWidth: strike.fSize, pixels: strike ]; }; FOR char: CHAR IN CHAR DO IF internalFont.charRep[char].pixels.refRep = NIL THEN { internalFont.charRep[char] _ internalFont.defaultChar; }; ENDLOOP; IF paranoid AND file.GetIndex # file.GetLength THEN ERROR FormatError[file.GetIndex]; file.Close; }; ComputeFontMetrics: PUBLIC PROC [internalFont: InternalFont] RETURNS [bc, ec: CHAR, sMin, fMin, sMax, fMax: INTEGER, maxWidth, totalWidth, fSizeStrike: CARDINAL] ~ { ProcessChar: PROC [charRep: InternalCharRep] ~ { bb: ImagerPixelMap.DeviceRectangle _ charRep.pixels.Window; fWidth: INT _ Real.RoundLI[charRep.fWidth]; IF bb.sSize > 0 AND bb.fSize > 0 THEN { sMin _ MIN[sMin, bb.sMin]; fMin _ MIN[fMin, bb.fMin]; sMax _ MAX[sMax, bb.sMin+bb.sSize]; fMax _ MAX[fMax, bb.fMin+bb.fSize]; fSizeStrike _ fSizeStrike + bb.fSize; }; totalWidth _ totalWidth + fWidth; maxWidth _ MAX[fWidth, maxWidth]; }; bc _ '\000; ec _ '\377; WHILE bc < '\377 AND internalFont.charRep[bc] = internalFont.defaultChar DO bc _ bc + 1 ENDLOOP; WHILE ec > '\000 AND internalFont.charRep[ec] = internalFont.defaultChar DO ec _ ec - 1 ENDLOOP; maxWidth _ totalWidth_ fSizeStrike _ 0; sMin _ fMin _ sMax _ fMax _ 0; FOR char: CHAR IN [bc..ec] DO IF internalFont.charRep[char] # internalFont.defaultChar THEN ProcessChar[internalFont.charRep[char]]; ENDLOOP; ProcessChar[internalFont.defaultChar]; }; ComputeWidthEntry: PROC [charRep: InternalCharRep, fMinFont: INTEGER] RETURNS [widthEntry: StrikeFontFormat.WidthEntry] ~ { window: ImagerPixelMap.DeviceRectangle _ charRep.pixels.Window; IF window.sSize = 0 OR window.fSize = 0 THEN window.fMin _ 0; IF window.fMin-fMinFont < 0 THEN ERROR; widthEntry.offset _ window.fMin-fMinFont; widthEntry.width _ Real.RoundLI[charRep.fWidth]; }; WriteKernedStrike: PUBLIC PROC [internalFont: InternalFont, fileName: Rope.ROPE] ~ TRUSTED { file: IO.STREAM _ FS.StreamOpen[fileName, $create]; WriteBlock: UNSAFE PROC [source: LONG POINTER, words: CARDINAL] ~ UNCHECKED { file.UnsafePutBlock[[source, 0, words*Basics.bytesPerWord]]; }; min, max: CHAR; sMin, fMin, sMax, fMax: INTEGER; maxwidth, strikeWidth: CARDINAL; [min, max, sMin, fMin, sMax, fMax, maxwidth, ----, strikeWidth] _ ComputeFontMetrics[internalFont]; IF max>=min THEN { ascent: NAT _ -sMin; descent: NAT _ sMax; bodyStart: INT; header: StrikeFontFormat.Header; boundingBox: StrikeFontFormat.BoundingBox _ [fbbox: fMin, fbboy: -sMax, fbbdx: fMax-fMin, fbbdy: sMax-sMin]; body: StrikeFontFormat.Body; strike: ImagerPixelMap.PixelMap; widthEntry: StrikeFontFormat.WidthEntry; f: INTEGER; strike _ ImagerPixelMap.Create[0, [-ascent, 0, ascent+descent, strikeWidth]]; strike.Clear; f _ 0; FOR c: CHAR IN [min..max] DO IF internalFont.charRep[c] # internalFont.defaultChar THEN { pixels: ImagerPixelMap.PixelMap _ internalFont.charRep[c].pixels; pixels _ pixels.ShiftMap[0, f-pixels.Window.fMin]; strike.Transfer[pixels]; IF pixels.sSize # 0 THEN f _ f + pixels.fSize; }; ENDLOOP; strike.Transfer[internalFont.defaultChar.pixels.ShiftMap[0, f-internalFont.defaultChar.pixels.Window.fMin]]; header.oneBit _ T; header.index _ F; header.fixed _ F; header.kerned _ T; header.unused _ 0; header.min _ ORD[min]; header.max _ ORD[max]; header.maxwidth _ maxwidth; body.length _ strike.refRep.words+SIZE[StrikeFontFormat.Body]+(max-min+3)*SIZE[CARDINAL]; body.ascent _ ascent; body.descent _ descent; body.xoffset _ 0; body.raster _ strike.refRep.rast; WriteBlock[@header, SIZE[StrikeFontFormat.Header]]; WriteBlock[@boundingBox, SIZE[StrikeFontFormat.BoundingBox]]; bodyStart _ file.GetIndex; WriteBlock[@body, SIZE[StrikeFontFormat.Body]]; WriteBlock[strike.refRep.pointer, strike.refRep.words]; strikeWidth _ 0; WriteBlock[@strikeWidth, SIZE[CARDINAL]]; FOR c: CHAR IN [min..max] DO charRep: InternalCharRep _ internalFont.charRep[c]; IF charRep # internalFont.defaultChar THEN { IF charRep.pixels.sSize # 0 THEN strikeWidth _ strikeWidth + charRep.pixels.fSize; }; WriteBlock[@strikeWidth, SIZE[CARDINAL]]; ENDLOOP; IF internalFont.defaultChar.pixels.sSize # 0 THEN strikeWidth _ strikeWidth + internalFont.defaultChar.pixels.fSize; WriteBlock[@strikeWidth, SIZE[CARDINAL]]; IF file.GetIndex-bodyStart # body.length*Basics.bytesPerWord THEN ERROR; FOR c: CHAR IN [min..max] DO widthEntry _ IF internalFont.charRep[c] = internalFont.defaultChar THEN widthEntry _ StrikeFontFormat.nullWidthEntry ELSE ComputeWidthEntry[internalFont.charRep[c], fMin]; WriteBlock[@widthEntry, SIZE[StrikeFontFormat.WidthEntry]]; ENDLOOP; widthEntry _ ComputeWidthEntry[internalFont.defaultChar, fMin]; WriteBlock[@widthEntry, SIZE[StrikeFontFormat.WidthEntry]]; }; file.Close; }; WriteStrike: PUBLIC PROC [internalFont: InternalFont, fileName: Rope.ROPE] ~ TRUSTED { file: IO.STREAM _ FS.StreamOpen[fileName, $create]; WriteBlock: UNSAFE PROC [source: LONG POINTER, words: CARDINAL] ~ UNCHECKED { file.UnsafePutBlock[[source, 0, words*Basics.bytesPerWord]]; }; header: StrikeFontFormat.Header; strike: ImagerPixelMap.PixelMap; body: StrikeFontFormat.Body; min, max: CHAR; sMin, fMin, sMax, fMax: INTEGER; maxwidth, strikeWidth: CARDINAL; [min, max, sMin, fMin, sMax, fMax, maxwidth, strikeWidth, ----] _ ComputeFontMetrics[internalFont]; IF max>=min THEN { ascent: NAT _ -sMin; descent: NAT _ sMax; bodyStart: INT; strike _ ImagerPixelMap.Create[0, [-ascent, 0, ascent+descent, strikeWidth]]; strike.Clear; strikeWidth _ 0; FOR c: CHAR IN [min..max] DO IF internalFont.charRep[c] # internalFont.defaultChar THEN { strike.Transfer[internalFont.charRep[c].pixels.ShiftMap[0, strikeWidth]]; strikeWidth _ strikeWidth + Real.RoundLI[internalFont.charRep[c].fWidth]; }; ENDLOOP; strike.Transfer[internalFont.defaultChar.pixels.ShiftMap[0, strikeWidth]]; header.oneBit _ T; header.index _ F; header.fixed _ F; header.kerned _ F; header.unused _ 0; header.min _ ORD[min]; header.max _ ORD[max]; header.maxwidth _ maxwidth; body.length _ strike.refRep.words+SIZE[StrikeFontFormat.Body]+(max-min+1+2)*SIZE[CARDINAL]; body.ascent _ ascent; body.descent _ descent; body.xoffset _ 0; body.raster _ strike.refRep.rast; WriteBlock[@header, SIZE[StrikeFontFormat.Header]]; bodyStart _ file.GetIndex; WriteBlock[@body, SIZE[StrikeFontFormat.Body]]; WriteBlock[strike.refRep.pointer, strike.refRep.words]; strikeWidth _ 0; WriteBlock[@strikeWidth, SIZE[CARDINAL]]; FOR c: CHAR IN [min..max] DO IF internalFont.charRep[c] # internalFont.defaultChar THEN { strikeWidth _ strikeWidth + Real.RoundLI[internalFont.charRep[c].fWidth]; }; WriteBlock[@strikeWidth, SIZE[CARDINAL]]; ENDLOOP; strikeWidth _ strikeWidth + Real.RoundLI[internalFont.defaultChar.fWidth]; WriteBlock[@strikeWidth, SIZE[CARDINAL]]; IF file.GetIndex-bodyStart # body.length*Basics.bytesPerWord THEN ERROR; }; file.Close; }; WriteNameEntry: PROC [file: IO.STREAM, code: FEPressFontFormat.FontCode, name: Rope.ROPE] ~ TRUSTED { WriteBlock: UNSAFE PROC [source: LONG POINTER, words: CARDINAL] ~ UNCHECKED { file.UnsafePutBlock[[source, 0, words*Basics.bytesPerWord]]; }; shortenedName: Rope.ROPE _ name.Substr[len: 19]; length: NAT _ shortenedName.Length; hdr: FEPressFontFormat.IndexHeader _ [type: name, length: 12]; WriteBlock[@hdr, SIZE[FEPressFontFormat.IndexHeader]]; file.PutChar['\000]; file.PutChar['\000+code]; file.PutChar['\000+length]; file.PutRope[shortenedName]; WHILE length < 19 DO file.PutChar['\000]; length _ length + 1 ENDLOOP; }; WriteAC: PUBLIC PROC [internalFont: InternalFont, fileName: Rope.ROPE] ~ TRUSTED { micaSize: REAL _ internalFont.bitsPerEmQuad/internalFont.bitsPerInch*2540.0; bitsPerInchX: REAL _ internalFont.bitsPerInch; bitsPerInchY: REAL _ internalFont.bitsPerInch; file: IO.STREAM _ FS.StreamOpen[fileName, $create]; WriteBlock: UNSAFE PROC [source: LONG POINTER, words: INT] ~ UNCHECKED { file.UnsafePutBlock[[source, 0, words*Basics.bytesPerWord]]; }; CurWordOffset: PROC RETURNS [wordOffset: INT] ~ CHECKED { wordOffset _ file.GetIndex/Basics.bytesPerWord; }; min, max: CHAR; endIndexEntry: FEPressFontFormat.IndexHeader _ [type: end, length: SIZE[FEPressFontFormat.IndexHeader]]; charsIndexEntryByteLoc: INT; charsIndexEntry: FEPressFontFormat.RawIndex.chars; pixelMap: ImagerPixelMap.PixelMap _ ImagerPixelMap.Create[0, [0,0,16,16]]; pixelMap.Clear; [min, max, ----, ----, ----, ----, ----, ----, ----] _ ComputeFontMetrics[internalFont]; charsIndexEntry _ [ hdr: [type: chars, length: SIZE[FEPressFontFormat.RawIndex.chars]], variantPart: chars[ family: 0, face: internalFont.face, bc: min, ec: max, size: Real.RoundLI[micaSize], rotation: 0, startaddress: [0,0], length: [0,0], resolutionx: Real.RoundLI[bitsPerInchX*10], resolutiony: Real.RoundLI[bitsPerInchY*10] ] ]; WriteNameEntry[file, 0, internalFont.family]; charsIndexEntryByteLoc _ file.GetIndex; IF max>=min THEN { WriteBlock[@charsIndexEntry, charsIndexEntry.hdr.length]; }; WriteBlock[@endIndexEntry, SIZE[FEPressFontFormat.IndexHeader]]; IF max>=min THEN { startaddress: INT _ CurWordOffset[]; directoryStart, filePos: INT; missingCharData: FEPressFontFormat.BoundingBox _ [xwidth: [0, 0], ywidth: [0, 0], BBox: 0, BBoy: 0, BBdx: 0, BBdy: LAST[CARDINAL]]; missingCharDirectoryMarker: FEPressFontFormat.bcplLONGCARDINAL _ [LAST[CARDINAL], LAST[CARDINAL]]; FOR c: CHAR IN [min..max] DO IF internalFont.charRep[c] = internalFont.defaultChar THEN { WriteBlock[@missingCharData, SIZE[FEPressFontFormat.BoundingBox]]; } ELSE { charRep: InternalCharRep ~ internalFont.charRep[c]; window: ImagerPixelMap.DeviceRectangle _ charRep.pixels.Window; xwidth: FEPressFontFormat.Fraction ~ Real.RoundLI[charRep.fWidth * 65536]; ywidth: FEPressFontFormat.Fraction ~ Real.RoundLI[-charRep.sWidth * 65536]; charData: FEPressFontFormat.BoundingBox _ [ xwidth: FEPressFontFormat.MesaToBcplFraction[xwidth], ywidth: FEPressFontFormat.MesaToBcplFraction[ywidth], BBox: window.fMin, BBoy: -window.sSize-window.sMin, BBdx: window.fSize, BBdy: window.sSize ]; WriteBlock[@charData, SIZE[FEPressFontFormat.BoundingBox]]; }; ENDLOOP; directoryStart _ CurWordOffset[]; filePos _ directoryStart + (max-min+1)*SIZE[FEPressFontFormat.bcplLONGCARDINAL]; FOR c: CHAR IN [min..max] DO charRep: InternalCharRep ~ internalFont.charRep[c]; IF charRep = internalFont.defaultChar THEN { WriteBlock[@missingCharDirectoryMarker, SIZE[FEPressFontFormat.bcplLONGCARDINAL]]; } ELSE { relFilePos: FEPressFontFormat.bcplLONGCARDINAL _ FEPressFontFormat.MesaToBcplLongCardinal[filePos-directoryStart]; bbdx: NAT ~ charRep.pixels.fSize; bbdy: NAT ~ charRep.pixels.sSize; bbdyW: NAT ~ (bbdy+Basics.bitsPerWord-1)/Basics.bitsPerWord; WriteBlock[@relFilePos, SIZE[FEPressFontFormat.bcplLONGCARDINAL]]; filePos _ filePos + 1 + INT[bbdyW]*bbdx; }; ENDLOOP; IF CurWordOffset[] # directoryStart + (max-min+1)*SIZE[FEPressFontFormat.bcplLONGCARDINAL] THEN ERROR; FOR c: CHAR IN [min..max] DO charRep: InternalCharRep ~ internalFont.charRep[c]; IF charRep # internalFont.defaultChar THEN { bbdx: NAT ~ charRep.pixels.fSize; bbdy: NAT ~ charRep.pixels.sSize; bbdyW: NAT ~ (bbdy+Basics.bitsPerWord-1)/Basics.bitsPerWord; rasterDef: MACHINE DEPENDENT RECORD [bbdyW: [0..64), bbdy: [0..1024)] _ [bbdyW, bbdx]; WriteBlock[@rasterDef, 1]; pixelMap _ ImagerPixelMap.Rotate[charRep.pixels, pixelMap.refRep]; IF pixelMap.refRep.lines # bbdx THEN ERROR; IF pixelMap.refRep.rast # bbdyW THEN ERROR; WriteBlock[pixelMap.refRep.pointer, INT[bbdyW]*bbdx]; }; ENDLOOP; IF filePos # CurWordOffset[] THEN ERROR; charsIndexEntry.startaddress _ LOOPHOLE[FEPressFontFormat.MesaToBcplLongCardinal[startaddress]]; charsIndexEntry.length _ FEPressFontFormat.MesaToBcplLongCardinal[CurWordOffset[] - startaddress]; file.SetIndex[charsIndexEntryByteLoc]; WriteBlock[@charsIndexEntry, charsIndexEntry.hdr.length]; }; file.Close; }; Trim: PUBLIC PROC [internalFont: InternalFont] ~ { oldDefault: InternalCharRep _ internalFont.defaultChar; internalFont.defaultChar.pixels _ internalFont.defaultChar.pixels.Trim[0]; FOR c: CHAR IN CHAR DO IF internalFont.charRep[c] = oldDefault THEN internalFont.charRep[c] _ internalFont.defaultChar ELSE internalFont.charRep[c].pixels _ internalFont.charRep[c].pixels.Trim[0]; ENDLOOP; }; END. 2RasterFontIOImpl.mesa Copyright c 1985 by Xerox Corporation. All rights reserved. Michael Plass, May 20, 1985 4:19:36 pm PDT Last changed by Pavel on October 12, 1984 6:21:43 pm PDT Removed some dependencies upon glyphs being small enough for 16-bit numbers. enables more stringent error checking. ΚΕ˜™Icodešœ Οmœ1™K˜K˜—šœžœ˜KšœB˜BK˜—š œžœ žœžœ!˜FKšœžœžœžœ˜,Kš  œžœ žœžœ žœ˜LKšœ ˜ Kšœžœžœ˜0Kšœ(˜(Kšœ.˜.Kšœžœžœ˜$Kšœžœžœ˜Kšœžœ˜$Kšœžœ˜Kš œ žœžœžœ$žœ˜AKš œ žœžœžœ%žœ˜CKšœ žœ˜šžœ‘˜Kšžœžœ!˜Fšžœ ž˜Kšœžœ˜ šœ ˜ Kšžœ žœžœ ‘˜Ušžœžœ$žœžœ˜LKšœžœ&˜C—Kšžœžœ ‘˜?šœ‘˜Kš œžœ žœžœžœžœžœ˜IKšœ1˜1K˜—Kšœ žœ˜K˜—šœ˜Kšžœ žœžœ ‘!˜\šžœžœ)žœžœ˜QKšœžœ+˜I—Kšžœžœ ‘˜?Kšœ žœ˜K˜—Kšžœžœ ‘˜H—Kšžœ˜—Kš žœ žœ žœžœž˜@Kšžœ ‘˜)Kšžœžœ ‘˜2KšœA‘ ˜MKšœD˜DKšœ-˜-Kšœ#˜#šžœ‘˜Kšœžœžœ˜ Kšœ&˜&K˜Kšœžœ8˜MK˜—Kšžœ˜KšœI˜IKšœ˜Kšœ˜Kšœ2˜2Kšœ.˜.Kšœ4˜4š žœžœžœžœ žœ ž˜0Jšœ žœžœ ˜!š œžœžœžœžœžœ"žœ˜QKšœžœ8˜?Kšžœžœžœžœ˜8Kšžœ˜Jšœ˜—Jšœ%˜%Jšžœ˜%šžœ-žœžœ˜=Kšœžœžœžœ+˜@Kšœžœ˜Kšœžœ˜šžœžœžœžœ˜:Kšœžœžœžœ ˜>KšœΝ˜ΝKšœ3˜3Kšœ2˜2Kšœ3˜3šœ˜Jšœ@˜@JšœA˜AJ•StartOfExpansion†[pointer: LONG POINTER, words: LONG CARDINAL, lgBitsPerPixel: [0..4], rast: CARDINAL, lines: CARDINAL, ref: REF ANY _ NIL]šœ˜Jšœ˜—Jšœ˜—Kšžœ ‘'˜4K˜—Jšžœ˜—K˜K˜—šœ žœžœ˜J™&J˜—š  œžœžœžœžœ žœ˜XJšœžœžœ˜*š  œžœžœžœžœ žœžœ ž œ˜`Jšžœžœ/˜FJšœ?˜?Jšœ˜—š   œžœžœžœžœ˜9Jšœ/˜/Jšœ˜—Jšœ ˜ Jšœ ˜ Jšœžœ˜$Jšœžœ˜5šžœžœžœžœ˜1Jšžœ ˜Jšžœ˜Jšœ˜—Jšžœžœžœžœ˜/Jšžœžœžœžœ˜.Jšžœžœžœ˜/šžœžœžœ˜Jšœ*˜*Jšœ˜Jšœžœ˜%Jšœžœ˜Jšœžœ˜Jšœ(˜(Jšœ žœ˜Jšœžœ ˜˜>Jšœžœ!˜6Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšžœ žœ*žœ˜FJšœ˜—J˜š  œžœžœ-žœžœ˜RJšœ žœ>˜LJšœžœ˜.Jšœžœ˜.Jšœžœžœ$˜3š  œžœžœ žœžœ žœž œ˜HJšœ<˜