<> <> <> DIRECTORY Basics USING [bitsPerWord], Font USING [FONT], Imager USING [black, Class, ClassRep, Context, Error, GetProp, State, white], ImagerBasic USING [ClientClipperItem, Color, ColorRep, ConstantColor, DeviceRectangle, IntPair, IntRectangle, Pair, PathMapType, PixelArray, PixelArrayRep, PixelBuffer, SampledColor, Transformation, Visibility], ImagerBrick USING [Brick], ImagerConic USING [ToCurves], ImagerDefault USING [ClipOutline, ClipRectangle, ClipRectangleI, ConcatT, Correct, CorrectMask, CorrectSpace, CorrectSpaceView, DoSave, DoSaveAll, ExcludeOutline, ExcludeRectangle, ExcludeRectangleI, MaskUnderline, MaskUnderlineI, MaskVector, MaskVectorI, Move, RotateT, Scale2T, ScaleT, SetAmplifySpace, SetColor, SetCorrectMeasure, SetCorrectShrink, SetCorrectTolerance, SetFont, SetGray, SetNoImage, SetPriorityImportant, SetSampledBlack, SetSampledColor, SetStrokeEnd, SetStrokeWidth, SetXY, SetXYI, SetXYRel, SetXYRelI, Space, SpaceI, StartUnderline, Trans, TranslateT], ImagerFontCache USING [Create, FontCache, FontCode, FontObject, GetFontCode, GetRopeData, GetTextData], <> ImagerHalftone USING [DeviceBrick, Halftone, MakeDeviceBrick, MakeSquareBrick], ImagerLF USING [DataRep, State], ImagerManhattan USING [BoundingBox, Copy, CountBoxes, CreateFromBox, CreateFromRuns, Destroy, Difference, Intersection, IsVisible, Polygon], ImagerMasks USING [ApplyConstant, ApplyTile, FromBitmap, FromPixelArray, GenerateRuns], ImagerOps USING [XOR], ImagerPixelMaps USING [BoundedWindow, Clear, Clip, Create, Fill, PixelMap, ShiftMap, Tile, TileFromStipple, Transfer], ImagerScanConverter USING [ConvertToManhattanPolygon, CreatePath, DevicePath, PathProc], ImagerStroke USING [DevicePathFromStroke], ImagerTransform USING [Concat, Contents, Create, FromRec, Invert, Rotate, TransformationRec, TransformIntRectangle, TransformVec], Real USING [RoundC, RoundI, RoundLI], RefText USING [ObtainScratch, ReleaseScratch], Rope USING [ROPE, Size], Scaled USING [Float, Floor, FromInt, FromReal, MINUS, PLUS, Round, Value]; ImagerLFImpl: CEDAR PROGRAM IMPORTS Imager, ImagerConic, ImagerDefault, ImagerFontCache, ImagerHalftone, ImagerManhattan, ImagerMasks, ImagerOps, ImagerPixelMaps, ImagerScanConverter, ImagerStroke, ImagerTransform, Real, RefText, Rope, Scaled ~ BEGIN OPEN ImagerBasic; ROPE: TYPE ~ Rope.ROPE; StatsRecord: TYPE ~ RECORD [ loadRunGroups, loadRasters, runGroupChars, rasterChars, clippedChars, culledChars: INT _ 0]; stats: StatsRecord _ []; Stats: PROC RETURNS [StatsRecord] ~ { x: StatsRecord ~ stats; stats _ []; RETURN[x] }; FONT: TYPE ~ Font.FONT; PixelMap: TYPE ~ ImagerPixelMaps.PixelMap; Tile: TYPE ~ ImagerPixelMaps.Tile; SpecialColor: TYPE ~ REF ColorRep[special]; ManhattanPolygon: TYPE ~ ImagerManhattan.Polygon; TransformationRec: TYPE ~ ImagerTransform.TransformationRec; Context: TYPE ~ Imager.Context; State: TYPE ~ ImagerLF.State; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD[ cpx, cpy: REAL, -- current position (persistent) correctMX, correctMY: REAL, -- correct measure (persistent) T: Transformation, -- current transformation (client to view) priorityImportant: INT, -- if nonzero, priority is important mediumXSize, mediumYSize: REAL, -- medium size fieldXMin, fieldYMin, fieldXMax, fieldYMax: REAL, -- field location font: FONT, -- current font ("showVec") color: Color, -- current color noImage: INT, -- if nonzero, don't image masks strokeWidth: REAL, -- current stroke width strokeEnd: INT, -- current stroke end treatment underlineStart: REAL, -- starting x position for underline amplifySpace: REAL, clipper: ClientClipper, correctPass: INT, correctShrink: REAL, correctTX, correctTY: REAL, -- correct tolerance correctMaskCount: INT, -- CORRECT variables (all persistent) correctMaskX, correctMaskY: REAL, correctSumX, correctSumY: REAL, correctSpaceX, correctSpaceY: REAL, correctcpx, correctcpy: REAL, correctTargetX, correctTargetY: REAL, <> viewClipper: ImagerManhattan.Polygon, -- in device coords clientClipper: ImagerBasic.ClientClipper, -- for noticing client clipper changes compositeClipper: ImagerManhattan.Polygon, -- in device coords; invalid if NIL or clientClipper#clipper <> viewOrigin: ImagerBasic.IntPair, <> devicePath: ImagerScanConverter.DevicePath, tileSamples: ImagerBasic.SampledColor, deviceBrick: ImagerHalftone.DeviceBrick _ NIL, deviceBrickMaxSampleValue: INT _ -1, <> cachedColor: ImagerBasic.Color _ NIL, tile: ImagerPixelMaps.Tile, <> canvas: ImagerPixelMaps.PixelMap ]; DoSave: PROC[context: Context, body: PROC] ~ { data: Data ~ NARROW[context.data]; T: Transformation ~ data.T; priorityImportant: INT ~ data.priorityImportant; mediumXSize: REAL ~ data.mediumXSize; mediumYSize: REAL ~ data.mediumYSize; fieldXMin: REAL ~ data.fieldXMin; fieldYMin: REAL ~ data.fieldYMin; fieldXMax: REAL ~ data.fieldXMax; fieldYMax: REAL ~ data.fieldYMax; showVec: REF ~ data.showVec; color: Color ~ data.color; noImage: INT ~ data.noImage; strokeWidth: REAL ~ data.strokeWidth; strokeEnd: INT ~ data.strokeEnd; underlineStart: REAL ~ data.underlineStart; amplifySpace: REAL ~ data.amplifySpace; clipper: ClientClipper ~ data.clipper; correctPass: INT ~ data.correctPass; correctShrink: REAL ~ data.correctShrink; correctTX: REAL ~ data.correctTX; correctTY: REAL ~ data.correctTY; Restore: PROC ~ { data.T _ T; data.priorityImportant _ priorityImportant; data.mediumXSize _ mediumXSize; data.mediumYSize _ mediumYSize; data.fieldXMin _ fieldXMin; data.fieldYMin _ fieldYMin; data.fieldXMax _ fieldXMax; data.fieldYMax _ fieldYMax; data.showVec _ showVec; data.color _ color; data.noImage _ noImage; data.strokeWidth _ strokeWidth; data.strokeEnd _ strokeEnd; data.underlineStart _ underlineStart; data.amplifySpace _ amplifySpace; data.clipper _ clipper; data.correctPass _ correctPass; data.correctShrink _ correctShrink; data.correctTX _ correctTX; data.correctTY _ correctTY; }; body[! UNWIND => Restore[]]; Restore[]; }; DoSaveAll: PROC[context: Context, body: PROC] ~ { data: Data ~ NARROW[context.data]; cpx: REAL ~ data.cpx; cpy: REAL ~ data.cpy; correctMX: REAL ~ data.correctMX; correctMY: REAL ~ data.correctMY; correctMaskCount: INT ~ data.correctMaskCount; correctMaskX: REAL ~ data.correctMaskX; correctMaskY: REAL ~ data.correctMaskY; correctSumX: REAL ~ data.correctSumX; correctSumY: REAL ~ data.correctSumY; correctSpaceX: REAL ~ data.correctSpaceX; correctSpaceY: REAL ~ data.correctSpaceY; correctcpx: REAL ~ data.correctcpx; correctcpy: REAL ~ data.correctcpy; correctTargetX: REAL ~ data.correctTargetX; correctTargetY: REAL ~ data.correctTargetY; Restore: PROC ~ { data.cpx _ cpx; data.cpy _ cpy; data.correctMX _ correctMX; data.correctMY _ correctMY; data.correctMaskCount _ correctMaskCount; data.correctMaskX _ correctMaskX; data.correctMaskY _ correctMaskY; data.correctSumX _ correctSumX; data.correctSumY _ correctSumY; data.correctSpaceX _ correctSpaceX; data.correctSpaceY _ correctSpaceY; data.correctcpx _ correctcpx; data.correctcpy _ correctcpy; data.correctTargetX _ correctTargetX; data.correctTargetY _ correctTargetY; }; DoSave[context, body ! UNWIND => Restore[]]; Restore[]; }; SetRef: PROC[context: Context, key: Variable, value: REF] ~ { data: Data ~ NARROW[context.data]; SELECT key FROM <<$DCScpx => data.cpx _ value;>> <<$DCScpy => data.cpy _ value;>> <<$correctMX => data.correctMX _ value;>> <<$correctMY => data.correctMY _ value;>> $T => data.T _ NARROW[value]; <<$priorityImportant => data.priorityImportant _ value;>> <<$mediumXSize => data.mediumXSize _ value;>> <<$mediumYSize => data.mediumYSize _ value;>> <<$fieldXMin => data.fieldXMin _ value;>> <<$fieldYMin => data.fieldYMin _ value;>> <<$fieldXMax => data.fieldXMax _ value;>> <<$fieldYMax => data.fieldYMax _ value;>> $showVec => data.font _ NARROW[value]; $color => data.color _ NARROW[value]; <<$noImage => data.noImage _ value;>> <<$strokeWidth => data.strokeWidth _ value;>> <<$strokeEnd => data.strokeEnd _ value;>> <<$underlineStart => data.underlineStart _ value;>> <<$amplifySpace => data.amplifySpace _ value;>> <<$correctPass => data.correctPass _ value;>> <<$correctShrink => data.correctShrink _ value;>> <<$correctTX => data.correctTX _ value;>> <<$correctTY => data.correctTY _ value;>> $clipper => data.clipper _ NARROW[value]; ENDCASE => ERROR Imager.Error[$WrongType]; }; SetReal: PROC[context: Context, key: Variable, value: REAL] ~ { data: Data ~ NARROW[context.data]; SELECT key FROM $DCScpx => data.cpx _ value; $DCScpy => data.cpy _ value; $correctMX => data.correctMX _ value; $correctMY => data.correctMY _ value; $mediumXSize => data.mediumXSize _ value; $mediumYSize => data.mediumYSize _ value; $fieldXMin => data.fieldXMin _ value; $fieldYMin => data.fieldYMin _ value; $fieldXMax => data.fieldXMax _ value; $fieldYMax => data.fieldYMax _ value; $strokeWidth => data.strokeWidth _ value; $underlineStart => data.underlineStart _ value; $amplifySpace => data.amplifySpace _ value; $correctShrink => data.correctShrink _ value; $correctTX => data.correctTX _ value; $correctTY => data.correctTY _ value; ENDCASE => ERROR Imager.Error[$WrongType]; }; SetInt: PROC[context: Context, key: Variable, value: INT] ~ { data: Data ~ NARROW[context.data]; SELECT key FROM $priorityImportant => data.priorityImportant _ value; $noImage => data.noImage _ value; $strokeEnd => data.strokeEnd _ value; $correctPass => data.correctPass _ value; ENDCASE => ERROR Imager.Error[$WrongType]; }; GetRef: PROC[context: Context, key: Variable] RETURNS[REF] ~ { data: Data ~ NARROW[context.data]; SELECT key FROM <<$DCScpx => RETURN[data.cpx];>> <<$DCScpy => RETURN[data.cpy];>> <<$correctMX => RETURN[data.correctMX];>> <<$correctMY => RETURN[data.correctMY];>> $T => RETURN[data.T]; <<$priorityImportant => RETURN[data.priorityImportant];>> <<$mediumXSize => RETURN[data.mediumXSize];>> <<$mediumYSize => RETURN[data.mediumYSize];>> <<$fieldXMin => RETURN[data.fieldXMin];>> <<$fieldYMin => RETURN[data.fieldYMin];>> <<$fieldXMax => RETURN[data.fieldXMax];>> <<$fieldYMax => RETURN[data.fieldYMax];>> $showVec => RETURN[data.font]; $color => RETURN[data.color]; <<$noImage => RETURN[data.noImage];>> <<$strokeWidth => RETURN[data.strokeWidth];>> <<$strokeEnd => RETURN[data.strokeEnd];>> <<$underlineStart => RETURN[data.underlineStart];>> <<$amplifySpace => RETURN[data.amplifySpace];>> <<$correctPass => RETURN[data.correctPass];>> <<$correctShrink => RETURN[data.correctShrink];>> <<$correctTX => RETURN[data.correctTX];>> <<$correctTY => RETURN[data.correctTY];>> $clipper => RETURN[data.clipper]; ENDCASE => ERROR Imager.Error[$WrongType]; }; GetReal: PROC[context: Context, key: Variable] RETURNS[REAL] ~ { data: Data ~ NARROW[context.data]; SELECT key FROM $DCScpx => RETURN[data.cpx]; $DCScpy => RETURN[data.cpy]; $correctMX => RETURN[data.correctMX]; $correctMY => RETURN[data.correctMY]; $mediumXSize => RETURN[data.mediumXSize]; $mediumYSize => RETURN[data.mediumYSize]; $fieldXMin => RETURN[data.fieldXMin]; $fieldYMin => RETURN[data.fieldYMin]; $fieldXMax => RETURN[data.fieldXMax]; $fieldYMax => RETURN[data.fieldYMax]; $strokeWidth => RETURN[data.strokeWidth]; $underlineStart => RETURN[data.underlineStart]; $amplifySpace => RETURN[data.amplifySpace]; $correctShrink => RETURN[data.correctShrink]; $correctTX => RETURN[data.correctTX]; $correctTY => RETURN[data.correctTY]; ENDCASE => ERROR Imager.Error[$WrongType]; }; GetInt: PROC[context: Context, key: Variable] RETURNS[INT] ~ { data: Data ~ NARROW[context.data]; SELECT key FROM $priorityImportant => RETURN[data.priorityImportant]; $noImage => RETURN[data.noImage]; $strokeEnd => RETURN[data.strokeEnd]; $correctPass => RETURN[data.correctPass]; ENDCASE => ERROR Imager.Error[$WrongType]; }; SetGray: PROC[context: Context, f: REAL] ~ { }; SetSampledColor: PROC[context: Context, pa: PixelArray, pixelT: Transformation, colorOperator: ATOM] ~ { }; SetSampledBlack: PROC[context: Context, pa: PixelArray, pixelT: Transformation, transparent: BOOL] ~ { }; ConcatT: PROC[context: Context, m: Transformation] ~ { data: Data ~ NARROW[context.data]; data.T _ ImagerTransform.Concat[m, data.T]; }; ScaleT: PROC[context: Context, s: REAL] ~ { data: Data ~ NARROW[context.data]; data.T _ ImagerTransform.PreScale[s, data.T]; }; Scale2T: PROC[context: Context, sx, sy: REAL] ~ { data: Data ~ NARROW[context.data]; data.T _ ImagerTransform.PreScale2[sx, sy, data.T]; }; RotateT: PROC[context: Context, a: REAL] ~ { data: Data ~ NARROW[context.data]; data.T _ ImagerTransform.PreRotate[a, data.T]; }; TranslateT: PROC[context: Context, x, y: REAL] ~ { data: Data ~ NARROW[context.data]; data.T _ ImagerTransform.PreTranslate[x, y, data.T]; }; Move: PROC[context: Context] ~ { data: Data ~ NARROW[context.data]; new: Pair ~ [data.cpx, data.cpy]; t: Transformation ~ data.T; data.T _ ImagerTransform.Create[t.a, t.b, new.x, t.d, t.e, new.y]; }; Trans: PROC[context: Context] ~ { data: Data ~ NARROW[context.data]; new: Pair ~ ImagerOps.DRound[[data.cpx, data.cpy]]; t: Transformation ~ data.T; data.T _ ImagerTransform.Create[t.a, t.b, new.x, t.d, t.e, new.y]; }; SetFont: PROC[context: Context, font: FONT] ~ { data: Data ~ NARROW[context.data]; }; ShowRope: PROC[context: Context, rope: ROPE, start, len: INT] ~ { data: Data ~ NARROW[context.data]; }; ShowText: PROC[context: Context, text: REF READONLY TEXT, start, len: NAT] ~ { data: Data ~ NARROW[context.data]; }; ShowCharCode: PROC[context: Context, charCode: CARDINAL] ~ { data: Data ~ NARROW[context.data]; }; SetXY: PROC[context: Context, x, y: REAL] ~ { data: Data ~ NARROW[context.data]; [[data.cpx, data.cpy]] _ ImagerTransform.Transform[[x, y], data.T]; }; SetXYI: PROC[context: Context, x, y: INTEGER] ~ { data: Data ~ NARROW[context.data]; [[data.cpx, data.cpy]] _ ImagerTransform.Transform[[x, y], data.T]; }; SetXYRel: PROC[context: Context, x, y: REAL] ~ { data: Data ~ NARROW[context.data]; delta: Pair ~ ImagerTransform.TransformVec[[x, y], data.T]; data.cpx _ data.cpx + delta.x; data.cpy _ data.cpy + delta.y; }; SetXYRelI: PROC[context: Context, x, y: INTEGER] ~ { data: Data ~ NARROW[context.data]; delta: Pair ~ ImagerTransform.TransformVec[[x, y], data.T]; data.cpx _ data.cpx + delta.x; data.cpy _ data.cpy + delta.y; }; MaskFill: PROC[context: Context, pathProc: PathProc, pathData: REF] ~ { data: Data ~ NARROW[context.data]; }; MaskStroke: PROC[context: Context, pathProc: PathProc, pathData: REF] ~ { data: Data ~ NARROW[context.data]; }; MaskStrokeClosed: PROC[context: Context, pathProc: PathProc, pathData: REF] ~ { data: Data ~ NARROW[context.data]; }; MaskVector: PROC[context: Context, x1, y1, x2, y2: REAL] ~ { vector: PathProc ~ { move[[x1, y1]]; line[[x2, y2]] }; MaskStroke[context, vector, NIL]; }; MaskVectorI: PROC[context: Context, x1, y1, x2, y2: INTEGER] ~ { vector: PathProc ~ { move[[x1, y1]]; line[[x2, y2]] }; MaskStroke[context, vector, NIL]; }; MaskRectangle: PROC[context: Context, x, y, w, h: REAL] ~ { data: Data ~ NARROW[context.data]; }; MaskRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ~ { data: Data ~ NARROW[context.data]; }; StartUnderline: PROC[context: Context] ~ { data: Data ~ NARROW[context.data]; cp: Pair ~ ImagerTransform.InverseTransform[[data.cpx, data.cpy], data.T]; data.underlineStart _ cp.x; }; MaskUnderline: PROC[context: Context, dy, h: REAL] ~ { data: Data ~ NARROW[context.data]; cpx: REAL ~ data.cpx; cpy: REAL ~ data.cpy; T: Transformation ~ data.T; cp: Pair ~ ImagerTransform.InverseTransform[[cpx, cpy], T]; SetXY[context, data.underlineStart, cp.y-dy-h]; Trans[context]; MaskRectangle[context, 0, 0, cp.x-data.underlineStart, h]; data.cpx _ cpx; data.cpy _ cpy; data.T _ T; }; MaskUnderlineI: PROC[context: Context, dy, h: INTEGER] ~ { MaskUnderline[context, dy, h]; }; MaskPixel: PROC[context: Context, pa: PixelArray] ~ { data: Data ~ NARROW[context.data]; }; ClipOutline: PROC[context: Context, pathProc: PathProc, pathData: REF] ~ { data: Data ~ NARROW[context.data]; }; ExcludeOutline: PROC[context: Context, pathProc: PathProc, pathData: REF] ~ { data: Data ~ NARROW[context.data]; }; ClipRectangle: PROC[context: Context, x, y, w, h: REAL] ~ { data: Data ~ NARROW[context.data]; }; ClipRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ~ { data: Data ~ NARROW[context.data]; }; ExcludeRectangle: PROC[context: Context, x, y, w, h: REAL] ~ { data: Data ~ NARROW[context.data]; }; ExcludeRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ~ { data: Data ~ NARROW[context.data]; }; CorrectMask: PROC[context: Context] ~ { data: Data ~ NARROW[context.data]; SELECT data.correctPass FROM 1 => data.correctMaskCount _ data.correctMaskCount + 1; 2 => IF data.correctMaskCount > 0 THEN { spx: REAL ~ data.correctMaskX/data.correctMaskCount; spy: REAL ~ data.correctMaskY/data.correctMaskCount; data.correctMaskX _ data.correctMaskX - spx; data.correctMaskY _ data.correctMaskY - spy; data.correctMaskCount _ data.correctMaskCount - 1; data.cpx _ data.cpx + spx; data.cpy _ data.cpy + spy; }; ENDCASE => NULL; }; CorrectSpace: PROC[context: Context, x, y: REAL] ~ { data: Data ~ NARROW[context.data]; }; Correct: PROC[context: Context, body: PROC] ~ { data: Data ~ NARROW[context.data]; }; SetCorrectMeasure: PROC[context: Context, x, y: REAL] ~ { data: Data ~ NARROW[context.data]; [[data.correctMX, data.correctMY]] _ ImagerTransform.TransformVec[[x, y], data.T]; }; SetCorrectTolerance: PROC[context: Context, x, y: REAL] ~ { data: Data ~ NARROW[context.data]; [[data.correctTX, data.correctTY]] _ ImagerTransform.TransformVec[[x, y], data.T]; }; Space: PROC[context: Context, x: REAL] ~ { <> data: Data ~ NARROW[context.data]; v: Pair ~ ImagerTransform.TransformVec[[x, 0], data.T]; data.cpx _ data.cpx + v.x; data.cpy _ data.cpy + v.y; SELECT data.correctPass FROM 1 => { data.correctSumX _ data.correctSumX + v.x; data.correctSumY _ data.correctSumY + v.y; }; 2 => IF data.correctMaskCount > 0 THEN { Div: PROC [num, denom: REAL] RETURNS [REAL] ~ { IF denom = 0.0 THEN { IF num = 0.0 THEN RETURN [0.0] ELSE ERROR Imager.Error[$ZeroDivideInCorrectSpace] } ELSE RETURN [num/denom] }; spx: REAL ~ Div[v.x*data.correctSpaceX, data.correctSumX]; spy: REAL ~ Div[v.y*data.correctSpaceY, data.correctSumY]; data.correctSumX _ data.correctSumX - v.x; data.correctSumY _ data.correctSumY - v.y; data.correctSpaceX _ data.correctSpaceX - spx; data.correctSpaceY _ data.correctSpaceY - spy; data.cpx _ data.cpx + spx; data.cpy _ data.cpy + spy; }; ENDCASE => NULL; }; SpaceI: PROC[context: Context, x: INTEGER] ~ { Space[context, x]; }; SurfaceOriginS: PROC[data: Data] RETURNS[INTEGER] ~ INLINE { RETURN[data.canvas.sSize] }; CompositeT: PROC [data: Data] RETURNS [TransformationRec] ~ { <> t: TransformationRec ~ data.T.Contents; RETURN [[ a: -t.d, d: t.a, b: -t.e, e: t.b, c: -t.f+SurfaceOriginS[data]-data.viewOrigin.y, f: t.c+data.viewOrigin.x ]] }; ViewToDevice: PROC [data: Data] RETURNS [TransformationRec] ~ { RETURN [[ a: 0, d: 1, b: -1, e: 0, c: SurfaceOriginS[data]-data.viewOrigin.y, f: data.viewOrigin.x ]] }; SurfaceToDevice: PROC [data: Data] RETURNS [TransformationRec] ~ { RETURN [[ a: 0, d: 1, b: -1, e: 0, c: SurfaceOriginS[data], f: 0 ]] }; DevicePair: TYPE ~ RECORD [s, f: Scaled.Value]; TransformDeviceToViewVec: PROC [d: DevicePair] RETURNS [v: Pair] ~ { v _ [x: Scaled.Float[d.f], y: -Scaled.Float[d.s]]; }; GetDeviceCP: PROC [data: Data] RETURNS [DevicePair] ~ { RETURN [[ s: ScaledFromReal[-data.cpy].PLUS[Scaled.FromInt[SurfaceOriginS[data]-data.viewOrigin.y]], f: ScaledFromReal[data.cpx].PLUS[Scaled.FromInt[data.viewOrigin.x]] ]] }; SetDeviceCP: PROC [data: Data, cp: DevicePair] ~ { data.cpy _ -Scaled.Float[cp.s.MINUS[Scaled.FromInt[SurfaceOriginS[data]-data.viewOrigin.y]]]; data.cpx _ Scaled.Float[cp.f.MINUS[Scaled.FromInt[data.viewOrigin.x]]]; }; <> <> <> <> <> <> <> <> < data.canvas _ pm^;>> < TRUSTED {data.canvas _ ImagerFrameBuffer.LFDisplay[]};>> <> <> <> <> <<};>> <<>> pixelsPerInch: REAL ~ 72.0; mmPerInch: REAL ~ 25.4; inchesPerMeter: REAL ~ 1000.0/mmPerInch; pixelsPerMeter: REAL _ pixelsPerInch*inchesPerMeter; <> <> <> <> <> <> <> <> <> <<};>> <<>> MakeTileSamples: PROC [xSize, ySize: NAT] RETURNS [tileSamples: SampledColor] ~ { tileSamples _ NEW[ColorRep[sampled]]; tileSamples.transparent _ FALSE; tileSamples.pa _ NEW[PixelArrayRep]; tileSamples.m _ tileSamples.pa.m _ ImagerTransform.Rotate[0]; tileSamples.colorOperator _ $Intensity; tileSamples.pa.xPixels _ xSize; tileSamples.pa.yPixels _ ySize; tileSamples.pa.maxSampleValue _ 255; tileSamples.pa.samplesPerPixel _ 1; tileSamples.pa.get _ ConstantGet; tileSamples.pa.data _ NEW[NAT _ 0]; }; ConstantGet: PROC [self: PixelArray, buffer: PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ { WITH self.data SELECT FROM n: REF NAT => { value: NAT _ n^; FOR i: NAT IN [0..nSamples) DO buffer[i] _ value ENDLOOP; }; ENDCASE => ERROR; }; SetTileSamples: PROC [tileSamples: SampledColor, intensity: [0..255]] ~ { WITH tileSamples.pa.data SELECT FROM n: REF NAT => n^ _ intensity; ENDCASE => ERROR; }; DevicePathFromViewPath: PROC[data: Data, pathMap: PathMapType, pathData: REF] RETURNS [ImagerScanConverter.DevicePath] ~ { GenPath: ImagerScanConverter.PathProc <> <> <> ~ { Xform: PROC [p: Pair] RETURNS [Pair] ~ {RETURN[[ <> -p.y + SurfaceOriginS[data]-data.viewOrigin.y, p.x + data.viewOrigin.x ]]}; Xmove: PROC [p: Pair] ~ { q: Pair ~ Xform[p]; move[q.x, q.y]; lp _ q }; Xline: PROC [p: Pair] ~ { q: Pair ~ Xform[p]; line[q.x, q.y]; lp _ q }; Xcurve: PROC [p1, p2, p3: Pair] ~ { q1: Pair ~ Xform[p1]; q2: Pair ~ Xform[p2]; q3: Pair ~ Xform[p3]; curve[q1.x, q1.y, q2.x, q2.y, q3.x, q3.y]; lp _ q3 }; Curve: PROC [p1, p2, p3: Pair] ~ {curve[p1.x, p1.y, p2.x, p2.y, p3.x, p3.y]}; Xconic: PROC [p1, p2: Pair, r: REAL] ~ { q1: Pair ~ Xform[p1]; q2: Pair ~ Xform[p2]; ImagerConic.ToCurves[lp, q1, q2, r, Curve]; lp _ q2; }; lp: Pair; pathMap[pathData, Xmove, Xline, Xcurve, Xconic]; }; RETURN [ImagerScanConverter.CreatePath[pathProc: GenPath, clipBox: data.canvas.BoundedWindow]]; }; DevicePathFromPath: PROC[data: Data, pathMap: PathMapType, pathData: REF] ~ { GenPath: ImagerScanConverter.PathProc <> <> <> ~ { m: TransformationRec ~ CompositeT[data]; Xform: PROC [p: Pair] RETURNS [Pair] ~ {RETURN[[ <> m.a * p.x + m.b * p.y + m.c, m.d * p.x + m.e * p.y + m.f ]]}; Xmove: PROC [p: Pair] ~ { q: Pair ~ Xform[p]; move[q.x, q.y]; lp _ q }; Xline: PROC [p: Pair] ~ { q: Pair ~ Xform[p]; line[q.x, q.y]; lp _ q }; Xcurve: PROC [p1, p2, p3: Pair] ~ { q1: Pair ~ Xform[p1]; q2: Pair ~ Xform[p2]; q3: Pair ~ Xform[p3]; curve[q1.x, q1.y, q2.x, q2.y, q3.x, q3.y]; lp _ q3 }; Curve: PROC [p1, p2, p3: Pair] ~ {curve[p1.x, p1.y, p2.x, p2.y, p3.x, p3.y]}; Xconic: PROC [p1, p2: Pair, r: REAL] ~ { q1: Pair ~ Xform[p1]; q2: Pair ~ Xform[p2]; ImagerConic.ToCurves[lp, q1, q2, r, Curve]; lp _ q2; }; lp: Pair; pathMap[pathData, Xmove, Xline, Xcurve, Xconic]; }; data.devicePath _ ImagerScanConverter.CreatePath[pathProc: GenPath, clipBox: data.canvas.BoundedWindow, scratch: data.devicePath]; }; DevicePathFromStroke: PROC [data: Data, pathMap: PathMapType, pathData: REF, closed: BOOL] ~ { data.devicePath _ ImagerStroke.DevicePathFromStroke[ pathMap: pathMap, pathData: pathData, clientToDevice: CompositeT[data].FromRec, width: data.strokeWidth, strokeEnd: SELECT data.strokeEnd FROM 0 => square, 1 => butt, ENDCASE => round, closed: closed, clipBox: data.canvas.BoundedWindow, scratch: data.devicePath ]; }; Floor: PROC [real: REAL] RETURNS [int: INT] ~ { int _ Real.RoundLI[real]; WHILE int < real DO int _ int + 1 ENDLOOP; WHILE int > real DO int _ int - 1 ENDLOOP; }; Ceiling: PROC [real: REAL] RETURNS [int: INT] ~ { int _ Real.RoundLI[real]; WHILE int > real DO int _ int - 1 ENDLOOP; WHILE int < real DO int _ int + 1 ENDLOOP; }; ScaledFromReal: PROC [real: REAL] RETURNS [Scaled.Value] ~ TRUSTED { <> i: INT _ Real.RoundLI[real * 65536.0]; RETURN[LOOPHOLE[i]] }; CompositeClipper: PROC [data: Data] RETURNS [ManhattanPolygon] ~ { mp: ManhattanPolygon _ data.compositeClipper; IF mp = NIL OR data.clientClipper # data.clipper THEN { ConcatClippers: PROC [l: LIST OF ClientClipperItem] ~ { IF l#NIL THEN { t1, t2: ManhattanPolygon; ConcatClippers[l.rest]; t1 _ ImagerScanConverter.ConvertToManhattanPolygon[DevicePathFromViewPath[data: data, pathMap: l.first.pathMap, pathData: l.first.pathData], [data.canvas.sOrigin+data.canvas.sMin, data.canvas.fOrigin+data.canvas.fMin, data.canvas.sSize, data.canvas.fSize]]; t2 _ mp; mp _ IF l.first.exclude THEN mp.Difference[t1] ELSE mp.Intersection[t1]; ImagerManhattan.Destroy[t1]; ImagerManhattan.Destroy[t2]; }; }; ImagerManhattan.Destroy[data.compositeClipper]; data.clientClipper _ data.clipper; mp _ ImagerManhattan.Copy[data.viewClipper]; ConcatClippers[data.clientClipper]; data.compositeClipper _ mp; }; RETURN [mp] }; lfBrick: ImagerHalftone.DeviceBrick _ ImagerHalftone.MakeSquareBrick[4, 3, 2, 1, 1, 255]; IntensityFromColor: PROC[c: ConstantColor] RETURNS[REAL] ~ { WITH c SELECT FROM c: REF ColorRep[constant][gray] => RETURN[c.f]; c: REF ColorRep[constant][cie] => RETURN[c.Y]; ENDCASE => ERROR Imager.Error[$UnknownSpecialColor]; }; CurrentColor: PROC [data: Data] RETURNS [color: Color] ~ { Runs: PROC [run: PROC[sMin, fMin: INTEGER, fSize: NAT]] ~ { FOR s: INTEGER IN [data.tile.sOrigin..data.tile.sOrigin + data.tile.sSize) DO run[s, data.tile.fOrigin, data.tile.fSize]; ENDLOOP; }; IF data.cachedColor = data.color THEN RETURN [data.cachedColor]; color _ data.cachedColor _ data.color; IF color = Imager.black OR color = Imager.white THEN RETURN; WITH color SELECT FROM constantColor: ConstantColor => { SetTileSamples[data.tileSamples, Real.RoundC[IntensityFromColor[constantColor]*255]]; ImagerHalftone.Halftone[ dest: [sOrigin: data.tile.sOrigin, fOrigin: data.tile.fOrigin, sMin: 0, fMin: 0, sSize: data.tile.sSize, fSize: data.tile.fSize, refRep: data.tile.refRep], runs: Runs, source: data.tileSamples.pa, transformation: ImagerTransform.Rotate[0], deviceBrick: lfBrick ]; }; specialColor: SpecialColor => { WITH specialColor.ref SELECT FROM stipple: REF CARDINAL => data.tile _ ImagerPixelMaps.TileFromStipple[stipple: stipple^, scratch: data.tile.refRep]; atom: ATOM => { SELECT atom FROM $XOR => NULL; ENDCASE => ERROR Imager.Error[$UnknownSpecialColor]; }; ENDCASE => ERROR Imager.Error[$UnknownSpecialColor]; }; sampledColor: SampledColor => NULL; ENDCASE => data.color _ Imager.black; }; ApplyMask: PROC [context: Context, mask: REF, sTranslate, fTranslate: INTEGER _ 0] ~ { data: Data ~ NARROW[context.data]; IF data.noImage = 0 THEN { color: Color ~ CurrentColor[data]; clipper: ManhattanPolygon ~ CompositeClipper[data]; SELECT color FROM Imager.black => ImagerMasks.ApplyConstant[mask, clipper, data.canvas, 1, [null, null], sTranslate, fTranslate]; Imager.white => ImagerMasks.ApplyConstant[mask, clipper, data.canvas, 0, [null, null], sTranslate, fTranslate]; ImagerOps.XOR => ImagerMasks.ApplyConstant[mask, clipper, data.canvas, 1, [xor, null], sTranslate, fTranslate]; ENDCASE => { WITH color SELECT FROM sampledColor: SampledColor => { Runs: PROC [run: PROC[sMin, fMin: INTEGER, fSize: NAT]] ~ { ImagerMasks.GenerateRuns[mask, clipper, run, sTranslate, fTranslate]; }; transform: Transformation _ sampledColor.pa.m.Concat[sampledColor.m].Concat[ViewToDevice[data].FromRec]; invertOutput: BOOLEAN _ FALSE; customBrick: ImagerBrick.Brick _ NARROW[Imager.GetProp[context, $CustomBrick]]; deviceBrick: ImagerHalftone.DeviceBrick; IF customBrick # NIL THEN deviceBrick _ ImagerHalftone.MakeDeviceBrick[customBrick, sampledColor.pa.maxSampleValue] ELSE { IF data.deviceBrickMaxSampleValue # sampledColor.pa.maxSampleValue THEN { data.deviceBrickMaxSampleValue _ sampledColor.pa.maxSampleValue; data.deviceBrick _ ImagerHalftone.MakeSquareBrick[4, 3, 2, 1, 1, sampledColor.pa.maxSampleValue]; }; deviceBrick _ data.deviceBrick; }; SELECT sampledColor.colorOperator FROM $SampledBlack => invertOutput _ TRUE; $Intensity => NULL; ENDCASE => Imager.Error[$UnknownColorModel]; ImagerHalftone.Halftone[data.canvas, Runs, sampledColor.pa, transform, deviceBrick, invertOutput, sampledColor.transparent]; }; ENDCASE => { -- constant (other than black or white) or stipple tile: ImagerPixelMaps.Tile _ data.tile; tile.sOrigin _ tile.sOrigin + SurfaceOriginS[data]-data.viewOrigin.y; tile.fOrigin _ tile.fOrigin + data.viewOrigin.x; ImagerMasks.ApplyTile[mask, clipper, data.canvas, tile, [null, null], sTranslate, fTranslate]; }; }; }; }; MaskStroke: PROC[context: Context, pathProc: PathMapType, pathData: REF] ~ { data: Data ~ NARROW[context.data]; DevicePathFromStroke[data, pathProc, pathData, FALSE]; ApplyMask[context, data.devicePath]; }; MaskStrokeClosed: PROC[context: Context, pathProc: PathMapType, pathData: REF] ~ { data: Data ~ NARROW[context.data]; DevicePathFromStroke[data, pathProc, pathData, TRUE]; ApplyMask[context, data.devicePath]; }; MaskFill: PROC [context: Context, pathProc: PathMapType, pathData: REF] ~ { data: Data ~ NARROW[context.data]; DevicePathFromPath[data, pathProc, pathData]; ApplyMask[context, data.devicePath]; }; specialCaseRectangles: BOOLEAN _ TRUE; MaskRectangle: PROC [context: Context, x, y, w, h: REAL] ~ { data: Data ~ NARROW[context.data]; trans: TransformationRec ~ CompositeT[data]; IF specialCaseRectangles AND trans.a = 0.0 AND trans.e = 0.0 THEN { s0: REAL ~ trans.b * y + trans.c; s1: REAL ~ trans.b * (y+h) + trans.c; f0: REAL ~ trans.d * x + trans.f; f1: REAL ~ trans.d * (x+w) + trans.f; sMin: INTEGER ~ Floor[MAX[MIN[s0, s1], -LAST[INTEGER]/2]]; sMax: INTEGER ~ Ceiling[MIN[MAX[s0, s1], LAST[INTEGER]/2]]; fMin: INTEGER ~ Floor[MAX[MIN[f0, f1], -LAST[INTEGER]/2]]; fMax: INTEGER ~ Ceiling[MIN[MAX[f0, f1], LAST[INTEGER]/2]]; t1: ManhattanPolygon; IF sMax<=sMin OR fMax<=fMin THEN RETURN; t1 _ ImagerManhattan.CreateFromBox[[sMin, fMin, sMax-sMin, fMax-fMin]]; ApplyMask[context, t1, 0, 0]; ImagerManhattan.Destroy[t1]; } ELSE { PathMap: PathMapType ~ { move[[x, y]]; line[[x+w, y]]; line[[x+w, y+h]]; line[[x, y+h]]; }; MaskFill[context, PathMap, NIL]; }; }; MaskRectangleI: PROC [context: Context, x, y, w, h: INTEGER] ~ { MaskRectangle[context, x, y, w, h]; }; MaskPixel: PROC [context: Context, pa: PixelArray] ~ { data: Data ~ NARROW[context.data]; trans: Transformation ~ CompositeT[data].FromRec; mask: REF _ ImagerMasks.FromPixelArray[pa, ImagerTransform.Concat[pa.m, trans]]; ApplyMask[context, mask, 0, 0]; mask _ NIL; }; rasterToRunGroupStorageRatio: INT _ 1; CharLoadInfo: TYPE ~ RECORD[sWidth, fWidth: Scaled.Value, mask: REF]; GetCharMask: PROC [font: FONT, transformation: Transformation, char: CHAR] RETURNS [ImagerManhattan.Polygon] ~ { Runs: PROC [ run: PROC [sMin, fMin: INTEGER, fSize: NAT], repeat: PROC [timesToRepeatScanline: NAT]] ~ { Run: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ { run[sMin: sMin, fMin: fMin, fSize: fSize]; }; font.fontGraphicsClass.maskProc[font, transformation, char, Run]; }; RETURN [ImagerManhattan.CreateFromRuns[Runs]] }; FontCompositeTransform: PROC[data: Data] RETURNS[t: TransformationRec] ~ { font: FONT ~ data.font; r: TransformationRec _ CompositeT[data]; r.c _ r.f _ 0; t _ ImagerTransform.Concat[font.actualTransformation, r.FromRec].Contents; }; fontCache: ImagerFontCache.FontCache _ ImagerFontCache.Create[]; LoadCharData: PROC [self: ImagerFontCache.FontObject, charCode: CARDINAL] RETURNS [charData: REF, memoryCost: INT] ~ { font: FONT ~ NARROW[self.fontAnyData]; char: CHAR ~ 0C+charCode; -- does this bounds check properly? transform: Transformation ~ ImagerTransform.Create[self.r0, self.r1, self.r2, self.r3, self.r4, self.r5]; -- character (to client) to device clientTransform: Transformation ~ font.actualTransformation.Invert.Concat[transform]; loadInfo: REF CharLoadInfo _ NEW[CharLoadInfo]; mask: ImagerManhattan.Polygon _ GetCharMask[font, transform, char]; nBoxes: INT ~ ImagerManhattan.CountBoxes[mask]; bb: DeviceRectangle ~ ImagerManhattan.BoundingBox[mask]; boxesSize: INT _ 7 * nBoxes; rasterSize: INT _ bb.sSize * INT[(bb.fSize+15)/16] + 2; width: Pair _ ImagerTransform.TransformVec[font.fontGraphicsClass.widthVectorProc[font, char] , clientTransform]; IF bb.fSize > 32*Basics.bitsPerWord OR boxesSize*rasterToRunGroupStorageRatio < rasterSize THEN loadInfo.mask _ mask ELSE { pixelMap: PixelMap _ ImagerPixelMaps.Create[0, bb]; ImagerPixelMaps.Clear[pixelMap]; FOR l: LIST OF DeviceRectangle _ mask, l.rest UNTIL l = NIL DO ImagerPixelMaps.Fill[pixelMap, l.first, 1]; ENDLOOP; loadInfo.mask _ ImagerMasks.FromBitmap[pixelMap]; ImagerManhattan.Destroy[mask]; mask _ NIL; }; loadInfo.sWidth _ Scaled.FromReal[width.x]; loadInfo.fWidth _ Scaled.FromReal[width.y]; RETURN[loadInfo, 0]; }; ShowChar: PROC[context: Context, char: CHAR] ~ { text: REF TEXT ~ RefText.ObtainScratch[1]; text[0] _ char; text.length _ 1; ShowText[context, text]; RefText.ReleaseScratch[text]; }; ShowText: PROC[context: Context, text: REF READONLY TEXT, start: NAT _ 0, len: NAT _ NAT.LAST] ~ { data: Data ~ NARROW[context.data]; transform: TransformationRec _ FontCompositeTransform[data]; fontCode: ImagerFontCache.FontCode _ ImagerFontCache.GetFontCode[[ CharDataProc: LoadCharData, r0: transform.a, r1: transform.b, r2: transform.c, r3: transform.d, r4: transform.e, r5: transform.f, fontAnyData: data.font]]; residual: NAT _ text.length; start _ MIN[residual, start]; len _ MIN[residual-start, len]; residual _ len; WHILE residual > 0 DO IF data.correctPass=0 AND ABS[data.cpx]> loadInfo: REF CharLoadInfo ~ NARROW[charData]; sDelta: Scaled.Value _ loadInfo.sWidth; fDelta: Scaled.Value _ loadInfo.fWidth; IF ABS[cp.s.Floor]>=NAT.LAST OR ABS[cp.s.Floor]>=NAT.LAST THEN RETURN[TRUE]; IF data.noImage=0 THEN ApplyMask[context, loadInfo.mask, cp.s.Round, cp.f.Round]; IF charCode = ORD[' ] AND data.amplifySpace # 1.0 THEN { sDelta _ Scaled.FromReal[data.amplifySpace*sDelta.Float]; fDelta _ Scaled.FromReal[data.amplifySpace*fDelta.Float]; }; cp.s _ cp.s.PLUS[sDelta]; cp.f _ cp.f.PLUS[fDelta]; residual _ residual - 1; }; ImagerFontCache.GetTextData[DoChar, fontCache, fontCode, text, start, len]; SetDeviceCP[data, cp]; start _ start + (len-residual); len _ residual; } ELSE { CorrectingDoChar: ImagerFontCache.CharAction ~ { <> loadInfo: REF CharLoadInfo ~ NARROW[charData]; delta: Pair _ TransformDeviceToViewVec[[loadInfo.sWidth, loadInfo.fWidth]]; IF data.noImage=0 THEN { cp: DevicePair _ GetDeviceCP[data]; ApplyMask[context, loadInfo.mask, cp.s.Round, cp.f.Round]; }; IF charCode = ORD[' ] THEN { IF data.amplifySpace # 1.0 THEN { delta.x _ delta.x * data.amplifySpace; delta.y _ delta.y * data.amplifySpace; }; ImagerDefault.CorrectSpaceView[context, delta]; } ELSE ImagerDefault.CorrectMask[context]; data.cpx _ data.cpx + delta.x; data.cpy _ data.cpy + delta.y; residual _ residual - 1; }; ImagerFontCache.GetTextData[CorrectingDoChar, fontCache, fontCode, text, start, len]; }; ENDLOOP; }; ShowRope: PROC[context: Context, rope: ROPE, start: INT _ 0, len: INT _ INT.LAST] ~ { data: Data ~ NARROW[context.data]; transform: TransformationRec _ FontCompositeTransform[data]; fontCode: ImagerFontCache.FontCode _ ImagerFontCache.GetFontCode[[ CharDataProc: LoadCharData, r0: transform.a, r1: transform.b, r2: transform.c, r3: transform.d, r4: transform.e, r5: transform.f, fontAnyData: data.font]]; residual: INT _ Rope.Size[rope]; start _ MIN[residual, MAX[0,start]]; len _ MIN[residual-start, MAX[len, 0]]; residual _ len; WHILE residual > 0 DO IF data.correctPass=0 AND ABS[data.cpx]> loadInfo: REF CharLoadInfo ~ NARROW[charData]; sDelta: Scaled.Value _ loadInfo.sWidth; fDelta: Scaled.Value _ loadInfo.fWidth; IF ABS[cp.s.Floor]>=NAT.LAST OR ABS[cp.s.Floor]>=NAT.LAST THEN RETURN[TRUE]; IF data.noImage=0 THEN ApplyMask[context, loadInfo.mask, Scaled.Round[cp.s], Scaled.Round[cp.f]]; IF charCode = ORD[' ] AND data.amplifySpace # 1.0 THEN { sDelta _ Scaled.FromReal[data.amplifySpace*Scaled.Float[sDelta]]; fDelta _ Scaled.FromReal[data.amplifySpace*Scaled.Float[fDelta]]; }; cp.s _ cp.s.PLUS[sDelta]; cp.f _ cp.f.PLUS[fDelta]; residual _ residual - 1; }; ImagerFontCache.GetRopeData[DoChar, fontCache, fontCode, rope, start, len]; SetDeviceCP[data, cp]; start _ start + (len-residual); len _ residual; } ELSE { CorrectingDoChar: ImagerFontCache.CharAction ~ { <> loadInfo: REF CharLoadInfo ~ NARROW[charData]; delta: Pair _ TransformDeviceToViewVec[[loadInfo.sWidth, loadInfo.fWidth]]; IF data.noImage=0 THEN { cp: DevicePair _ GetDeviceCP[data]; ApplyMask[context, loadInfo.mask, Scaled.Round[cp.s], Scaled.Round[cp.f]]; }; IF charCode = ORD[' ] THEN { IF data.amplifySpace # 1.0 THEN { delta.x _ delta.x * data.amplifySpace; delta.y _ delta.y * data.amplifySpace; }; ImagerDefault.CorrectSpaceView[context, delta]; } ELSE ImagerDefault.CorrectMask[context]; data.cpx _ data.cpx + delta.x; data.cpy _ data.cpy + delta.y; residual _ residual - 1; }; ImagerFontCache.GetRopeData[CorrectingDoChar, fontCache, fontCode, rope, start, len]; }; ENDLOOP; }; ManhattanPolygonFromSurfaceRectangle: PROC [context: Context, box: IntRectangle] RETURNS [LIST OF DeviceRectangle] ~ { data: Data ~ NARROW[context.data]; s0: INTEGER _ SurfaceOriginS[data]-box.y; s1: INTEGER _ SurfaceOriginS[data]-(box.y+box.h); f0: INTEGER _ box.x; f1: INTEGER _ box.x+box.w; RETURN [ImagerManhattan.CreateFromBox[[MIN[s0, s1], MIN[f0, f1], ABS[s1-s0], ABS[f1-f0]]]]; }; SetViewOrigin: PROC [context: Context, viewOrigin: IntPair] ~ { data: Data _ NARROW[context.data]; data.viewOrigin _ viewOrigin; }; GetViewOrigin: PROC [context: Context] RETURNS [viewOrigin: IntPair] ~ { data: Data ~ NARROW[context.data]; RETURN[data.viewOrigin]; }; SetViewBox: PROC [context: Context, viewBox: IntRectangle] ~ { data: Data _ NARROW[context.data]; surfaceBox: IntRectangle _ [ x: viewBox.x+data.viewOrigin.x, y: viewBox.y+data.viewOrigin.y, w: viewBox.w, h: viewBox.h ]; mask: ImagerManhattan.Polygon _ ManhattanPolygonFromSurfaceRectangle[context, surfaceBox]; ImagerManhattan.Destroy[data.compositeClipper]; data.compositeClipper _ NIL; ImagerManhattan.Destroy[data.viewClipper]; data.viewClipper _ mask; }; GetViewBox: PROC [context: Context] RETURNS [IntRectangle] ~ { data: Data ~ NARROW[context.data]; deviceBox: DeviceRectangle _ ImagerManhattan.BoundingBox[data.viewClipper]; surfaceBox: IntRectangle _ [ x: deviceBox.fMin, y: SurfaceOriginS[data]-(deviceBox.sMin+deviceBox.sSize), w: deviceBox.fSize, h: deviceBox.sSize ]; RETURN[[ x: surfaceBox.x-data.viewOrigin.x, y: surfaceBox.y-data.viewOrigin.y, w: surfaceBox.w, h: surfaceBox.h ]]; }; ClipView: PROC [context: Context, clipBox: IntRectangle, exclude: BOOLEAN] ~ { data: Data _ NARROW[context.data]; surfaceBox: IntRectangle _ [ x: clipBox.x+data.viewOrigin.x, y: clipBox.y+data.viewOrigin.y, w: clipBox.w, h: clipBox.h ]; newBox: ImagerManhattan.Polygon _ ManhattanPolygonFromSurfaceRectangle[context, surfaceBox]; old: ImagerManhattan.Polygon _ data.viewClipper; ImagerManhattan.Destroy[data.compositeClipper]; data.compositeClipper _ NIL; data.viewClipper _ IF exclude THEN ImagerManhattan.Difference[old, newBox] ELSE ImagerManhattan.Intersection[old, newBox]; newBox.rest _ old; ImagerManhattan.Destroy[newBox]; }; MoveSurfaceRectangle: PROC [context: Context, source: IntRectangle, dest: IntPair] ~ { data: Data ~ NARROW[context.data]; m: Transformation ~ SurfaceToDevice[data].FromRec; sMinDest, fMinDest, sSize, fSize: INTEGER; shift: Pair _ ImagerTransform.TransformVec[[dest.x-source.x, dest.y-source.y], m]; [[sMinDest, fMinDest, sSize, fSize]] _ ImagerTransform.TransformIntRectangle[[dest.x, dest.y, source.x, source.h], m]; data.canvas.Clip[[sMinDest, fMinDest, sSize, fSize]].Transfer[data.canvas.ShiftMap[Real.RoundI[shift.x], Real.RoundI[shift.y]]]; }; <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<}>> <> <> <> <> <> <> <<};>> <> <> <<};>> <> <> <<};>> <<>> GetSurfaceBounds: PROC [context: Context] RETURNS [IntRectangle] ~ { data: Data ~ NARROW[context.data]; deviceToSurface: Transformation ~ ImagerTransform.Invert[SurfaceToDevice[data].FromRec]; RETURN [ImagerTransform.TransformIntRectangle[[data.canvas.sMin, data.canvas.fMin, data.canvas.sSize, data.canvas.fSize], deviceToSurface]] }; SpecialOp: PROC [context: Context, op: ATOM, data: REF] RETURNS [REF] ~ { SELECT op FROM ENDCASE => ERROR Imager.Error[$UnimplementedSpecialOp]; }; LFDisplayClass: Imager.Class _ NEW [Imager.ClassRep _ [ type: $LFDisplay, DoSave: ImagerDefault.DoSave, DoSaveAll: ImagerDefault.DoSaveAll, SetPriorityImportant: ImagerDefault.SetPriorityImportant, SetFont: ImagerDefault.SetFont, SetColor: ImagerDefault.SetColor, SetNoImage: ImagerDefault.SetNoImage, SetStrokeWidth: ImagerDefault.SetStrokeWidth, SetStrokeEnd: ImagerDefault.SetStrokeEnd, SetAmplifySpace: ImagerDefault.SetAmplifySpace, SetCorrectShrink: ImagerDefault.SetCorrectShrink, ConcatT: ImagerDefault.ConcatT, ScaleT: ImagerDefault.ScaleT, Scale2T: ImagerDefault.Scale2T, RotateT: ImagerDefault.RotateT, TranslateT: ImagerDefault.TranslateT, Move: ImagerDefault.Move, Trans: ImagerDefault.Trans, ShowRope: ShowRope, ShowText: ShowText, ShowChar: ShowChar, SetXY: ImagerDefault.SetXY, SetXYI: ImagerDefault.SetXYI, SetXYRel: ImagerDefault.SetXYRel, SetXYRelI: ImagerDefault.SetXYRelI, SetSampledColor: ImagerDefault.SetSampledColor, SetSampledBlack: ImagerDefault.SetSampledBlack, SetGray: ImagerDefault.SetGray, MaskFill: MaskFill, MaskStroke: MaskStroke, MaskStrokeClosed: MaskStrokeClosed, MaskVector: ImagerDefault.MaskVector, MaskVectorI: ImagerDefault.MaskVectorI, MaskRectangle: MaskRectangle, MaskRectangleI: MaskRectangleI, StartUnderline: ImagerDefault.StartUnderline, MaskUnderline: ImagerDefault.MaskUnderline, MaskUnderlineI: ImagerDefault.MaskUnderlineI, MaskPixel: MaskPixel, ClipOutline: ImagerDefault.ClipOutline, ExcludeOutline: ImagerDefault.ExcludeOutline, ClipRectangle: ImagerDefault.ClipRectangle, ClipRectangleI: ImagerDefault.ClipRectangleI, ExcludeRectangle: ImagerDefault.ExcludeRectangle, ExcludeRectangleI: ImagerDefault.ExcludeRectangleI, CorrectMask: ImagerDefault.CorrectMask, CorrectSpace: ImagerDefault.CorrectSpace, Correct: ImagerDefault.Correct, SetCorrectMeasure: ImagerDefault.SetCorrectMeasure, SetCorrectTolerance: ImagerDefault.SetCorrectTolerance, Space: ImagerDefault.Space, SpaceI: ImagerDefault.SpaceI ]]; <> END.