DIRECTORY Ascii USING [NUL], ImagerBasic USING [Pair, PathMapType, Transformation], UFPressFontReader, ImagerScanConverter USING [ConvertToRuns, CreatePath, DevicePath, PathProc], PressFontFormat, Real USING [MinusZero], RealConvert USING [BcplToIeee], Rope USING [FromProc], UFFileManager, Font USING [Box, FONT, FontGraphicsClassRec, Key, RegisterFontGraphicsClass, Transformation]; UFPressFontReaderImpl: CEDAR MONITOR -- monitored because of devicePath IMPORTS Font, ImagerScanConverter, PressFontFormat, RealConvert, Rope, UFFileManager EXPORTS UFPressFontReader = BEGIN OPEN UFPressFontReader, F: PressFontFormat; FONT: TYPE = Font.FONT; Pair: TYPE = ImagerBasic.Pair; zero: REAL = Real.MinusZero; FontFile: TYPE = UFFileManager.FontFile; FontVector: TYPE = REF FontVectorRec; FontVectorRec: TYPE = RECORD [ names: LIST OF CodeNamePair, fonts: SEQUENCE length: NAT OF PressFontRec ]; CodeNamePair: TYPE = RECORD [ code: [0..256), name: ROPE ]; PressFontRec: TYPE = RECORD [ rawIndexPtr: LONG POINTER, procs: Procs, data: REF ]; Procs: TYPE = REF ProcsRec; ProcsRec: TYPE = RECORD [ charInfoProc: PROC [data: REF, char: CHAR] RETURNS [info: CharInfo] ]; Object: TYPE = RECORD [procs: Procs, data: REF]; FontPrivateRec: TYPE = F.FontPrivateRec; Error: PUBLIC SIGNAL[errorCode: ErrorCode, fontFileWordOffset: INT] = CODE; OpenInitialization: UFFileManager.InitProc = TRUSTED { fontVector: FontVector; fontCount: NAT _ 0; countProc: VisitProc = TRUSTED { SELECT p.hdr.type FROM splines, chars, widths => { fontCount _ fontCount+1; }; ENDCASE; }; saveProc: VisitProc = TRUSTED { SELECT p.hdr.type FROM splines, chars, widths => { fontVector[fontCount].rawIndexPtr _ p; fontCount _ fontCount+1; }; name => { pp: LONG POINTER _ p; nameIndex: LONG POINTER TO name F.RawIndex _ pp; fontVector.names _ CONS[[nameIndex.code, ExtractName[nameIndex]], fontVector.names] }; ENDCASE; }; EnumerateIndex[fontFile, countProc]; fontVector _ NEW[FontVectorRec[fontCount]]; fontCount _ 0; EnumerateIndex[fontFile, saveProc]; RETURN[fontVector]; }; NameFromCode: PROCEDURE [names: LIST OF CodeNamePair, code: [0..256)] RETURNS [ROPE] = { FOR n: LIST OF CodeNamePair _ names, n.rest UNTIL n=NIL DO IF n.first.code = code THEN RETURN [n.first.name]; ENDLOOP; RETURN [NIL] }; ExtractName: PROCEDURE [p: LONG POINTER TO name F.RawIndex] RETURNS [rope: ROPE] = TRUSTED { i: NAT _ 1; len: [0..20) _ p.fontname[0]-Ascii.NUL; charProc: SAFE PROC RETURNS [char: CHAR] = TRUSTED { char _ p.fontname[i]; i _ i + 1; }; rope _ Rope.FromProc[len, charProc]; }; VisitProc: TYPE = PROCEDURE [openFile: FontFile, p: LONG POINTER TO F.RawIndex] RETURNS [quit: BOOLEAN _ FALSE]; EnumerateIndex: PROCEDURE [openFile: FontFile, visitProc: VisitProc] = TRUSTED { p: LONG POINTER TO F.RawIndex _ openFile.Pointer; offset: INT _ 0; DO p: LONG POINTER TO F.RawIndex _ openFile.Pointer[] + offset; IF NOT openFile.InBounds[p, p.hdr.length] THEN ERROR Error[fontIndexTooLong, offset]; IF visitProc[openFile, p] THEN EXIT; IF p.hdr.type = end THEN EXIT; offset _ offset + p.hdr.length; ENDLOOP }; NumberOfFontsInFile: PUBLIC PROCEDURE [fileKey: Font.Key] RETURNS [NAT] = { file: FontFile _ UFFileManager.Open[fileKey, OpenInitialization]; data: FontVector _ NARROW[file.GetData[]]; RETURN[data.length]; }; Family: PUBLIC PROCEDURE [fontKey: FontKey] RETURNS [family: ROPE] = TRUSTED { file: FontFile _ UFFileManager.Open[fontKey.fileKey, OpenInitialization]; data: FontVector _ NARROW[file.GetData[]]; p: LONG POINTER TO chars F.RawIndex _ data[fontKey.fontIndex].rawIndexPtr; family _ NameFromCode[data.names, p.family]; }; Face: PUBLIC PROCEDURE [fontKey: FontKey] RETURNS [face: [0..256)] = TRUSTED { file: FontFile _ UFFileManager.Open[fontKey.fileKey, OpenInitialization]; data: FontVector _ NARROW[file.GetData[]]; p: LONG POINTER TO chars F.RawIndex _ data[fontKey.fontIndex].rawIndexPtr; face _ p.face; }; Range: PUBLIC PROCEDURE [fontKey: FontKey] RETURNS [bc, ec: CHAR] = TRUSTED { file: FontFile _ UFFileManager.Open[fontKey.fileKey, OpenInitialization]; data: FontVector _ NARROW[file.GetData[]]; p: LONG POINTER TO chars F.RawIndex _ data[fontKey.fontIndex].rawIndexPtr; bc _ p.bc; ec _ p.ec; }; Size: PUBLIC PROCEDURE [fontKey: FontKey] RETURNS [size: REAL] = TRUSTED { file: FontFile _ UFFileManager.Open[fontKey.fileKey, OpenInitialization]; data: FontVector _ NARROW[file.GetData[]]; p: LONG POINTER TO chars F.RawIndex _ data[fontKey.fontIndex].rawIndexPtr; size _ p.size/100000.0; }; Rotation: PUBLIC PROCEDURE [fontKey: FontKey] RETURNS [rotation: REAL] = TRUSTED { file: FontFile _ UFFileManager.Open[fontKey.fileKey, OpenInitialization]; data: FontVector _ NARROW[file.GetData[]]; p: LONG POINTER TO chars F.RawIndex _ data[fontKey.fontIndex].rawIndexPtr; rotation _ p.rotation/60.0; }; Representation: PUBLIC PROCEDURE [fontKey: FontKey] RETURNS [representation: CharShapeRepresentation] = TRUSTED { file: FontFile _ UFFileManager.Open[fontKey.fileKey, OpenInitialization]; data: FontVector _ NARROW[file.GetData[]]; p: LONG POINTER TO chars F.RawIndex _ data[fontKey.fontIndex].rawIndexPtr; representation _ SELECT p.hdr.type FROM splines => outline, chars => raster, widths => widthsOnly, ENDCASE => ERROR; }; Resolution: PUBLIC PROCEDURE [fontKey: FontKey] RETURNS [xRes, yRes: REAL] = TRUSTED { file: FontFile _ UFFileManager.Open[fontKey.fileKey, OpenInitialization]; data: FontVector _ NARROW[file.GetData[]]; p: LONG POINTER TO chars F.RawIndex _ data[fontKey.fontIndex].rawIndexPtr; IF p.hdr.type # chars THEN {xRes _ yRes _ zero} ELSE { xRes _ p.resolutionx/10.0; yRes _ p.resolutiony/10.0; } }; GetCharInfo: PUBLIC PROCEDURE [fontKey: FontKey, char: CHAR] RETURNS [info: CharInfo] = TRUSTED { fontFile: FontFile _ UFFileManager.Open[fontKey.fileKey, OpenInitialization]; object: Object _ GetObject[fontFile, fontKey]; info _ object.procs.charInfoProc[object.data, char]; }; CharPathData: TYPE = RECORD [fontKey: FontKey, char: CHAR]; GenerateCharPath: PROCEDURE [ data: REF, move: PROC [Pair], line: PROC [Pair], curve: PROC [Pair, Pair, Pair], conic: PROC [Pair, Pair, REAL] ] = { moveToProc: UFPressFontReader.MoveToProc = {move[[x, y]]}; lineToProc: UFPressFontReader.LineToProc = {line[[x, y]]}; curveToProc: UFPressFontReader.CurveToProc = {curve[[x1, y1], [x2, y2], [x3, y3]]}; drawAreaProc: UFPressFontReader.DrawAreaProc = {}; d: REF CharPathData _ NARROW[data]; GetCharOutline[d.fontKey, d.char, moveToProc, lineToProc, curveToProc, drawAreaProc]; }; GetCharPath: PUBLIC PROCEDURE [fontKey: FontKey, char: CHAR] RETURNS [pathMap: ImagerBasic.PathMapType, pathData: REF] = { RETURN[pathMap: GenerateCharPath, pathData: NEW[CharPathData _ [fontKey, char]]]; }; GetObject: PROCEDURE [fontFile: FontFile, fontKey: FontKey] RETURNS [object: Object] = TRUSTED { fontVector: FontVector _ NARROW[fontFile.GetData[]]; charsIndexPtr: LONG POINTER TO chars F.RawIndex _ fontVector[fontKey.fontIndex].rawIndexPtr; IF fontVector[fontKey.fontIndex].data = NIL THEN { charsIndexPtr: LONG POINTER TO chars F.RawIndex _ fontVector[fontKey.fontIndex].rawIndexPtr; SELECT charsIndexPtr.hdr.type FROM chars => MakeCharsObject[fontFile, fontVector, fontKey]; splines => MakeSplinesObject[fontFile, fontVector, fontKey]; widths => MakeWidthsObject[fontFile, fontVector, fontKey]; ENDCASE => ERROR; }; object _ [fontVector[fontKey.fontIndex].procs, fontVector[fontKey.fontIndex].data]; }; RasterData: TYPE = REF RasterDataRec; RasterDataRec: TYPE = RECORD [ indexEntry: LONG POINTER TO chars F.RawIndex, dataDesc: F.CharBboxDesc, dirDesc: F.CharDirDesc, rasterStart, rasterEnd: LONG CARDINAL, base: LONG POINTER ]; MakeCharsObject: PROCEDURE [fontFile: FontFile, fontVector: FontVector, fontKey: FontKey] = TRUSTED { rasterData: RasterData _ NEW[RasterDataRec]; ix: LONG POINTER TO chars F.RawIndex _ fontVector[fontKey.fontIndex].rawIndexPtr; base: LONG POINTER _ fontFile.Pointer[]; nChars: NAT _ ix.ec - ix.bc + 1; dataOffset, dirOffset, rasterOffset: LONG CARDINAL; IF ix.hdr.type # chars THEN ERROR Error[cantHappen, ix-base]; dataOffset _ F.LongCardinalFromBcplLongPointer[ix.startaddress]; dirOffset _ dataOffset + nChars*SIZE[F.BoundingBox]; rasterOffset _ dirOffset + nChars*SIZE[F.bcplLONGPOINTER]; IF rasterOffset - dataOffset > F.BcplToMesaLongCardinal[ix.length] THEN ERROR Error[dataSegmentTooLong, dataOffset]; rasterData.indexEntry _ ix; rasterData.rasterStart _ rasterOffset; rasterData.rasterEnd _ dataOffset + F.BcplToMesaLongCardinal[ix.length]; rasterData.dataDesc _ DESCRIPTOR[base+dataOffset, nChars]; rasterData.dirDesc _ DESCRIPTOR[base+dirOffset, nChars]; rasterData.base _ base; fontVector[fontKey.fontIndex].procs _ charsProcs; fontVector[fontKey.fontIndex].data _ rasterData; }; charsProcs: Procs _ NEW[ProcsRec _ [ charInfoProc: CharsCharInfo ]]; CharsCharInfo: PROCEDURE [data: REF, char: CHAR] RETURNS [info: CharInfo] = TRUSTED { rasterData: RasterData _ NARROW[data]; ix: LONG POINTER TO chars F.RawIndex _ rasterData.indexEntry; IF ix.hdr.type # chars THEN ERROR Error[cantHappen, 0]; IF (NOT char IN [ix.bc..ix.ec]) THEN RETURN[[zero,zero,zero,zero,zero,zero]] ELSE { data: F.BoundingBox _ rasterData.dataDesc[char-ix.bc]; xscale: REAL _ 25400.0/(INT[ix.resolutionx]*ix.size); yscale: REAL _ 25400.0/(INT[ix.resolutiony]*ix.size); IF data.BBdy = LAST[CARDINAL] THEN RETURN[[zero,zero,zero,zero,zero,zero]]; info.widthX _ BcplFractionToMesaReal[data.xwidth]*xscale; info.widthY _ BcplFractionToMesaReal[data.ywidth]*yscale; info.minX _ data.BBox*xscale; info.minY _ data.BBoy*yscale; info.maxX _ data.BBdx*xscale + info.minX; info.maxY _ data.BBdy*yscale + info.minY; }; }; SplinesData: TYPE = REF SplinesDataRec; SplinesDataRec: TYPE = RECORD [ indexEntry: LONG POINTER TO splines F.RawIndex, dataDesc: F.SplineDataDesc, dirDesc: F.SplineDirDesc, commandStart, commandEnd: LONG CARDINAL, fontKey: FontKey, base: LONG POINTER ]; MakeSplinesObject: PROCEDURE [fontFile: FontFile, fontVector: FontVector, fontKey: FontKey] = TRUSTED { splinesData: SplinesData _ NEW[SplinesDataRec]; ix: LONG POINTER TO splines F.RawIndex _ fontVector[fontKey.fontIndex].rawIndexPtr; base: LONG POINTER _ fontFile.Pointer[]; nChars: NAT _ ix.ec - ix.bc + 1; dataOffset, dirOffset, commandOffset: LONG CARDINAL; IF ix.hdr.type # splines THEN ERROR Error[cantHappen, ix-base]; dataOffset _ F.LongCardinalFromBcplLongPointer[ix.startaddress]; dirOffset _ dataOffset + nChars*SIZE[F.BcplSplineData]; commandOffset _ dirOffset + nChars*SIZE[F.bcplLONGPOINTER]; IF commandOffset - dataOffset > F.BcplToMesaLongCardinal[ix.length] THEN ERROR Error[dataSegmentTooLong, dataOffset]; splinesData.indexEntry _ ix; splinesData.commandStart _ commandOffset; splinesData.commandEnd _ dataOffset + F.BcplToMesaLongCardinal[ix.length]; splinesData.dataDesc _ DESCRIPTOR[base+dataOffset, nChars]; splinesData.dirDesc _ DESCRIPTOR[base+dirOffset, nChars]; splinesData.base _ base; splinesData.fontKey _ fontKey; fontVector[fontKey.fontIndex].procs _ splinesProcs; fontVector[fontKey.fontIndex].data _ splinesData; }; splinesProcs: Procs _ NEW[ProcsRec _ [ charInfoProc: SplinesCharInfo ]]; SplinesCharInfo: PROCEDURE [data: REF, char: CHAR] RETURNS [info: CharInfo] = TRUSTED { splinesData: SplinesData _ NARROW[data]; ix: LONG POINTER TO splines F.RawIndex _ splinesData.indexEntry; IF ix.hdr.type # splines THEN ERROR Error[cantHappen, 0]; IF (NOT char IN [ix.bc..ix.ec]) OR splinesData.dataDesc[char-ix.bc].xwidth = F.missingCharValue THEN RETURN[[zero,zero,zero,zero,zero,zero]] ELSE { data: F.BcplSplineData _ splinesData.dataDesc[char-ix.bc]; info.widthX _ BcplToMesaReal[data.xwidth]; info.widthY _ BcplToMesaReal[data.ywidth]; info.minX _ BcplToMesaReal[data.bbox]; info.minY _ BcplToMesaReal[data.bboy]; info.maxX _ BcplToMesaReal[data.rightx]; info.maxY _ BcplToMesaReal[data.topy]; }; }; BcplToMesaReal: PROCEDURE [b: F.BcplREAL] RETURNS [r: REAL] = TRUSTED { r _ RealConvert.BcplToIeee[LOOPHOLE[b]] }; BcplFractionToMesaReal: PROCEDURE [f: F.bcplFraction] RETURNS [r: REAL] = TRUSTED { r _ F.BcplToMesaFraction[f]/(LAST[CARDINAL]+1.0); }; GetCharOutline: PUBLIC PROCEDURE [ fontKey: FontKey, char: CHAR, moveToProc: MoveToProc, lineToProc: LineToProc, curveToProc: CurveToProc, drawAreaProc: DrawAreaProc ] = TRUSTED { p: LONG POINTER; curX, curY: REAL _ 0.0; file: FontFile _ UFFileManager.Open[fontKey.fileKey, OpenInitialization]; object: Object _ GetObject[file, fontKey]; splinesData: SplinesData _ NARROW[object.data]; bc: CHAR _ splinesData.indexEntry.bc; IF splinesData.indexEntry.hdr.type # splines THEN ERROR Error[cantHappen, 0]; IF NOT char IN [bc..splinesData.indexEntry.ec] THEN RETURN; IF splinesData.dataDesc[char-bc].xwidth = F.missingCharValue THEN RETURN; p _ BASE[splinesData.dirDesc] + F.LongCardinalFromBcplLongPointer[splinesData.dirDesc[char-bc]]; DO splineCommand: LONG POINTER TO F.BcplSplineCommand _ p; IF (p-splinesData.base) < splinesData.commandStart OR (p-splinesData.base) >= splinesData.commandEnd THEN ERROR Error[invalidPointerInFile, @(splinesData.dirDesc[char-bc])-splinesData.base]; SELECT splineCommand.type FROM F.moveToCode => {cmd: LONG POINTER TO MoveTo F.BcplSplineCommand _ p; moveToProc[curX _ BcplToMesaReal[cmd.x], curY _ BcplToMesaReal[cmd.y]]; p _ p + SIZE[MoveTo F.BcplSplineCommand]; }; F.drawToCode => {cmd: LONG POINTER TO DrawTo F.BcplSplineCommand _ p; lineToProc[curX _ BcplToMesaReal[cmd.x], curY _ BcplToMesaReal[cmd.y]]; p _ p + SIZE[DrawTo F.BcplSplineCommand]; }; F.drawCurveCode => {cmd: LONG POINTER TO DrawCurve F.BcplSplineCommand _ p; b: Bezier _ CoeffsToBezier[[ [curX, curY], [BcplToMesaReal[cmd.x0], BcplToMesaReal[cmd.y0]], [BcplToMesaReal[cmd.x1], BcplToMesaReal[cmd.y1]], [BcplToMesaReal[cmd.x2], BcplToMesaReal[cmd.y2]] ]]; [curX, curY] _ b.b3; curveToProc[b.b1.x, b.b1.y, b.b2.x, b.b2.y, b.b3.x, b.b3.y]; p _ p + SIZE[DrawCurve F.BcplSplineCommand]; }; F.newObjectCode => { drawAreaProc[]; p _ p + SIZE[NewObject F.BcplSplineCommand]; }; F.endSplineCode => { drawAreaProc[]; EXIT }; ENDCASE => ERROR Error[invalidCodeInFile, p-splinesData.base]; ENDLOOP }; Vec: TYPE = RECORD[x, y: REAL]; VecAdd: PROCEDURE [a: Vec, b: Vec] RETURNS [Vec] = INLINE {RETURN[[a.x+b.x,a.y+b.y]]}; VecSub: PROCEDURE [a: Vec, b: Vec] RETURNS [Vec] = INLINE {RETURN[[a.x-b.x,a.y-b.y]]}; VecDiv: PROCEDURE [a: Vec, s: REAL] RETURNS [Vec] = INLINE {RETURN[[a.x/s,a.y/s]]}; Coeffs: TYPE = RECORD[c0,c1,c2,c3: Vec]; Bezier: TYPE = RECORD[b0,b1,b2,b3: Vec]; CoeffsToBezier: PROCEDURE [c: Coeffs] RETURNS [b: Bezier] = { OPEN b,c; b0_c0; b1_VecAdd[c0,VecDiv[c1,3]]; b2_VecAdd[b1,VecDiv[VecAdd[c1,c2],3]]; b3_VecAdd[VecAdd[VecAdd[c0,c1],c2],c3]; }; WidthsData: TYPE = REF WidthsDataRec; WidthsDataRec: TYPE = RECORD [ indexEntry: LONG POINTER TO widths F.RawIndex, widthSeg: LONG POINTER TO F.BcplWidthSegment, xWidthDesc: LONG DESCRIPTOR FOR ARRAY OF CARDINAL, yWidthDesc: LONG DESCRIPTOR FOR ARRAY OF CARDINAL ]; MakeWidthsObject: PROCEDURE [fontFile: FontFile, fontVector: FontVector, fontKey: FontKey] = TRUSTED { widthsData: WidthsData _ NEW[WidthsDataRec]; ix: LONG POINTER TO widths F.RawIndex _ fontVector[fontKey.fontIndex].rawIndexPtr; base: LONG POINTER _ fontFile.Pointer[]; nChars: NAT _ ix.ec - ix.bc + 1; segOffset, xWidthOffset, yWidthOffset: LONG CARDINAL; nx, ny: NAT; IF ix.hdr.type # widths THEN ERROR Error[cantHappen, ix-base]; segOffset _ F.LongCardinalFromBcplLongPointer[ix.startaddress]; widthsData.indexEntry _ ix; widthsData.widthSeg _ base + segOffset; nx _ IF widthsData.widthSeg.XWidthFixed THEN 1 ELSE nChars; ny _ IF widthsData.widthSeg.YWidthFixed THEN 1 ELSE nChars; xWidthOffset _ segOffset + SIZE[F.BcplWidthSegment]; yWidthOffset _ xWidthOffset + nx; widthsData.xWidthDesc _ DESCRIPTOR[fontFile.Pointer[]+xWidthOffset, nx]; widthsData.yWidthDesc _ DESCRIPTOR[fontFile.Pointer[]+yWidthOffset, ny]; IF yWidthOffset + ny - segOffset # F.BcplToMesaLongCardinal[ix.length] THEN ERROR Error [consistencyCheck, ix-fontFile.Pointer[]]; fontVector[fontKey.fontIndex].procs _ widthsProcs; fontVector[fontKey.fontIndex].data _ widthsData; }; widthsProcs: Procs _ NEW[ProcsRec _ [ charInfoProc: WidthsCharInfo ]]; WidthsCharInfo: PROCEDURE [data: REF, char: CHAR] RETURNS [info: CharInfo] = TRUSTED { widthsData: WidthsData _ NARROW[data]; ix: LONG POINTER TO widths F.RawIndex _ widthsData.indexEntry; IF ix.hdr.type # widths THEN ERROR Error[cantHappen, 0]; IF (NOT char IN [ix.bc..ix.ec]) THEN RETURN[[zero,zero,zero,zero,zero,zero]] ELSE { data: F.BcplWidthSegment _ widthsData.widthSeg^; scale: REAL _ IF ix.size = 0 THEN 0.001 ELSE 1.0/ix.size; wx: INTEGER _ widthsData.xWidthDesc[IF data.XWidthFixed THEN 0 ELSE char-ix.bc]; wy: INTEGER _ widthsData.yWidthDesc[IF data.YWidthFixed THEN 0 ELSE char-ix.bc]; IF wx = FIRST[INTEGER] OR wy = FIRST[INTEGER] THEN RETURN[[zero,zero,zero,zero,zero,zero]]; info.widthX _ wx*scale; info.widthY _ wy*scale; info.minX _ data.FBBox*scale; info.minY _ data.FBBoy*scale; info.maxX _ data.FBBdx*scale + info.minX; info.maxY _ data.FBBdy*scale + info.minY; }; }; devicePath: ImagerScanConverter.DevicePath _ NIL; PFMask: ENTRY PROC [font: FONT, transformation: Font.Transformation, char: CHAR, run: PROC [sMin, fMin: INTEGER, fSize: NAT]] = { ENABLE UNWIND => NULL; GenPath: ImagerScanConverter.PathProc = { Xform: PROC [p: Pair] RETURNS [Pair] ~ {RETURN[[ transformation.a * p.x + transformation.b * p.y + transformation.c, transformation.d * p.x + transformation.e * p.y + transformation.f ]]}; moveToProc: UFPressFontReader.MoveToProc ~ { p: Pair = Xform[[x, y]]; move[p.x, p.y] }; lineToProc: UFPressFontReader.LineToProc ~ { p: Pair = Xform[[x, y]]; line[p.x, p.y] }; curveToProc: UFPressFontReader.CurveToProc ~ { p1: Pair = Xform[[x1, y1]]; p2: Pair = Xform[[x2, y2]]; p3: Pair = Xform[[x3, y3]]; curve[p1.x, p1.y, p2.x, p2.y, p3.x, p3.y] }; drawAreaProc: UFPressFontReader.DrawAreaProc = {}; GetCharOutline[[font.graphicsKey, 0], char, moveToProc, lineToProc, curveToProc, drawAreaProc]; }; devicePath _ ImagerScanConverter.CreatePath[pathProc: GenPath, scratch: devicePath]; devicePath.ConvertToRuns[runProc: run, parityFill: TRUE]; }; PFBoundingBox: PROCEDURE [font: FONT, char: CHAR] RETURNS [box: Font.Box] = { m: ImagerBasic.Transformation _ font.actualTransformation; B: PROC[p: Vec, box: Font.Box] RETURNS [Font.Box] = { x: REAL _ m.a * p.x + m.b * p.y + m.c; y: REAL _ m.d * p.x + m.e * p.y + m.f; RETURN [[ xmin: MIN[box.xmin, x], ymin: MIN[box.ymin, y], xmax: MAX[box.xmax, x], ymax: MAX[box.ymax, y] ]] }; charInfo: CharInfo _ GetCharInfo[[font.graphicsKey, 0], char]; x0: REAL _ charInfo.minX; y0: REAL _ charInfo.minY; x1: REAL _ charInfo.maxX; y1: REAL _ charInfo.maxY; box _ B[[x0,y0],B[[x0,y1],B[[x1,y0],[x1,y1,x1,y1]]]]; }; PFWidthVector: PROCEDURE [font: FONT, char: CHAR] RETURNS [Pair] = { m: ImagerBasic.Transformation _ font.actualTransformation; charInfo: CharInfo _ GetCharInfo[[font.graphicsKey, 0], char]; p: Vec _ [charInfo.widthX, charInfo.widthY]; RETURN [[ x: m.a * p.x + m.b * p.y + m.c, y: m.d * p.x + m.e * p.y + m.f ]]; }; PFContains: PROCEDURE [font: FONT, char: CHAR] RETURNS [BOOLEAN] = { charInfo: CharInfo _ GetCharInfo[[font.graphicsKey, 0], char]; RETURN[charInfo#[zero,zero,zero,zero,zero,zero]]; }; PFObjectInit: PROCEDURE [font: FONT] = { font.fontGraphicsClass _ PFClass; [font.bc, font.ec] _ Range[[font.graphicsKey, 0]]; }; PFClass: REF Font.FontGraphicsClassRec_NEW[Font.FontGraphicsClassRec_[ maskProc: PFMask, boundingBoxProc: PFBoundingBox, widthVectorProc: PFWidthVector, containsProc: PFContains ]]; Font.RegisterFontGraphicsClass[$Sd, PFObjectInit]; END. UFPressFontReaderImpl.mesa Created January 17, 1983 Last edit by Michael Plass on October 27, 1983 10:30 am Last edit by Doug Wyatt on October 3, 1983 2:42 pm A press font file can contain many fonts; the FontVector records where each one starts. The names and raw index pointers are computed when the font file is opened, and the font objects are filled in as needed. Strings in press font files are represented by one-byte codes; this list records the correspondence between codes and names for the file. This gets called when the font file is first opened; its responsibility is to initialize the FontVector that is recorded by the file manager. Raster format operations. CharsDrawChar: PROCEDURE [data: REF, context: Graphics.Context, char: CHAR] = TRUSTED { rasterData: RasterData _ NARROW[data]; ix: LONG POINTER TO chars F.RawIndex _ rasterData.indexEntry; scalex: REAL _ IF ix.size = 0 THEN 1.0 ELSE 25400.0/(INT[ix.resolutionx]*ix.size); scaley: REAL _ IF ix.size = 0 THEN 1.0 ELSE 25400.0/(INT[ix.resolutiony]*ix.size); Graphics.Scale[context, scalex, scaley]; Graphics.Rotate[context, - ix.rotation/60.0]; DrawCharRasterPrivate[context, rasterData, char]; }; DrawCharRasterPrivate: PROCEDURE [context: Graphics.Context, rasterData: RasterData, char: CHAR] = TRUSTED { ix: LONG POINTER TO chars F.RawIndex _ rasterData.indexEntry; data: F.BoundingBox _ rasterData.dataDesc[char-ix.bc]; offset: LONG CARDINAL _ F.LongCardinalFromBcplLongPointer[rasterData.dirDesc[char-ix.bc]]; rawRasterPointer: LONG POINTER _ BASE[rasterData.dirDesc] + offset; r: F.RasterPointer _ rawRasterPointer; rawRasterPointer _ rawRasterPointer + SIZE[F.RasterDimension]; IF data.BBdy = LAST[CARDINAL] THEN RETURN; IF offset = LAST[LONG CARDINAL] THEN RETURN; IF (rawRasterPointer-rasterData.base) < rasterData.rasterStart OR (rawRasterPointer-rasterData.base) >= rasterData.rasterEnd THEN ERROR Error[invalidPointerInFile, @(rasterData.dirDesc[char-ix.bc]) - rasterData.base]; Graphics.SetCP[self: context, x: data.BBox, y: data.BBoy, rel: TRUE]; Graphics.Rotate[context, 90]; CGPrivate.DrawBits[ self: context, base: rawRasterPointer, raster: r.height, bitsPerPixel: 0, x: 0, y: 0, w: data.BBdy, h: data.BBdx, xorigin:0, yorigin: 0 ]; }; Spline format operations. Routines for converting to bezier points. Widths format operations. FontGraphicsClass interface move: PROC [s, f: REAL], line: PROC [s, f: REAL], curve: PROC [s1, f1, s2, f2, s3, f3: REAL] ส‡– "Cedar" style˜Jšœ™Jšœ™Jšœ7™7Jšœ2™2unitšฯk ˜ Jšœœœ˜Jšœ œ%˜6Jšœ˜Jšœœ3˜LJšœ˜Jšœœ ˜Jšœ œ˜Jšœœ ˜Jšœ˜JšœœœH˜]—šœœœฯc"˜GJšœM˜TJšœ˜Jšœ˜Jšœ'˜+Kšœœœ˜Kšœœ˜Kšœœ˜Kšœ œ˜(Kšœ œœ˜%šœœœ˜Jšœœœ˜Jšœœ œœ˜,Jšœ˜Jšœา™า—šœœœ˜J˜Jšœ˜ Jšœ˜J™‰—šœœœ˜Jšœ œœ˜J˜ Jšœ˜ Jšœ˜—Kšœœœ ˜šœ œœ˜Jš œœœœœ˜CJ˜—Kšœœœœ˜0Kšœœœ˜(Kš ฯnœœœ+œœ˜KšŸœœ˜6Jšœ™Jšœ˜Jšœ œ˜šœœ˜ šœ ˜˜J˜J˜—Jšœ˜—J˜—šœœ˜šœ ˜˜Jšœ&˜&J˜J˜—šœ ˜ Jšœœœ˜Jš œ œœœœ˜0Jšœœ<˜SJšœ˜—Jšœ˜—J˜—Jšœ$˜$Jšœ œ˜+Jšœ˜Jšœ#˜#Jšœ ˜J˜—š Ÿ œ œ œœœœ˜Xš œœœœœ˜:Jšœœœ˜2Jšœ˜—Jšœœ˜ J˜—š Ÿ œ œœœœ˜;Jšœœœ˜ Jšœœ˜ Jšœ#œ˜'š œ œœœœœ˜4Jšœ#˜#—Jšœ$˜$J˜—š Ÿ œœ œœœœ ˜OJšœœœ˜ —šŸœ œ.œ˜PJš œœœœœ˜1Jšœœ˜š˜Jš œœœœœ(˜Jš œ œœœœ™*Jš œ œœœœœ™,Jšœ=œ<œœR™ูJšœ?œ™EJšœ™Jšœž™žJšœ™——šŸ™Kšœ œœ˜'šœœœ˜Jš œ œœœ œ ˜/Jšœ œ˜Jšœ œ˜Jšœœœ˜(J˜Jšœœ˜J˜—šŸœ œBœ˜gJšœœ˜/Jš œœœœ œ6˜SJšœœœ˜(Jšœœ˜ Jšœ&œœ˜4Jšœœœ˜?Jšœ œ2˜@Jšœ œœ˜7Jšœ#œœ˜;šœœ#˜HJšœ'˜,—Jšœ˜Jšœ)˜)Jšœ&œ#˜JJšœ œ˜;Jšœ œ˜9Jšœ˜Jšœ˜Jšœ3˜3Jšœ1˜1Jšœ˜—šœœ ˜&Jšœ˜J˜—š Ÿœ œœœœœ˜WJšœœ˜(Jš œœœœ œ#˜@Jšœœœ˜9Jšœœœœ+œœœ!˜Œšœ˜Jšœœ3˜:Jšœ*˜*Jšœ*˜*Jšœ&˜&Jšœ&˜&Jšœ(˜(Jšœ&˜&J˜—Jšœ˜—š Ÿœ œœ œœœ˜GJšœœ˜'J˜—š Ÿœ œœœœœ˜SJšœœœœ˜1J˜—šŸœœ œ˜"Jšœ˜Jšœœ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœœ˜ Jšœœœ˜Jšœ œ˜JšœI˜IJšœ*˜*Jšœœ˜/Jšœœ˜%Jšœ+œœ˜MJš œœœ!œœ˜;Jšœ(œœœ˜IJšœ œ?˜`š œœœœœ˜:Jšœ0œ/œœN˜พšœ˜š œœœœœ˜EJšœG˜GJšœœœ˜)Jšœ˜—š œœœœœ˜EJšœG˜GJšœœœ˜)Jšœ˜—š œœœœ œ˜Kšœ˜Jšœ ˜ Jšœ1˜1Jšœ1˜1Jšœ0˜0J˜—Jšœ˜Jšœ=˜=Jšœœ œ˜,Jšœ˜—šœ˜Jšœ˜Jšœœ œ˜,Jšœ˜—šœ˜Jšœ˜Jš˜Jšœ˜—Jšœœ.˜>—Jš˜—J˜——šฯb)™)Kšœœœœ˜Iprocš Ÿœ œœ œœ˜VLš Ÿœ œœ œœ˜VLš Ÿœ œ œœ œœ˜SLšœœœ˜(Lšœœœ˜(šŸœ œ œ˜=Jšœ˜ J˜J˜J˜&J˜'J˜——šŸ™Kšœ œœ˜%šœœœ˜Jš œ œœœœ ˜.Jš œ œœœœ˜-Jš œ œ œœœœœ˜2Jš œ œ œœœœ˜1J˜—šŸœ œBœ˜fJšœœ˜,Jš œœœœœ6˜RJšœœœ˜(Jšœœ˜ Jšœ'œœ˜5Jšœœ˜ Jšœœœ˜>Jšœ œ2˜?Jšœ˜Jšœ'˜'Jšœœ!œœ˜;Jšœœ!œœ˜;Jšœœœ˜4Jšœ!˜!Jšœ œ&˜HJšœ œ&˜Hšœ!œ#˜KJšœ1˜6—Jšœ2˜2Jšœ0˜0Jšœ˜—šœœ ˜%Jšœ˜J˜—š Ÿœ œœœœœ˜VJšœœ˜&Jš œœœœœ"˜>Jšœœœ˜8Jš œœœœœ!˜Lšœ˜Jšœœ)˜0Jš œœœ œœ ˜9Jš œœœœœ ˜PJš œœœœœ ˜PJšœœœœœœœœ"˜\Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ)˜)Jšœ)˜)J˜—Jšœ˜——š ™Kšœ-œ˜1šŸœ œœ-œ˜PJšœœœ œ˜0Jšœœœ˜šŸœ˜%Jšœœœ™Jšœœœ™Jšœœœ™*Jšœ˜šŸœœ œ œ˜0JšœC˜CJšœB˜BJšœ˜—šœ,˜,Jšœ˜Jšœ˜—šœ,˜,Jšœ˜Jšœ˜—šœ.˜.Jšœ˜Jšœ˜Jšœ˜Jšœ,˜,—Jšœ2˜2Jšœ_˜_Jšœ˜—JšœT˜TJšœ3œ˜9Jšœ˜—š Ÿ œ œœœœ˜MJšœ:˜:šœœœ˜5Jšœœ˜&Jšœœ˜&šœ˜ Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ ˜J˜—Jšœ˜—Jšœ>˜>Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ˜Jšœœ œ œ˜5Jšœ˜—š Ÿ œ œœœœ ˜DJšœ:˜:Jšœ>˜>Jšœ,˜,šœ˜ Jšœ˜Jšœ˜Jšœ˜—Jšœ˜—š Ÿ œ œœœœœ˜DJšœ>˜>Jšœ+˜1Jšœ˜—šŸ œ œœ˜(Jšœ!˜!Jšœ2˜2Jšœ˜—šœ œœ˜FJšœ˜Jšœ˜Jšœ˜Jšœ˜J˜—Kšœ2˜2—Kšœ˜——…—L@nW