<> <> <> <<>> DIRECTORY Environment, PDInterpBitmap, PDInterpSysCalls, PDTextBitmap, Stream, PDStrikeFormat, PDRemoteStream, Inline, String; PDTextBitmapImpl: PROGRAM IMPORTS PDInterpBitmap, PDInterpSysCalls, PDRemoteStream, Stream, Inline, String EXPORTS PDTextBitmap = BEGIN fontName: PUBLIC LONG STRING _ [120]; bc: CHAR = ' ; ec: CHAR = '~; charBitmap: ARRAY CHAR[bc..ec] OF PDInterpBitmap.BitmapDesc; charWidth: ARRAY CHAR[bc..ec] OF INTEGER; fontAscent: INTEGER _ 0; fontDescent: INTEGER _ 0; ksFontBuffer: LONG POINTER _ NIL; bytesPerWord: NAT = Environment.bytesPerWord; nilBitmap: PDInterpBitmap.BitmapDesc = [ sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0, sSize: 0, fSize: 0, pointer: NIL, rast: 0, lines: 0 ]; BadFont: ERROR = CODE; SetFont: PUBLIC PROC [fontFileName: LONG STRING, userName, password: LONG STRING] RETURNS [ok: BOOLEAN _ FALSE] = { cr: LONG STRING _ [40]; nameCopy: LONG STRING _ [120]; NameCopy: PROC RETURNS [LONG STRING] = { String.Copy[nameCopy, fontFileName]; RETURN [nameCopy] }; bytes: INT _ PDRemoteStream.Lookup[NameCopy[], cr, userName, password]; newBuffer: LONG POINTER _ NIL; bytesRead: INT _ 0; readFile: PROC[stream: Stream.Handle] = { bytesRead _ Stream.GetBlock[stream, [blockPointer: newBuffer, startIndex: 0, stopIndexPlusOne: bytes]].bytesTransferred; }; IF ksFontBuffer # NIL THEN { FOR c: CHAR IN [bc..ec] DO charBitmap[c] _ nilBitmap; charWidth[c] _ 0 ENDLOOP; PDInterpSysCalls.FreeSpace[ksFontBuffer]; fontAscent _ fontDescent _ 0; ksFontBuffer _ NIL }; fontName.length _ 0; newBuffer _ PDInterpSysCalls.AllocateSpace[(bytes+bytesPerWord-1)/bytesPerWord]; PDRemoteStream.Read[fontFileName, userName, password, readFile]; IF bytesRead # bytes THEN { PDInterpSysCalls.FreeSpace[newBuffer]; RETURN [FALSE] }; ok _ TRUE; ParseFont[fontFileName, newBuffer, bytes < {ok _ FALSE; CONTINUE};>> ]; IF ok THEN { ksFontBuffer _ newBuffer; } ELSE { FOR c: CHAR IN [bc..ec] DO charBitmap[c] _ nilBitmap; charWidth[c] _ 0 ENDLOOP; PDInterpSysCalls.FreeSpace[newBuffer]; fontAscent _ fontDescent _ 0; String.Copy[to: fontName, from: fontFileName]; }; }; ParseFont: PUBLIC PROC [fontFileName: LONG STRING, buffer: LONG POINTER, bytes: INT] = { wordIndex: INT _ 0; ReadBlock: PROC [dest: LONG POINTER, words: CARDINAL, wordOffset: INT _ -1] = { IF wordOffset >= 0 THEN wordIndex _ wordOffset; Inline.LongCOPY[from: buffer+wordIndex, nwords: words, to: dest]; wordIndex _ wordIndex + words; }; strike: PDInterpBitmap.BitmapDesc _ nilBitmap; defaultCharBitmap: PDInterpBitmap.BitmapDesc _ nilBitmap; defaultCharWidth: INTEGER _ 0; header: PDStrikeFormat.Header; ReadBlock[@header, SIZE[PDStrikeFormat.Header], 0]; IF header.format.oneBit # T THEN ERROR BadFont; IF header.format.index # F THEN ERROR BadFont; IF header.format.unused # 0 THEN ERROR BadFont; IF header.format.kerned = T THEN { boundingBox: PDStrikeFormat.BoundingBox; body: PDStrikeFormat.Body; xInSegment, prevXInSegment: CARDINAL; xInSegmentOffset: INT; widthEntryOffset: INT; widthEntry: PDStrikeFormat.WidthEntry; bodyOffset: INT; ReadBlock[@boundingBox, SIZE[PDStrikeFormat.BoundingBox]]; bodyOffset _ wordIndex; ReadBlock[@body, SIZE[PDStrikeFormat.Body]]; fontAscent _ body.ascent; fontDescent _ body.descent; strike _ [ sOrigin: -body.ascent, fOrigin: 0, sMin: 0, fMin: 0, sSize: body.ascent+body.descent, fSize: body.raster*Environment.bitsPerWord, pointer: buffer+wordIndex, rast: body.raster, lines: body.ascent+body.descent ]; wordIndex _ wordIndex + strike.rast*strike.lines; widthEntryOffset _ wordIndex+(header.max-header.min+3)*SIZE[CARDINAL]; IF widthEntryOffset # bodyOffset + body.length THEN ERROR BadFont; ReadBlock[@prevXInSegment, SIZE[CARDINAL]]; xInSegmentOffset _ wordIndex; FOR char: CHAR IN [header.min..header.max] DO charPixels: PDInterpBitmap.BitmapDesc _ strike; ReadBlock[@xInSegment, SIZE[CARDINAL], xInSegmentOffset]; xInSegmentOffset _ xInSegmentOffset + SIZE[CARDINAL]; ReadBlock[@widthEntry, SIZE[PDStrikeFormat.WidthEntry], widthEntryOffset]; widthEntryOffset _ widthEntryOffset + SIZE[PDStrikeFormat.WidthEntry]; IF widthEntry # PDStrikeFormat.nullWidthEntry THEN { IF widthEntry.width > header.maxwidth THEN ERROR BadFont; charPixels.fOrigin _ widthEntry.offset+boundingBox.fbbox-prevXInSegment; charPixels.fMin _ prevXInSegment; charPixels.fSize _ xInSegment-prevXInSegment; IF char IN [bc..ec] THEN { charBitmap[char] _ charPixels; charWidth[char] _ widthEntry.width; }; }; prevXInSegment _ xInSegment; ENDLOOP; ReadBlock[@xInSegment, SIZE[CARDINAL], xInSegmentOffset]; xInSegmentOffset _ xInSegmentOffset + SIZE[CARDINAL]; ReadBlock[@widthEntry, SIZE[PDStrikeFormat.WidthEntry], widthEntryOffset]; widthEntryOffset _ widthEntryOffset + SIZE[PDStrikeFormat.WidthEntry]; IF widthEntry # PDStrikeFormat.nullWidthEntry THEN { strike.fOrigin _ widthEntry.offset+boundingBox.fbbox-prevXInSegment; strike.fMin _ prevXInSegment; strike.fSize _ xInSegment-prevXInSegment; defaultCharBitmap _ strike; defaultCharWidth _ widthEntry.width; } ELSE ERROR BadFont; } ELSE ERROR BadFont; FOR char: CHAR IN [bc..ec] DO IF charBitmap[char].pointer = NIL THEN { charBitmap[char] _ defaultCharBitmap; charWidth[char] _ defaultCharWidth; }; ENDLOOP; IF wordIndex*bytesPerWord # bytes THEN ERROR BadFont; }; FontAscent: PUBLIC PROC RETURNS [INTEGER] = {RETURN [fontAscent]}; FontDescent: PUBLIC PROC RETURNS [INTEGER] = {RETURN [fontDescent]}; TextWidth: PUBLIC PROC [string: LONG STRING, start: NAT _ 0, length: NAT _ NAT.LAST] RETURNS [textWidth: INTEGER] = { textWidth _ 0; FOR i: NAT IN [start..start+length) DO IF i >= string.length THEN EXIT ELSE { char: CHAR _ string[i]; IF char IN [bc..ec] THEN textWidth _ textWidth + charWidth[char]; }; ENDLOOP; }; TextToBitmap: PUBLIC PROC [dest: PDInterpBitmap.BitmapDesc, string: LONG STRING, start: NAT _ 0, length: NAT _ NAT.LAST, function: PDInterpBitmap.Function] = { w: INTEGER _ 0; FOR i: NAT IN [start..start+length) DO IF i >= string.length THEN EXIT ELSE { char: CHAR _ string[i]; IF char IN [bc..ec] THEN { bitmap: PDInterpBitmap.BitmapDesc _ charBitmap[char]; bitmap.fOrigin _ bitmap.fOrigin + w; PDInterpBitmap.Transfer[dest, bitmap, function]; w _ w + charWidth[char]; }; }; ENDLOOP; }; END.