DIRECTORY Imager, ImagerBackdoor, ImagerDevice USING [Device, DeviceClass, DeviceClassRep, DeviceParm, MakeDeviceParm], ImagerFont USING [Font, Modify, XChar], ImagerFontWorks, ImagerMaskCache USING [Parameters, ParametersRep], ImagerPath USING [ArcTo, ArcToProc, ConicTo, ConicToProc, CurveTo, CurveToProc, LineTo, LineToProc, MapTrajectoryList, MoveTo, MoveToProc, PathProc, TrajectoryList, Transform], ImagerPrivate USING [Class, DefaultMaskDashedStroke], ImagerRaster USING [Create, CreateClass, GetDevice], ImagerSample USING [SampleMap], ImagerTransformation USING [ApplyInvert, Destroy, Scale, ScanMode, Transformation], ImagerTypeface USING [Typeface, TypefaceFromFont], SF USING [Box, BoxGenerator, Vec], Vector2 USING [VEC]; ImagerFontWorksImpl: CEDAR MONITOR IMPORTS Imager, ImagerBackdoor, ImagerDevice, ImagerFont, ImagerPath, ImagerPrivate, ImagerRaster, ImagerTransformation, ImagerTypeface EXPORTS ImagerFontWorks ,ImagerTypeface -- Export MaskChar here also (for compatibility) ~ BEGIN Context: TYPE = Imager.Context; Device: TYPE = ImagerDevice.Device; Font: TYPE = ImagerFont.Font; Parameters: TYPE = ImagerMaskCache.Parameters; SampleMap: TYPE = ImagerSample.SampleMap; ScanMode: TYPE = ImagerTransformation.ScanMode; TrajectoryList: TYPE = ImagerPath.TrajectoryList; Transformation: TYPE = ImagerTransformation.Transformation; Typeface: TYPE = ImagerTypeface.Typeface; VEC: TYPE = Vector2.VEC; XChar: TYPE = ImagerFont.XChar; GetClientToDevice: PROC [context: Imager.Context] RETURNS [Transformation] ~ { m: Transformation ¬ NIL; m ¬ ImagerBackdoor.GetTransformation[context: context, from: client, to: device ! Imager.Error => { m ¬ ImagerTransformation.Scale[1/4096.0] }]; RETURN [m] }; MaskChar: PUBLIC -- ImagerFontWorks-- PROC [font: Font, char: XChar, context: Imager.Context] ~ { typeface: Typeface ~ ImagerTypeface.TypefaceFromFont[font]; Action: PROC ~ { IF (typeface.class.Mask = NIL) AND (typeface.class.MapChar # NIL) THEN { m: Transformation ¬ GetClientToDevice[context]; f: Font ~ ImagerFont.Modify[font, m]; Path: ImagerPath.PathProc ~ { [] ¬ typeface.class.MapChar[font: f, char: char, parameters: NIL, moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, arcTo: arcTo, conicTo: conicTo]; }; ImagerTransformation.ApplyInvert[m]; Imager.ConcatT[context, m]; {ImagerTransformation.Destroy[m]; m ¬ NIL}; Imager.MaskFill[context: context, path: Path]; } ELSE { Imager.ConcatT[context, font.charToClient]; typeface.class.Mask[typeface, char, context]; } }; Imager.DoSaveAll[context, Action]; }; MapChar: PUBLIC ImagerFontWorks.MapCharProc = { typeface: Typeface = ImagerTypeface.TypefaceFromFont[font]; success ¬ FALSE; IF typeface.class.MapChar # NIL THEN { success ¬ typeface.class.MapChar[font: font, char: char, parameters: parameters, moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, arcTo: arcTo, conicTo: conicTo]; }; IF NOT success AND typeface.class.Mask # NIL THEN { myContext: Context ¬ GetContext[parameters]; data: Data = NARROW[myContext.data]; Inner: PROC ~ { Imager.ConcatT[myContext, font.charToClient]; typeface.class.Mask[typeface, char, myContext]; }; Imager.DoSaveAll[myContext, Inner]; success ¬ NOT data.failed; IF success THEN ImagerPath.MapTrajectoryList[data.list, moveTo, lineTo, curveTo, conicTo, arcTo]; FreeContext[myContext]; }; }; Wrap: TYPE ~ { unknown, nz, eo }; Data: TYPE = REF DataRep ¬ NIL; DataRep: TYPE = RECORD [ wrap: Wrap ¬ unknown, failed: BOOL, list: TrajectoryList -- captured outline ]; CreateContext: PROC RETURNS [Context] = { deviceParm: ImagerDevice.DeviceParm ¬ ImagerDevice.MakeDeviceParm[ class: mapCharDeviceClass, sSize: INTEGER.LAST, fSize: INTEGER.LAST, scanMode: [slow: right, fast: up], surfaceUnitsPerInch: [1, 1]]; data: Data = NEW[DataRep ¬ [failed: FALSE, list: NIL]]; context: Context = ImagerRaster.Create[ class: mapCharContextClass, deviceParm: deviceParm, deviceClass: mapCharDeviceClass, data: NIL, pixelUnits: TRUE]; context.data ¬ data; -- context.data is used instead of device.data because these procs capture at the context class level RETURN[context]; }; defaultParameters: Parameters ¬ NEW[ImagerMaskCache.ParametersRep ¬ []]; GetContext: PROC [parameters: Parameters] RETURNS [context: Context] = { context ¬ TryGetContext[]; IF context = NIL THEN context ¬ CreateContext[]; IF parameters = NIL THEN parameters ¬ defaultParameters; ImagerRaster.GetDevice[context].parm.parameters ¬ parameters; }; c1: Context ¬ NIL; c2: Context ¬ NIL; TryGetContext: ENTRY PROC RETURNS [context: Context] = INLINE { ENABLE UNWIND => NULL; IF c1 # NIL THEN {context ¬ c1; c1 ¬ NIL} ELSE IF c2 # NIL THEN {context ¬ c2; c2 ¬ NIL} ELSE context ¬ NIL; }; -- Be sure to call FreeContext when you are done. FreeContext: ENTRY PROC [context: Context] = INLINE { ENABLE UNWIND => NULL; data: Data = NARROW[context.data]; data.wrap ¬ unknown; data.failed ¬ FALSE; data.list ¬ NIL; IF c1 = NIL THEN {c1 ¬ context} ELSE {c2 ¬ context; }; }; MyMaskFill: PROC [context: Context, path: ImagerPath.PathProc, oddWrap: BOOL] = { data: Data = NARROW[context.data]; m: Transformation ~ ImagerBackdoor.GetT[context]; wrap: Wrap ~ IF oddWrap THEN eo ELSE nz; myMoveTo: ImagerPath.MoveToProc = { data.list ¬ CONS[ImagerPath.MoveTo[p], data.list]; }; myLineTo: ImagerPath.LineToProc = { data.list.first ¬ ImagerPath.LineTo[data.list.first, p1]; }; myCurveTo: ImagerPath.CurveToProc = { data.list.first ¬ ImagerPath.CurveTo[data.list.first, p1, p2, p3]; }; myConicTo: ImagerPath.ConicToProc = { data.list.first ¬ ImagerPath.ConicTo[data.list.first, p1, p2, r]; }; myArcTo: ImagerPath.ArcToProc = { data.list.first ¬ ImagerPath.ArcTo[data.list.first, p1, p2]; }; ImagerPath.Transform[path, m, myMoveTo, myLineTo, myCurveTo, myConicTo, myArcTo]; IF data.wrap = unknown THEN data.wrap ¬ wrap; IF data.wrap # wrap THEN data.failed ¬ TRUE; ImagerTransformation.Destroy[m]; }; MyMaskRectangle: PROC [context: Context, r: Imager.Rectangle] = { Path: Imager.PathProc ~ { moveTo[[r.x, r.y]]; lineTo[[r.x+r.w, r.y]]; lineTo[[r.x+r.w, r.y+r.h]]; lineTo[[r.x, r.y+r.h]]; }; Imager.MaskFill[context: context, path: Path, oddWrap: TRUE]; }; MyMaskStroke: PROC [context: Context, path: ImagerPath.PathProc, closed: BOOL] = { data: Data = NARROW[context.data]; data.failed ¬ TRUE; }; MyMaskPixel: PROC [context: Context, pa: Imager.PixelArray] = { data: Data = NARROW[context.data]; data.failed ¬ TRUE; }; MyMaskVector: PROC [context: Context, p1, p2: VEC] = { data: Data = NARROW[context.data]; data.failed ¬ TRUE; }; MyMaskBitmap: PROC [context: Context, bitmap: SampleMap, referencePoint: SF.Vec, scanMode: ScanMode, position: VEC] = { data: Data = NARROW[context.data]; data.failed ¬ TRUE; }; MyDrawBitmap: PROC [context: Context, bitmap: SampleMap, referencePoint: SF.Vec, scanMode: ScanMode, position: VEC] = { data: Data = NARROW[context.data]; data.failed ¬ TRUE; }; MyDrawPixels: PROC [context: Context, pixelMap: Imager.PixelMap, colorOperator: Imager.ColorOperator, referencePoint: SF.Vec, scanMode: ScanMode, position: VEC] = { data: Data = NARROW[context.data]; data.failed ¬ TRUE; }; mapCharContextClass: ImagerPrivate.Class = InitMapCharContextClass[]; InitMapCharContextClass: PROC RETURNS [ImagerPrivate.Class] = { new: ImagerPrivate.Class = ImagerRaster.CreateClass[type: $MapChar]; new.MaskFill ¬ MyMaskFill; new.MaskRectangle ¬ MyMaskRectangle; new.MaskStroke ¬ MyMaskStroke; new.MaskPixel ¬ MyMaskPixel; new.MaskVector ¬ MyMaskVector; new.MaskDashedStroke ¬ ImagerPrivate.DefaultMaskDashedStroke; new.MaskBitmap ¬ MyMaskBitmap; new.DrawPixels ¬ MyDrawPixels; RETURN[new]; }; MySetColor: PROC [device: Device, color: Imager.Color, viewToDevice: Transformation] = {NULL}; MyMaskBoxes: PROC [device: Device, bounds: SF.Box, boxes: SF.BoxGenerator] = {NULL}; mapCharDeviceClass: ImagerDevice.DeviceClass = InitMapCharDeviceClass[]; InitMapCharDeviceClass: PROC RETURNS [ImagerDevice.DeviceClass] = { RETURN[NEW[ImagerDevice.DeviceClassRep ¬ [ SetColor: MySetColor, MaskBoxes: MyMaskBoxes]]]}; END. L ImagerFontWorksImpl.mesa Copyright Σ 1990, 1991 by Xerox Corporation. All rights reserved. Michael Plass, December 21, 1990 2:29 pm PST Types MaskChar N.B. Also exported to ImagerTypeface (for compatibility) MapChar Issue: should we return here? Capturing character outlines Capture class procs Capture device class procs Κi–(cedarcode) style•NewlineDelimiter ™codešœ™Kšœ Οeœ7™BK™,K™—šΟk ˜ Kšœ˜Kšœ˜Kšœ žœC˜UKšœ žœ˜'Kšœ˜Kšœžœ˜2Kšœ žœ ˜°Kšœžœ"˜5Kšœ žœ"˜4Kšœ žœ ˜Kšœžœ9˜SKšœžœ˜2Kšžœžœ˜"Kšœžœžœ˜—K˜KšΟnœžœž˜"Kšžœ€˜‡šžœ˜KšœΟcΠbc˜@—šœž˜K˜—head™Kšœ žœ˜Kšœžœ˜#Kšœžœ˜Kšœ žœ˜.Kšœ žœ˜)Kšœ žœ!˜/Kšœžœ˜1Kšœžœ'˜;Kšœ žœ˜)Kšžœžœ žœ˜Kšœžœ˜—šœ™šŸœžœžœ˜NKšœžœ˜Kšœ˜Kšžœ˜ Kšœ˜K˜—šŸœžœ œžœ7˜aKšΟb‘"™8Kšœ;˜;šŸœžœ˜šžœžœžœžœ˜Ašžœ˜Kšœ/˜/Kšœ%˜%šŸœ˜Kšœ=žœT˜”Kšœ˜—Kšœ$˜$Kšœ˜Kšœ&žœ˜+Kšœ.˜.Kšœ˜—šžœ˜Kšœ+˜+Kšœ-˜-Kšœ˜——K˜—Kšœ"˜"K˜——šœ™šŸœžœ ˜/K˜;Kšœ žœ˜šžœžœžœ˜&Kšœ£˜£K™Kšœ˜—š žœžœ žœžœžœ˜3K˜,Kšœ žœ˜$šŸœžœ˜Kšœ-˜-K˜/Kšœ˜—Kšœ#˜#Kšœ žœ ˜Kšžœ žœR˜aK˜Kšœ˜—K˜——šœ™K™šœžœ˜!K˜—Kšœžœžœ žœ˜šœ žœžœ˜K˜Kšœžœ˜ Kšœ ˜)K˜——˜šŸ œžœžœ˜)˜BKš œ"žœžœ žœžœ˜DK˜@—Kšœ žœžœžœ˜7˜'K˜3Kšœ'žœžœ˜>—Kšœ e˜{Kšžœ ˜K˜——˜Kšœ žœ%˜H—˜šŸ œžœžœ˜HK˜Kšžœ žœžœ˜0Kšžœžœžœ ˜8K˜=K˜——˜Kšœžœ˜Kšœžœ˜š Ÿ œžœžœžœžœ˜?Kšžœžœžœ˜Kšžœžœžœžœ˜)Kšžœžœžœžœžœžœ žœ˜BKšœ 1˜5——˜šŸ œžœžœžœ˜5Kšžœžœžœ˜Kšœ žœ˜"Kšœ˜Kšœžœ˜Kšœ žœ˜Kšžœžœžœ˜Kšžœ˜K˜——K˜K˜Lšœ™˜šŸ œžœ8žœ˜QKšœ žœ˜"Kšœ1˜1Kšœ žœ žœžœ˜(˜#Kšœ žœ"˜2K˜—˜#K˜<—˜%K˜BK˜—˜%K˜AK˜—˜!K˜