<> <> <> <> DIRECTORY Font, Imager USING [Class, ClassRep, Context, ContextRep, Error, IntKey, RealKey], ImagerBasic USING [IntPair], ImagerColor USING [black, Color, ColorRep, MakeGray], ImagerDisplayPrivate, ImagerManhattan USING [BoundingBox, Copy, CreateFromBox, Destroy, Difference, Intersection, Polygon], ImagerMask USING [GenerateRuns, Mask], ImagerPath USING [Clipper, PathProc], ImagerPixelArray USING [PixelArray], ImagerPixelMap USING [DeviceRectangle, PixelMap], ImagerScanConverter USING [ConvertToManhattanPolygon, CreatePath, DevicePath], ImagerStroke USING [DevicePathFromStroke, StrokeStyle], ImagerTransformation USING [Concat, DRound, InverseTransform, PreMultiply, PreRotate, PreScale2, PreTranslate, Scale, SetTrans, Transform, Transformation, TransformationRep, TransformVec], ImagerUtils USING [ClipRectangleIViaClipRectangle, MaskUnderlineIViaMaskUnderline, MaskVectorIViaMaskStroke, MaskVectorViaMaskStroke, SpaceIViaSpace], Real USING [RoundI], RefText, Rope, Vector2 USING [Add, Div, InlineAdd, Length, Mul, Sub, VEC]; ImagerDisplayImpl: CEDAR PROGRAM IMPORTS Font, Imager, ImagerColor, ImagerManhattan, ImagerMask, ImagerDisplayPrivate, ImagerScanConverter, ImagerStroke, ImagerTransformation, ImagerUtils, Real, RefText, Rope, Vector2 <> ~ BEGIN Context: TYPE ~ Imager.Context; Display: TYPE ~ ImagerDisplayPrivate.Display; BYTE: TYPE ~ [0..377B]; CARD: TYPE ~ LONG CARDINAL; ROPE: TYPE ~ Rope.ROPE; VEC: TYPE ~ Vector2.VEC; IVEC: TYPE ~ ImagerBasic.IntPair; FONT: TYPE ~ Font.FONT; Transformation: TYPE ~ ImagerTransformation.Transformation; TransformationRep: TYPE ~ ImagerTransformation.TransformationRep; Color: TYPE ~ ImagerColor.Color; PixelArray: TYPE ~ ImagerPixelArray.PixelArray; PathProc: TYPE ~ ImagerPath.PathProc; Clipper: TYPE ~ ImagerPath.Clipper; PixelMap: TYPE ~ ImagerPixelMap.PixelMap; ManhattanPolygon: TYPE ~ ImagerManhattan.Polygon; DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle; PersistentVariables: TYPE ~ RECORD[ cp: VEC _ [0, 0], -- current position correctMeasure: VEC _ [0, 0], -- target line measure for Correct correctMaskCount: INT _ 0, -- tally number of CorrectMask calls in pass 1 correctSum: VEC _ [0, 0], -- tally adjustable space from CorrectSpace calls in pass 1 correctMask: VEC _ [0, 0], -- amount of space added by each CorrectMask call in pass 2 correctSpace: VEC _ [0, 0] -- fraction of space added by each CorrectSpace call in pass 2 ]; NonPersistentVariables: TYPE ~ RECORD[ priorityImportant: INT _ 0, -- if nonzero, priority of masks is important mediumSize: VEC _ [0, 0], -- size of medium, in meters fieldMin: VEC _ [0, 0], -- minimum x and y of field, in meters fieldMax: VEC _ [0, 0], -- maximum x and y of field, in meters noImage: INT _ 0, -- if nonzero, don't image masks strokeWidth: REAL _ 0, -- stroke width strokeEnd: INT _ 0, -- stroke end treatment underlineStart: REAL _ 0, -- starting x position for underline amplifySpace: REAL _ 1.0, -- multiplies width of amplified characters correctPass: INT _ 0, -- which pass, during Correct correctShrink: REAL _ 0.5, -- allowable space shrink correctTolerance: VEC _ [0, 0] -- tolerable deviation from correctMeasure ]; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD[ p: PersistentVariables _ [], -- persistent variables np: NonPersistentVariables _ [], -- non-persistent variables, except T, font, color, clipper font: FONT _ NIL, -- current font ("showVec") color: Color _ NIL, -- current color clipper: Clipper _ NIL, -- current clipping outline clientToView: Transformation _ NIL, -- current client-to-view transformation ("T") clientToViewID: CARD _ 0, -- unique id for contents of clientToView transformation lastID: CARD _ 0, -- last value used for clientToViewID devicePath: ImagerScanConverter.DevicePath _ NIL, -- scratch storage for scan converter viewToDisplayValid: BOOL _ FALSE, viewClipperValid: BOOL _ FALSE, clientToDisplayValid: BOOL _ FALSE, clientClipperValid: BOOL _ FALSE, charToDisplayValid: BOOL _ FALSE, displayColorValid: BOOL _ FALSE, viewToDisplayEasy: BOOL _ FALSE, -- valid iff viewToDisplayValid clientToDisplayEasy: BOOL _ FALSE, -- valid iff clientToDisplayValid viewToDisplay: Transformation _ NIL, -- always valid clientToDisplay: Transformation _ NIL, -- valid iff clientToDisplayValid charToDisplay: Transformation _ NIL, -- valid iff charToDisplayValid viewOrigin: IVEC _ [0, 0], -- valid iff viewToDisplayValid AND viewToDisplayEasy clientOrigin: IVEC _ [0, 0], -- valid iff clientToDisplayValid AND clientToDisplayEasy viewClipMask: ManhattanPolygon _ NIL, -- display coords; always valid clientClipMask: ManhattanPolygon _ NIL, -- display coords; valid iff clientClipperValid viewClipBox: DeviceRectangle _ [0, 0, 0, 0], -- display coords; valid iff viewClipperValid clientClipBox: DeviceRectangle _ [0, 0, 0, 0], -- display coords; valid iff clientClipperValid display: Display _ NIL -- the particular display; its color setting is valid iff displayColorValid ]; Create: PROC[display: Display] RETURNS[Context] ~ { data: Data ~ NEW[DataRep _ []]; data.color _ ImagerColor.black; data.clientToView _ ImagerTransformation.Scale[1]; data.viewToDisplay _ ImagerTransformation.Scale[1]; data.clientToDisplay _ ImagerTransformation.Scale[1]; data.charToDisplay _ ImagerTransformation.Scale[1]; data.display _ display; ViewReset[data]; RETURN[NEW[Imager.ContextRep _ [class: displayClass, data: data, props: NIL]]]; }; GetOriginI: PROC[m: Transformation] RETURNS[origin: IVEC] ~ { origin.x _ Real.RoundI[MIN[MAX[m.c, INTEGER.FIRST], INTEGER.LAST]]; origin.y _ Real.RoundI[MIN[MAX[m.f, INTEGER.FIRST], INTEGER.LAST]]; }; ComputeViewToDisplay: PROC[data: Data] ~ { m: Transformation ~ data.viewToDisplay; origin: IVEC ~ GetOriginI[m]; data.viewOrigin _ origin; data.viewToDisplayEasy _ m.a=0 AND m.b=-1 AND m.c=origin.y -- s = (0) x + (-1) y + (origin.y) = origin.y-y AND m.d=1 AND m.e=0 AND m.f=origin.x; -- f = (1) x + (0) y + (origin.x) = origin.x+x data.viewToDisplayValid _ TRUE; }; ComputeClientToDisplay: PROC[data: Data] ~ { m: Transformation ~ data.clientToDisplay; origin: IVEC; ValidateViewToDisplay[data]; m^ _ data.viewToDisplay^; m.PreMultiply[data.clientToView]; origin _ GetOriginI[m]; data.clientOrigin _ origin; data.clientToDisplayEasy _ m.a=0 AND m.b=-1 AND m.c=origin.y -- s = (0) x + (-1) y + (origin.y) = origin.y-y AND m.d=1 AND m.e=0 AND m.f=origin.x; -- f = (1) x + (0) y + (origin.x) = origin.x+x data.clientToDisplayValid _ TRUE; }; ComputeCharToDisplay: PROC[data: Data] ~ { m: Transformation ~ data.charToDisplay; ValidateViewToDisplay[data]; m^ _ data.viewToDisplay^; m.PreMultiply[data.clientToView]; m.SetTrans[[0, 0]]; m.PreMultiply[data.font.charToClient]; data.charToDisplayValid _ TRUE; }; ComputeViewClipper: PROC[data: Data] ~ { data.viewClipBox _ ImagerManhattan.BoundingBox[data.viewClipMask]; data.viewClipperValid _ TRUE; }; ComputeClientClipper: PROC[data: Data] ~ { <> ImagerManhattan.Destroy[data.clientClipMask]; ValidateViewClipper[data]; data.clientClipMask _ ImagerManhattan.Copy[data.viewClipMask]; FOR list: Clipper _ data.clipper, list.rest UNTIL list=NIL DO old, this, new: ManhattanPolygon; old _ data.clientClipMask; data.devicePath _ ImagerScanConverter.CreatePath[ pathProc: list.first.outline.pathProc, pathData: list.first.outline.pathData, transformation: data.viewToDisplay, clipBox: data.viewClipBox, scratch: data.devicePath]; this _ ImagerScanConverter.ConvertToManhattanPolygon[data.devicePath, data.clientClipBox]; IF list.first.exclude THEN new _ old.Difference[this] ELSE new _ old.Intersection[this]; data.clientClipMask _ new; ImagerManhattan.Destroy[old]; ImagerManhattan.Destroy[this]; ENDLOOP; data.clientClipBox _ ImagerManhattan.BoundingBox[data.clientClipMask]; data.clientClipperValid _ TRUE; }; SetDisplayColor: PROC[data: Data] ~ { data.display.SetColor[data.color, data.viewOrigin]; data.displayColorValid _ TRUE; }; ValidateViewToDisplay: PROC[data: Data] ~ INLINE { IF data.viewToDisplayValid THEN NULL ELSE ComputeViewToDisplay[data]; }; ValidateClientToDisplay: PROC[data: Data] ~ INLINE { IF data.clientToDisplayValid THEN NULL ELSE ComputeClientToDisplay[data]; }; ValidateCharToDisplay: PROC[data: Data] ~ INLINE { IF data.charToDisplayValid THEN NULL ELSE ComputeCharToDisplay[data]; }; ValidateViewClipper: PROC[data: Data] ~ INLINE { IF data.viewClipperValid THEN NULL ELSE ComputeViewClipper[data]; }; ValidateClientClipper: PROC[data: Data] ~ INLINE { IF data.clientClipperValid THEN NULL ELSE ComputeClientClipper[data]; }; ValidateDisplayColor: PROC[data: Data] ~ INLINE { IF data.displayColorValid THEN NULL ELSE SetDisplayColor[data]; }; DoSave: PROC[context: Context, body: PROC] ~ { data: Data ~ NARROW[context.data]; np: NonPersistentVariables ~ data.np; clientToViewID: CARD ~ data.clientToViewID; clientToViewRep: TransformationRep ~ data.clientToView^; font: FONT ~ data.font; color: Color ~ data.color; clipper: Clipper ~ data.clipper; Restore: PROC ~ { data.np _ np; IF clientToViewID#data.clientToViewID THEN { data.clientToView^ _ clientToViewRep; data.clientToViewID _ clientToViewID; data.clientToDisplayValid _ FALSE; data.charToDisplayValid _ FALSE; }; IF font#data.font THEN { data.font _ font; data.charToDisplayValid _ FALSE; }; IF color#data.color THEN { data.color _ color; data.displayColorValid _ FALSE; }; IF clipper#data.clipper THEN { data.clipper _ clipper; data.clientClipperValid _ FALSE; }; }; body[! UNWIND => Restore[]]; Restore[]; }; DoSaveAll: PROC[context: Context, body: PROC] ~ { data: Data ~ NARROW[context.data]; p: PersistentVariables ~ data.p; DoSave[context, body ! UNWIND => data.p _ p]; data.p _ p; }; ChangedClientToView: PROC[data: Data] ~ INLINE { data.clientToViewID _ data.lastID _ data.lastID+1; }; SetTransformation: PROC[context: Context, transformation: Transformation] ~ { data: Data ~ NARROW[context.data]; data.clientToView^ _ transformation^; ChangedClientToView[data]; data.clientToDisplayValid _ FALSE; data.charToDisplayValid _ FALSE; }; SetFont: PROC[context: Context, font: FONT] ~ { data: Data ~ NARROW[context.data]; IF font#data.font THEN { data.font _ font; data.charToDisplayValid _ FALSE; }; }; SetColor: PROC[context: Context, color: Color] ~ { data: Data ~ NARROW[context.data]; IF color#data.color THEN { data.color _ color; data.displayColorValid _ FALSE; }; }; SetClipper: PROC[context: Context, clipper: Clipper] ~ { data: Data ~ NARROW[context.data]; IF clipper#data.clipper THEN { data.clipper _ clipper; data.clientClipperValid _ FALSE; }; }; SetReal: PROC[context: Context, key: Imager.RealKey, value: REAL] ~ { data: Data ~ NARROW[context.data]; SELECT key FROM $DCScpx => data.p.cp.x _ value; $DCScpy => data.p.cp.y _ value; $correctMX => data.p.correctMeasure.x _ value; $correctMY => data.p.correctMeasure.y _ value; $mediumXSize => data.np.mediumSize.x _ value; $mediumYSize => data.np.mediumSize.y _ value; $fieldXMin => data.np.fieldMin.x _ value; $fieldYMin => data.np.fieldMin.y _ value; $fieldXMax => data.np.fieldMax.x _ value; $fieldYMax => data.np.fieldMax.y _ value; $strokeWidth => data.np.strokeWidth _ value; $underlineStart => data.np.underlineStart _ value; $amplifySpace => data.np.amplifySpace _ value; $correctShrink => data.np.correctShrink _ value; $correctTX => data.np.correctTolerance.x _ value; $correctTY => data.np.correctTolerance.y _ value; ENDCASE => ERROR Imager.Error[$Bug]; }; SetInt: PROC[context: Context, key: Imager.IntKey, value: INT] ~ { data: Data ~ NARROW[context.data]; SELECT key FROM $priorityImportant => data.np.priorityImportant _ value; $noImage => data.np.noImage _ value; $strokeEnd => data.np.strokeEnd _ value; $correctPass => data.np.correctPass _ value; ENDCASE => ERROR Imager.Error[$Bug]; }; GetTransformation: PROC[context: Context] RETURNS[Transformation] ~ { data: Data ~ NARROW[context.data]; RETURN[NEW[TransformationRep _ data.clientToView^]]; }; GetFont: PROC[context: Context] RETURNS[FONT] ~ { data: Data ~ NARROW[context.data]; RETURN[data.font]; }; GetColor: PROC[context: Context] RETURNS[Color] ~ { data: Data ~ NARROW[context.data]; RETURN[data.color]; }; GetClipper: PROC[context: Context] RETURNS[Clipper] ~ { data: Data ~ NARROW[context.data]; ERROR Imager.Error[$Unimplemented]; }; GetReal: PROC[context: Context, key: Imager.RealKey] RETURNS[REAL] ~ { data: Data ~ NARROW[context.data]; SELECT key FROM $DCScpx => RETURN[data.p.cp.x]; $DCScpy => RETURN[data.p.cp.y]; $correctMX => RETURN[data.p.correctMeasure.x]; $correctMY => RETURN[data.p.correctMeasure.y]; $mediumXSize => RETURN[data.np.mediumSize.x]; $mediumYSize => RETURN[data.np.mediumSize.y]; $fieldXMin => RETURN[data.np.fieldMin.x]; $fieldYMin => RETURN[data.np.fieldMin.y]; $fieldXMax => RETURN[data.np.fieldMax.x]; $fieldYMax => RETURN[data.np.fieldMax.y]; $strokeWidth => RETURN[data.np.strokeWidth]; $underlineStart => RETURN[data.np.underlineStart]; $amplifySpace => RETURN[data.np.amplifySpace]; $correctShrink => RETURN[data.np.correctShrink]; $correctTX => RETURN[data.np.correctTolerance.x]; $correctTY => RETURN[data.np.correctTolerance.y]; ENDCASE => ERROR Imager.Error[$Bug]; }; GetInt: PROC[context: Context, key: Imager.IntKey] RETURNS[INT] ~ { data: Data ~ NARROW[context.data]; SELECT key FROM $priorityImportant => RETURN[data.np.priorityImportant]; $noImage => RETURN[data.np.noImage]; $strokeEnd => RETURN[data.np.strokeEnd]; $correctPass => RETURN[data.np.correctPass]; ENDCASE => ERROR Imager.Error[$Bug]; }; GetCP: PROC[context: Context] RETURNS[VEC] ~ { data: Data ~ NARROW[context.data]; RETURN[data.clientToView.InverseTransform[data.p.cp]]; }; GetCPRounded: PROC[context: Context] RETURNS[VEC] ~ { data: Data ~ NARROW[context.data]; RETURN[data.clientToView.InverseTransform[ImagerTransformation.DRound[data.p.cp]]]; }; ConcatT: PROC[context: Context, m: Transformation] ~ { data: Data ~ NARROW[context.data]; data.clientToView.PreMultiply[m]; ChangedClientToView[data]; data.clientToDisplayValid _ FALSE; data.charToDisplayValid _ FALSE; }; Scale2T: PROC[context: Context, sx, sy: REAL] ~ { data: Data ~ NARROW[context.data]; data.clientToView.PreScale2[sx, sy]; ChangedClientToView[data]; data.clientToDisplayValid _ FALSE; data.charToDisplayValid _ FALSE; }; RotateT: PROC[context: Context, a: REAL] ~ { data: Data ~ NARROW[context.data]; data.clientToView.PreRotate[a]; ChangedClientToView[data]; data.clientToDisplayValid _ FALSE; data.charToDisplayValid _ FALSE; }; TranslateT: PROC[context: Context, x, y: REAL] ~ { data: Data ~ NARROW[context.data]; data.clientToView.PreTranslate[x, y]; ChangedClientToView[data]; data.clientToDisplayValid _ FALSE; }; Move: PROC[context: Context] ~ { data: Data ~ NARROW[context.data]; data.clientToView.SetTrans[data.p.cp]; ChangedClientToView[data]; data.clientToDisplayValid _ FALSE; }; Trans: PROC[context: Context] ~ { data: Data ~ NARROW[context.data]; data.clientToView.SetTrans[ImagerTransformation.DRound[data.p.cp]]; ChangedClientToView[data]; data.clientToDisplayValid _ FALSE; }; SetGray: PROC[context: Context, f: REAL] ~ { data: Data ~ NARROW[context.data]; data.color _ ImagerColor.MakeGray[f]; data.displayColorValid _ FALSE; }; SetSampledColor: PROC[context: Context, pa: PixelArray, m: Transformation, op: ATOM] ~ { data: Data ~ NARROW[context.data]; colorToView: Transformation ~ m.Concat[data.clientToView]; color: Color ~ NEW[ImagerColor.ColorRep[sampled] _ [sampled[ pa: pa, m: colorToView, transparent: FALSE, colorOperator: op]]]; data.color _ color; data.displayColorValid _ FALSE; }; StartUnderline: PROC[context: Context] ~ { data: Data ~ NARROW[context.data]; data.np.underlineStart _ data.clientToView.InverseTransform[data.p.cp].x; }; MaskUnderline: PROC[context: Context, dy, h: REAL] ~ { data: Data ~ NARROW[context.data]; end: VEC ~ data.clientToView.InverseTransform[data.p.cp]; -- current position (client space) start: VEC ~ [data.np.underlineStart, end.y-dy-h]; -- corner of underline (client space) underline: PROC ~ { data.clientToView.SetTrans[ImagerTransformation.DRound[start]]; ChangedClientToView[data]; data.clientToDisplayValid _ FALSE; MaskRectangle[context, 0, 0, end.x-start.x, h]; }; DoSave[context, underline]; }; SetXY: PROC[context: Context, p: VEC] ~ { data: Data ~ NARROW[context.data]; data.p.cp _ data.clientToView.Transform[p]; }; SetXYI: PROC[context: Context, x, y: INTEGER] ~ { data: Data ~ NARROW[context.data]; data.p.cp _ data.clientToView.Transform[[x, y]]; }; SetXYRel: PROC[context: Context, v: VEC] ~ { data: Data ~ NARROW[context.data]; data.p.cp _ data.p.cp.InlineAdd[data.clientToView.TransformVec[v]]; }; SetXYRelI: PROC[context: Context, x, y: INTEGER] ~ { data: Data ~ NARROW[context.data]; data.p.cp _ data.p.cp.InlineAdd[data.clientToView.TransformVec[[x, y]]]; }; ClipOutline: PROC[context: Context, pathProc: PathProc, pathData: REF, exclude: BOOL] ~ { ERROR Imager.Error[$Unimplemented]; }; ClipRectangle: PROC[context: Context, x, y, w, h: REAL, exclude: BOOL] ~ { ERROR Imager.Error[$Unimplemented]; }; CorrectMask: PROC[context: Context] ~ { data: Data ~ NARROW[context.data]; IF data.np.correctPass=0 THEN NULL ELSE { SELECT data.np.correctPass FROM 1 => data.p.correctMaskCount _ data.p.correctMaskCount+1; 2 => IF data.p.correctMaskCount#0 THEN { data.p.cp _ data.p.cp.InlineAdd[data.p.correctMask]; data.p.correctMaskCount _ data.p.correctMaskCount-1; }; ENDCASE; }; }; VMul: PROC[a, b: VEC] RETURNS[VEC] ~ INLINE { RETURN[[a.x*b.x, a.y*b.y]] }; <> CorrectSpace: PROC[context: Context, v: VEC] ~ { data: Data ~ NARROW[context.data]; IF data.np.correctPass=0 THEN NULL ELSE { s: VEC ~ data.clientToView.TransformVec[v]; SELECT data.np.correctPass FROM 1 => data.p.correctSum _ data.p.correctSum.InlineAdd[s]; 2 => data.p.cp _ data.p.cp.InlineAdd[VMul[s, data.p.correctSpace]]; ENDCASE; }; }; Space: PROC[context: Context, x: REAL] ~ { data: Data ~ NARROW[context.data]; s: VEC ~ data.clientToView.TransformVec[[x, 0]]; data.p.cp _ data.p.cp.InlineAdd[s]; SELECT data.np.correctPass FROM 0 => NULL; 1 => data.p.correctSum _ data.p.correctSum.InlineAdd[s]; 2 => data.p.cp _ data.p.cp.InlineAdd[VMul[s, data.p.correctSpace]]; ENDCASE; }; SetCorrectMeasure: PROC[context: Context, v: VEC] ~ { data: Data ~ NARROW[context.data]; data.p.correctMeasure _ data.clientToView.TransformVec[v]; }; SetCorrectTolerance: PROC[context: Context, v: VEC] ~ { data: Data ~ NARROW[context.data]; data.np.correctTolerance _ data.clientToView.TransformVec[v]; }; Correct: PROC[context: Context, body: PROC] ~ { data: Data ~ NARROW[context.data]; shrink: REAL ~ data.np.correctShrink; tolerance: VEC ~ data.np.correctTolerance; start, end, measure, target, correction: VEC; mask, space: VEC _ [0, 0]; data.p.correctMaskCount _ 0; data.p.correctSum _ [0, 0]; data.np.noImage _ 1; data.np.correctPass _ 1; start _ data.p.cp; -- starting position DoSave[context, body]; -- pass 1 end _ data.p.cp; -- ending position measure _ data.p.correctMeasure; -- desired measure (note: may be set by pass 1) target _ start.Add[measure]; -- target position correction _ target.Sub[end]; -- amount of correction needed (end + correction = target) IF correction.Length<=tolerance.Length THEN NULL -- close enough ELSE IF end.Sub[start].Length(shrink*data.p.correctSum.Length) THEN { mask _ correction.Add[data.p.correctSum.Mul[shrink]]; space _ correction.Sub[mask]; }; }; IF data.p.correctSum.x#0 THEN space.x _ space.x/data.p.correctSum.x ELSE IF space.x#0 THEN { mask.x _ mask.x+space.x; space.x _ 0 }; IF data.p.correctSum.y#0 THEN space.y _ space.y/data.p.correctSum.y ELSE IF space.y#0 THEN { mask.y _ mask.y+space.y; space.y _ 0 }; IF data.p.correctMaskCount#0 THEN { IF mask.x=0 AND mask.y=0 THEN data.p.correctMaskCount _ 0 ELSE IF data.p.correctMaskCount>1 THEN { data.p.correctMaskCount _ data.p.correctMaskCount-1; mask _ mask.Div[data.p.correctMaskCount]; }; }; data.p.correctMask _ mask; data.p.correctSpace _ space; data.np.noImage _ 0; data.np.correctPass _ 2; data.p.cp _ start; DoSave[context, body]; -- pass 2 end _ data.p.cp; -- ending position data.p.cp _ target; <tolerance.Length THEN>> <> }; MaskDevicePath: PROC[data: Data, parity: BOOL _ FALSE] ~ { IF data.clientClipperValid THEN { Runs: PROC[run: PROC[sMin, fMin: INTEGER, fSize: NAT]] ~ { ImagerMask.GenerateRuns[ mask: data.devicePath, clipper: data.clientClipMask, runProc: run]; }; ValidateDisplayColor[data]; -- notify display if color changed data.display.MaskRuns[Runs]; } ELSE ERROR Imager.Error[$Bug]; -- clipper should have been validated }; MaskFill: PROC[context: Context, pathProc: PathProc, pathData: REF, parity: BOOL] ~ { data: Data ~ NARROW[context.data]; <> IF data.np.noImage=0 THEN { ValidateClientToDisplay[data]; -- validate data.clientToDisplay ValidateClientClipper[data]; -- validate data.clientClipMask and data.clientClipBox data.devicePath _ ImagerScanConverter.CreatePath[ pathProc: pathProc, pathData: pathData, transformation: data.clientToDisplay, clipBox: data.clientClipBox, scratch: data.devicePath]; MaskDevicePath[data, parity]; }; }; MaskStroke: PROC[context: Context, pathProc: PathProc, pathData: REF, closed: BOOL] ~ { data: Data ~ NARROW[context.data]; <> IF data.np.noImage=0 THEN { style: ImagerStroke.StrokeStyle ~ SELECT data.np.strokeEnd FROM 0 => square, 1 => butt, 2 => round, ENDCASE => roundWithRoundJoints; ValidateClientToDisplay[data]; -- validate data.clientToDisplay ValidateClientClipper[data]; -- validate data.clientClipMask and data.clientClipBox data.devicePath _ ImagerStroke.DevicePathFromStroke[ pathProc: pathProc, pathData: pathData, width: data.np.strokeWidth, style: style, closed: closed, clientToDevice: data.clientToDisplay, clipBox: data.clientClipBox, scratch: data.devicePath]; MaskDevicePath[data]; }; }; MaskRectangle: PROC[context: Context, x, y, w, h: REAL] ~ { data: Data ~ NARROW[context.data]; <> IF data.np.noImage=0 THEN { rectangle: PathProc ~ { moveTo[[x, y]]; lineTo[[x+w, y]]; lineTo[[x+w, y+h]]; lineTo[[x, y+h]]; }; ValidateClientToDisplay[data]; -- validate data.clientToDisplay ValidateClientClipper[data]; -- validate data.clientClipMask and data.clientClipBox data.devicePath _ ImagerScanConverter.CreatePath[ pathProc: rectangle, pathData: NIL, transformation: data.clientToDisplay, clipBox: data.clientClipBox, scratch: data.devicePath]; MaskDevicePath[data]; }; }; MaskRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ~ { data: Data ~ NARROW[context.data]; <> IF data.np.noImage=0 THEN { ValidateClientToDisplay[data]; -- validate data.clientToDisplay <> <> <> <> <> <> <> <> <> <> <> <> <> <<}>> <> MaskRectangle[context, x, y, w, h]; }; }; MaskPixel: PROC[context: Context, pa: PixelArray] ~ { data: Data ~ NARROW[context.data]; <> IF data.np.noImage=0 THEN { paToDisplay: Transformation _ NIL; pixelMask: ImagerMask.Mask _ NIL; ValidateClientToDisplay[data]; -- validate data.clientToDisplay ValidateClientClipper[data]; -- validate data.clientClipMask and data.clientClipBox ERROR; <> <> <> <> }; }; MaskBits: PROC[context: Context, base: LONG POINTER, wordsPerLine: NAT, sMin, fMin, sSize, fSize: NAT, sOffset, fOffset: INTEGER _ 0] ~ { data: Data ~ NARROW[context.data]; <> IF data.np.noImage=0 THEN { pixelMask: ImagerMask.Mask _ NIL; ValidateClientToDisplay[data]; -- validate data.clientToDisplay ValidateClientClipper[data]; -- validate data.clientClipMask and data.clientClipBox ERROR; <> <> <> <> }; }; ShowChar: PROC[context: Context, char: CHAR, charSet: BYTE _ 0] ~ { data: Data ~ NARROW[context.data]; <> font: FONT ~ data.font; code: Font.Char ~ charSet*256+ORD[char]; action: PROC ~ { width: VEC _ font.Width[code]; IF font.Amplified[code] THEN width _ width.Mul[data.np.amplifySpace]; Trans[context]; font.MaskChar[code, context]; SetXYRel[context, width]; SELECT font.Correction[code] FROM none => NULL; space => CorrectSpace[context, width]; mask => CorrectMask[context]; ENDCASE => ERROR Imager.Error[$Bug]; }; DoSave[context, action]; }; ShowRope: PROC[context: Context, rope: ROPE, start, len: INT, charSet: BYTE] ~ { action: Rope.ActionType ~ { ShowChar[context, c] }; [] _ Rope.Map[base: rope, start: start, len: len, action: action]; }; ShowText: PROC[context: Context, text: REF READONLY TEXT, start, len: NAT, charSet: BYTE] ~ { action: Rope.ActionType ~ { ShowChar[context, c] }; [] _ RefText.Map[s: text, start: start, len: len, action: action]; }; <> <> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <<};>> <> <> <> <> < NULL;>> < { -- correct mask -- };>> < { -- correct space -- };>> <> <<};>> <> <> <> <> <> <> < IF char='\377 THEN state _ esc ELSE Char[char];>> < IF char='\377 THEN state _ esc2 ELSE { Set[ORD[char]]; state _ run };>> < IF char='\000 THEN state _ ext ELSE ERROR Imager.Error[$InvalidString];>> < IF char='\377 THEN state _ esc ELSE { Set[ORD[char]]; state _ ext2 };>> < { Char[char]; state _ ext };>> < ERROR;>> <> <> <<};>> <<>> ViewReset: PROC[data: Data] ~ { data.viewToDisplay^ _ data.display.surfaceToDisplay^; data.viewToDisplayValid _ FALSE; data.clientToDisplayValid _ FALSE; data.charToDisplayValid _ FALSE; ImagerManhattan.Destroy[data.viewClipMask]; data.viewClipMask _ ImagerManhattan.CreateFromBox[data.display.clipBox]; data.viewClipperValid _ FALSE; data.clientClipperValid _ FALSE; }; ViewTranslate: PUBLIC PROC[context: Context, x, y: INTEGER] ~ { WITH context.data SELECT FROM data: Data => { data.viewToDisplay.PreTranslate[x, y]; data.viewToDisplayValid _ FALSE; data.clientToDisplayValid _ FALSE; <> data.clientClipperValid _ FALSE; }; ENDCASE => ERROR Imager.Error[$Unimplemented]; }; ViewClip: PUBLIC PROC[context: Context, x, y, w, h: INTEGER, exclude: BOOL] ~ { WITH context.data SELECT FROM data: Data => { old, this, new: ManhattanPolygon; old _ data.viewClipMask; ValidateViewToDisplay[data]; IF data.viewToDisplayEasy THEN { origin: IVEC ~ data.viewOrigin; xmin, xmax: INTEGER _ x; ymin, ymax: INTEGER _ y; IF w<0 THEN xmin _ xmax+w ELSE xmax _ xmin+w; IF h<0 THEN ymin _ ymax+h ELSE ymax _ ymin+h; this _ ImagerManhattan.CreateFromBox[[ sMin: origin.y-ymax, fMin: origin.x+xmin, sSize: ymax-ymin, fSize: xmax-xmin]]; } ELSE { rectangle: PathProc ~ { moveTo[[x, y]]; lineTo[[x+w, y]]; lineTo[[x+w, y+h]]; lineTo[[x, y+h]]; }; displayClipBox: DeviceRectangle ~ data.display.clipBox; data.devicePath _ ImagerScanConverter.CreatePath[ pathProc: rectangle, pathData: NIL, transformation: data.viewToDisplay, clipBox: displayClipBox, scratch: data.devicePath]; this _ ImagerScanConverter.ConvertToManhattanPolygon[ devicePath: data.devicePath, clipBox: displayClipBox]; }; IF exclude THEN new _ old.Difference[this] ELSE new _ old.Intersection[this]; data.viewClipMask _ new; ImagerManhattan.Destroy[old]; ImagerManhattan.Destroy[this]; data.viewClipperValid _ FALSE; data.clientClipperValid _ FALSE; }; ENDCASE => ERROR Imager.Error[$Unimplemented]; }; <> <> < {>> <> <> <> <> <> <> <> <> <> <> <<};>> <> <> <> <<};>> <<[[sMinDest, fMinDest, sSize, fSize]] _>> <> <<[[sMinSource, fMinSource, sSize, fSize]] _>> <> <> <<};>> < ERROR Imager.Error[$Unimplemented];>> <<};>> <<>> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<}>> <> <> <> <> <> <> <<};>> <> <> <> <<};>> <> <> <> <<};>> <<>> <> <> < RETURN[[0, 0, data.surfaceWidth, data.surfaceHeight]];>> < ERROR Imager.Error[$Unimplemented];>> <<};>> <<>> displayClass: Imager.Class ~ NEW[Imager.ClassRep _ [ type: $Display, DoSave: DoSave, DoSaveAll: DoSaveAll, SetTransformation: SetTransformation, SetFont: SetFont, SetColor: SetColor, SetClipper: SetClipper, SetReal: SetReal, SetInt: SetInt, ConcatT: ConcatT, Scale2T: Scale2T, RotateT: RotateT, TranslateT: TranslateT, Move: Move, Trans: Trans, SetGray: SetGray, SetSampledColor: SetSampledColor, MaskFill: MaskFill, MaskStroke: MaskStroke, MaskRectangle: MaskRectangle, MaskRectangleI: MaskRectangleI, MaskVector: ImagerUtils.MaskVectorViaMaskStroke, MaskVectorI: ImagerUtils.MaskVectorIViaMaskStroke, StartUnderline: StartUnderline, MaskUnderline: MaskUnderline, MaskUnderlineI: ImagerUtils.MaskUnderlineIViaMaskUnderline, MaskPixel: MaskPixel, MaskBits: MaskBits, SetXY: SetXY, SetXYI: SetXYI, SetXYRel: SetXYRel, SetXYRelI: SetXYRelI, ShowChar: ShowChar, ShowRope: ShowRope, ShowText: ShowText, ClipOutline: ClipOutline, ClipRectangle: ClipRectangle, ClipRectangleI: ImagerUtils.ClipRectangleIViaClipRectangle, CorrectMask: CorrectMask, CorrectSpace: CorrectSpace, Space: Space, SpaceI: ImagerUtils.SpaceIViaSpace, SetCorrectMeasure: SetCorrectMeasure, SetCorrectTolerance: SetCorrectTolerance, Correct: Correct, GetTransformation: GetTransformation, GetFont: GetFont, GetColor: GetColor, GetClipper: GetClipper, GetReal: GetReal, GetInt: GetInt, GetCP: GetCP, GetCPRounded: GetCPRounded, props: NIL ]]; END.