-- PressFontWriterImpl.mesa <<-- Written by Michael Plass on August 16, 1982 11:12 am>> <<-- Last edit by Michael Plass on August 17, 1982 5:37 pm>> DIRECTORY IO, Graphics, GraphicsOps, PressFontFormat, PressFontWriter, Real, RealConvert, Rope; PressFontWriterImpl: PROGRAM IMPORTS IO, Graphics, GraphicsOps, PressFontFormat, Real, RealConvert, Rope EXPORTS PressFontWriter = BEGIN OPEN PressFontWriter, F: PressFontFormat; NewFont: PUBLIC TYPE = REF NewFontRec; NewFontRec: PUBLIC TYPE = RECORD [ family: ROPE _ NIL, face: [0..256), bc: CHAR, ec: CHAR, size: REAL, rotation: REAL, representation: CharShapeRepresentation, xRes, yRes: REAL, context: Graphics.Context, file: IO.STREAM, endLoc: Location, -- word length of file startaddressLoc, dataLoc, directoryLoc: Location _ LAST[Location] ]; Location: TYPE = LONG CARDINAL; -- a word index into the file. WriteBlock: PROCEDURE [newFont: NewFont, base: LONG POINTER, size: NAT] RETURNS [location: Location] = { location _ newFont.endLoc; newFont.file.UnsafePutBlock[[base: base, startIndex: 0, stopIndexPlusOne: size*2]]; newFont.endLoc _ newFont.endLoc + size; }; FixUp: PROCEDURE [newFont: NewFont, location: Location, base: LONG POINTER, size: NAT] = { newFont.file.SetIndex[location*2]; newFont.file.UnsafePutBlock[[base: base, startIndex: 0, stopIndexPlusOne: size*2]]; newFont.file.SetIndex[newFont.endLoc*2]; }; WriteError: PUBLIC SIGNAL[writeErrorCode: WriteErrorCode] = CODE; Create: PUBLIC PROCEDURE [filename: ROPE, representation: CharShapeRepresentation, family: ROPE, face: [0..256) _ 0, size: REAL _ 0, -- in meters, or 0 for a scalable font rotation: REAL _ 0, -- in degrees bc: CHAR _ FIRST[CHAR], -- first character in the font ec: CHAR _ LAST[CHAR], -- last character in the font xRes, yRes: REAL _ 0 -- In bits per inch. Only used for a raster font. ] RETURNS [newFont: NewFont] = { newFont _ NEW[NewFontRec]; newFont.family _ family; newFont.face _ face; newFont.size _ size; newFont.rotation _ rotation; newFont.bc _ bc; newFont.ec _ ec; newFont.representation _ representation; newFont.xRes _ xRes; newFont.yRes _ yRes; IF representation=outline AND size#0.0 THEN ERROR WriteError[inconsistentParameters]; IF representation=raster AND (size<=0.0 OR xRes<=0.0 OR yRes<=0.0) THEN ERROR WriteError[inconsistentParameters]; IF bc > ec THEN ERROR WriteError[inconsistentParameters]; IF representation#outline THEN ERROR WriteError[notImplemented]; newFont.file _ IO.CreateFileStream[filename, overwrite]; newFont.endLoc _ 0; WriteNameIndex[newFont]; newFont.context _ GraphicsOps.NewContextFromBitmap[GraphicsOps.NewBitmap[1,1]]; IF representation=outline THEN { WriteSplineSkeleton[newFont]; newFont.context.procs_NEW[Graphics.GraphicsProcs _ newFont.context.procs^]; newFont.context.procs.FlushPath _ NIL; newFont.context.procs.Close _ NIL; newFont.context.procs.Rectangle _ NIL; newFont.context.procs.DrawTo _ NIL; newFont.context.procs.DrawPath _ NIL; newFont.context.procs.DrawBox _ NIL; newFont.context.procs.DrawImage _ NIL; newFont.context.procs.SetColor _ NIL; newFont.context.procs.GetColor _ NIL; newFont.context.procs.SetPaintMode _ NIL; newFont.context.procs.GetDefaultFont _ NIL; newFont.context.procs.SetDefaultFont _ NIL; newFont.context.procs.DrawChars _ NIL; newFont.context.procs.ClipArea _ NIL; newFont.context.procs.ClipBox _ NIL; newFont.context.procs.IsPointVisible _ NIL; newFont.context.procs.IsRectangular _ NIL; newFont.context.procs.GetBounds _ NIL; newFont.context.procs.Visible _ NIL; newFont.context.procs.DrawBits _ NIL; newFont.context.procs.GetYMode _ NIL; newFont.context.procs.SetYMode _ NIL; newFont.context.procs.DrawTexturedBox _ NIL; }; }; WriteNameIndex: PROCEDURE [newFont: NewFont] = { nameIndex: NameIndex; nameLength: [1..20) _ newFont.family.Length[]; nameIndex.hdr.type _ name; nameIndex.hdr.length _ SIZE[NameIndex]; nameIndex.code _ 1; nameIndex.fontname[0] _ LOOPHOLE[nameLength]; FOR i: NAT IN [0..nameLength) DO nameIndex.fontname[i+1] _ newFont.family.Fetch[i]; ENDLOOP; [] _ WriteBlock[newFont, @nameIndex, SIZE[NameIndex]]; }; WriteSplineSkeleton: PROCEDURE [newFont: NewFont] = { splinesIndex: splines F.RawIndex; splinesIndexLoc: Location; splinesIndex.hdr _ [type: splines, length: SIZE[splines F.RawIndex]]; splinesIndex.family _ 1; splinesIndex.face _ newFont.face; splinesIndex.bc _ newFont.bc; splinesIndex.ec _ newFont.ec; splinesIndex.size _ 0; splinesIndex.rotation _ Real.RoundC[newFont.rotation*60.0]; splinesIndexLoc _ WriteBlock[newFont, @splinesIndex, SIZE[splines F.RawIndex]]; newFont.startaddressLoc _ newFont.endLoc - (SIZE[F.bcplLONGPOINTER] + SIZE[F.bcplLONGCARDINAL]); WriteEndIndex[newFont]; newFont.dataLoc _ newFont.endLoc; WriteDummySplineCharData[newFont]; newFont.directoryLoc _ newFont.endLoc; WriteDummyDirectory[newFont]; }; WriteEndIndex: PROCEDURE [newFont: NewFont] = { endIndex: end F.RawIndex; endIndex.hdr _ [type: end, length: SIZE[end F.RawIndex]]; [] _ WriteBlock[newFont, @endIndex, SIZE[end F.RawIndex]]; }; WriteDummySplineCharData: PROCEDURE [newFont: NewFont] = { bcplSplineData: F.BcplSplineData _ [F.missingCharValue, F.missingCharValue, F.missingCharValue, F.missingCharValue, F.missingCharValue, F.missingCharValue]; FOR i: CHAR IN [newFont.bc..newFont.ec] DO [] _ WriteBlock[newFont, @bcplSplineData, SIZE[F.BcplSplineData]]; ENDLOOP }; WriteDummyDirectory: PROCEDURE [newFont: NewFont] = { dummyLP: F.bcplLONGPOINTER _ LocationToBcplPointer[LAST[Location]]; FOR i: CHAR IN [newFont.bc..newFont.ec] DO [] _ WriteBlock[newFont, @dummyLP, SIZE[F.bcplLONGPOINTER]]; ENDLOOP }; PaintChar: PUBLIC PROCEDURE [newFont: NewFont, char: CHAR, charInfo: CharInfo, paintProc: PaintProc] = {OPEN charInfo; Undefined: PROCEDURE [r: REAL] RETURNS [BOOLEAN] = { RETURN[ LOOPHOLE[r, LONG CARDINAL] = LOOPHOLE[Real.NonTrappingNaN, LONG CARDINAL] ] }; mark: Graphics.Mark _ Graphics.Save[newFont.context]; Graphics.SetCP[newFont.context, 0, 0]; IF Undefined[minX] OR Undefined[minY] OR Undefined[maxX] OR Undefined[maxY] THEN ERROR WriteError[notImplemented]; SELECT newFont.representation FROM outline => PaintSplineChar[newFont, char, charInfo, paintProc]; ENDCASE => ERROR WriteError[notImplemented]; Graphics.Restore[newFont.context]; }; PaintSplineChar: PROCEDURE [newFont: NewFont, char: CHAR, charInfo: CharInfo, paintProc: PaintProc] = { MoveTo: PROC[self: Graphics.Context, x,y: REAL, rel: BOOLEAN] = { wx, wy: REAL; bcplSplineCommand: MoveTo F.BcplSplineCommand; IF rel THEN {[wx, wy] _ Graphics.GetCP[self, FALSE]; x _ x+wx; y_y+wy}; [wx, wy] _ Graphics.UserToWorld[self, x, y]; bcplSplineCommand.type _ F.moveToCode; bcplSplineCommand.x _ MesaToBcplReal[wx]; bcplSplineCommand.y _ MesaToBcplReal[wy]; [] _ WriteBlock[newFont, @bcplSplineCommand, SIZE[DrawTo F.BcplSplineCommand]]; Graphics.SetCP[self, x, y]; }; LineTo: PROC[self: Graphics.Context, x,y: REAL, rel: BOOLEAN] = { wx, wy: REAL; bcplSplineCommand: DrawTo F.BcplSplineCommand; IF rel THEN {[wx, wy] _ Graphics.GetCP[self, FALSE]; x _ x+wx; y_y+wy}; [wx, wy] _ Graphics.UserToWorld[self, x, y]; bcplSplineCommand.type _ F.drawToCode; bcplSplineCommand.x _ MesaToBcplReal[wx]; bcplSplineCommand.y _ MesaToBcplReal[wy]; [] _ WriteBlock[newFont, @bcplSplineCommand, SIZE[DrawTo F.BcplSplineCommand]]; Graphics.SetCP[self, x, y]; }; CurveTo: PROC[self: Graphics.Context, x1,y1,x2,y2,x3,y3: REAL, rel: BOOLEAN] = { wx0, wy0, wx1, wy1, wx2, wy2, wx3, wy3: REAL; bcplSplineCommand: DrawCurve F.BcplSplineCommand; c: Coeffs; [wx0, wy0] _ Graphics.GetCP[self, FALSE]; IF rel THEN { x1 _ x1+wx0; y1_y1+wy0; x1 _ x2+wx0; y1_y2+wy0; x1 _ x3+wx0; y1_y3+wy0; }; [wx0, wy0] _ Graphics.UserToWorld[self, wx0, wy0]; [wx1, wy1] _ Graphics.UserToWorld[self, x1, y1]; [wx2, wy2] _ Graphics.UserToWorld[self, x2, y2]; [wx3, wy3] _ Graphics.UserToWorld[self, x3, y3]; c _ BezierToCoeffs[[[wx0, wy0], [wx1, wy1], [wx2, wy2], [wx3, wy3]]]; bcplSplineCommand.type _ F.drawCurveCode; bcplSplineCommand.x0 _ MesaToBcplReal[c.c1.x]; bcplSplineCommand.y0 _ MesaToBcplReal[c.c1.y]; bcplSplineCommand.x1 _ MesaToBcplReal[c.c2.x]; bcplSplineCommand.y1 _ MesaToBcplReal[c.c2.y]; bcplSplineCommand.x2 _ MesaToBcplReal[c.c3.x]; bcplSplineCommand.y2 _ MesaToBcplReal[c.c3.y]; [] _ WriteBlock[newFont, @bcplSplineCommand, SIZE[DrawCurve F.BcplSplineCommand]]; Graphics.SetCP[self, x3, y3]; }; DrawArea: PROC[self: Graphics.Context, parityFill: BOOLEAN] = { IF areaDrawn THEN ERROR WriteError[notImplemented]; areaDrawn _ TRUE; }; areaDrawn: BOOLEAN _ FALSE; endSplineCommand: EndDefinition F.BcplSplineCommand; splineDataLP: F.bcplLONGPOINTER _ LocationToBcplPointer[newFont.endLoc - newFont.directoryLoc]; bcplSplineData: F.BcplSplineData; bcplSplineData.xwidth _ MesaToBcplReal[charInfo.widthX]; bcplSplineData.ywidth _ MesaToBcplReal[charInfo.widthY]; bcplSplineData.bbox _ MesaToBcplReal[charInfo.minX]; bcplSplineData.bboy _ MesaToBcplReal[charInfo.minY]; bcplSplineData.rightx _ MesaToBcplReal[charInfo.maxX]; bcplSplineData.topy _ MesaToBcplReal[charInfo.maxY]; FixUp[newFont, newFont.dataLoc + (char-newFont.bc)*SIZE[F.BcplSplineData], @bcplSplineData, SIZE[F.BcplSplineData]]; newFont.context.procs.MoveTo _ MoveTo; newFont.context.procs.LineTo _ LineTo; newFont.context.procs.CurveTo _ CurveTo; newFont.context.procs.DrawArea _ DrawArea; paintProc[newFont.context]; newFont.context.procs.MoveTo _ NIL; newFont.context.procs.LineTo _ NIL; newFont.context.procs.CurveTo _ NIL; newFont.context.procs.DrawArea _ NIL; endSplineCommand.type _ F.endSplineCode; [] _ WriteBlock[newFont, @endSplineCommand, SIZE[EndDefinition F.BcplSplineCommand]]; FixUp[newFont, newFont.directoryLoc + (char-newFont.bc)*SIZE[F.bcplLONGPOINTER], @splineDataLP, SIZE[F.bcplLONGPOINTER]]; }; NameIndex: TYPE = MACHINE DEPENDENT RECORD [ hdr: F.IndexHeader, code: CARDINAL, fontname: PACKED ARRAY [0..20) OF CHAR ]; FontDataDescriptor: TYPE = MACHINE DEPENDENT RECORD [ startaddress: F.bcplLONGPOINTER, -- Starting address of data part length: F.bcplLONGCARDINAL -- Length of data part ]; Close: PUBLIC PROCEDURE [newFont: NewFont] = { IF newFont.startaddressLoc # LAST[Location] THEN { fontDataDescriptor: FontDataDescriptor; fontDataDescriptor.startaddress _ LocationToBcplPointer[newFont.dataLoc]; fontDataDescriptor.length _ F.MesaToBcplLongCardinal[newFont.endLoc - newFont.dataLoc]; FixUp[newFont, newFont.startaddressLoc, @fontDataDescriptor, SIZE[FontDataDescriptor]]; }; newFont.file.Close[]; newFont.file _ NIL }; MesaToBcplReal: PROCEDURE [r: REAL] RETURNS [b: F.BcplREAL] = { b _ LOOPHOLE[RealConvert.IeeeToBcpl[r]] }; LocationToBcplPointer: PROCEDURE [location: Location] RETURNS [F.bcplLONGPOINTER] = INLINE { RETURN[LOOPHOLE[F.MesaToBcplLongCardinal[location]]] }; <<-- Routines for converting from bezier points.>> 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]]}; VecMul: 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]; BezierToCoeffs: PROCEDURE [b: Bezier] RETURNS [c: Coeffs] = { OPEN b,c; temp: Vec; c0 _ b0; c1 _ VecMul[VecSub[b1,b0],3]; c2 _ VecSub[(temp_VecMul[VecSub[b2,b1],3]),c1]; c3 _ VecSub[b3,VecAdd[b0,temp]]; }; END.