DIRECTORY Atom, Basics, Font, Imager, ImagerBasic, ImagerBrick, ImagerConic, ImagerDefault, ImagerFontCache, ImagerDisplay, ImagerManhattan, ImagerPixelMaps, ImagerPrivate, ImagerScanConverter, ImagerStroke, ImagerTransform, ImagerMasks, Real, RefText, Scaled; ImagerDisplayImpl: CEDAR MONITOR IMPORTS Atom, Imager, ImagerConic, ImagerDefault, ImagerFontCache, ImagerManhattan, ImagerPixelMaps, ImagerScanConverter, ImagerStroke, ImagerTransform, ImagerMasks, Real, RefText, Scaled EXPORTS ImagerDisplay ~ BEGIN OPEN ImagerDisplay; 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; Name: TYPE ~ ImagerPrivate.Name; ManhattanPolygon: TYPE ~ ImagerManhattan.Polygon; TransformationRec: TYPE ~ ImagerTransform.TransformationRec; DevicePath: TYPE ~ ImagerScanConverter.DevicePath; ClientClipperItem: TYPE ~ ImagerBasic.ClientClipperItem; IntPair: TYPE ~ ImagerBasic.IntPair; IntRectangle: TYPE ~ ImagerBasic.IntRectangle; Pair: TYPE ~ ImagerBasic.Pair; PathMapType: TYPE ~ ImagerBasic.PathMapType; PixelArray: TYPE ~ ImagerBasic.PixelArray; StrokeEnd: TYPE ~ ImagerBasic.StrokeEnd; Transformation: TYPE ~ ImagerBasic.Transformation; Visibility: TYPE ~ ImagerBasic.Visibility; Context: TYPE ~ Imager.Context; State: TYPE ~ ImagerDefault.State; Data: TYPE ~ ImagerDisplay.DisplayData; CompositeT: PROC [data: Data, state: State] RETURNS [TransformationRec] ~ { t: TransformationRec ~ state.T.Contents; IF data.rotate THEN RETURN [[ a: -t.d, d: t.a, b: -t.e, e: t.b, c: -t.f+data.surfaceHeight-data.viewOrigin.y, f: t.c+data.viewOrigin.x ]] ELSE RETURN [[ a: t.a, d: t.d, b: t.b, e: t.e, c: t.c-data.viewOrigin.x, f: t.f+data.viewOrigin.y ]] }; ViewToDevice: PROC [data: Data] RETURNS [TransformationRec] ~ { IF data.rotate THEN RETURN [[ a: 0, d: 1, b: -1, e: 0, c: data.surfaceHeight-data.viewOrigin.y, f: data.viewOrigin.x ]] ELSE RETURN [[ a: 1, d: 0, b: 0, e: 1, c: data.viewOrigin.x, f: data.viewOrigin.y ]] }; SurfaceToDevice: PROC [data: Data] RETURNS [TransformationRec] ~ { IF data.rotate THEN RETURN [[ a: 0, d: 1, b: -1, e: 0, c: data.surfaceHeight, f: 0 ]] ELSE RETURN [[ a: 1, d: 0, b: 0, e: 1, c: 0, f: 0 ]] }; DevicePair: TYPE ~ RECORD [s, f: Scaled.Value]; GetDeviceCP: PROC [data: Data, state: State] RETURNS [DevicePair] ~ { IF data.rotate THEN RETURN [[ s: ScaledFromReal[-state.cpy].PLUS[Scaled.FromInt[data.surfaceHeight-data.viewOrigin.y]], f: ScaledFromReal[state.cpx].PLUS[Scaled.FromInt[data.viewOrigin.x]] ]] ELSE RETURN [[ s: ScaledFromReal[state.cpx].PLUS[Scaled.FromInt[data.viewOrigin.x]], f: ScaledFromReal[state.cpy].PLUS[Scaled.FromInt[data.viewOrigin.y]] ]] }; SetDeviceCP: PROC [data: Data, state: State, cp: DevicePair] ~ { IF data.rotate THEN { state.cpy _ -Scaled.Float[cp.s.MINUS[Scaled.FromInt[data.surfaceHeight-data.viewOrigin.y]]]; state.cpx _ Scaled.Float[cp.f.MINUS[Scaled.FromInt[data.viewOrigin.x]]]; } ELSE { state.cpx _ Scaled.Float[cp.s.MINUS[Scaled.FromInt[data.viewOrigin.x]]]; state.cpy _ Scaled.Float[cp.f.MINUS[Scaled.FromInt[data.viewOrigin.y]]]; } }; displayRegistrationKey: ATOM ~ $ImagerDisplayClass; CreateImagerClass: PUBLIC PROC [displayClass: DisplayClass] RETURNS [class: ImagerPrivate.Class] ~ { Atom.PutProp[displayClass.displayType, displayRegistrationKey, displayClass]; class _ NEW[ImagerPrivate.ClassRep _ imagerClassTemplate^]; class.deviceType _ displayClass.displayType; }; Init: PROC [context: Context, info: REF] ~ { class: ImagerPrivate.Class ~ NARROW[context.class]; displayClass: DisplayClass _ NARROW[Atom.GetProp[class.deviceType, displayRegistrationKey]]; data: Data ~ displayClass.Create[displayClass, info]; context.data _ data; ImagerDefault.InitState[context]; SetViewOrigin[context, [0, 0]]; SetViewBox[context, GetSurfaceBounds[context]]; Reset[context]; }; pixelsPerInch: REAL ~ 72.0; mmPerInch: REAL ~ 25.4; inchesPerMeter: REAL ~ 1000.0/mmPerInch; pixelsPerMeter: REAL _ pixelsPerInch*inchesPerMeter; Reset: PROC [context: Context] ~ { data: Data ~ NARROW[context.data]; state: State ~ context.state; ImagerDefault.Reset[context]; ImagerDefault.Scale2T[context, data.xRes * inchesPerMeter, data.yRes * inchesPerMeter]; state.fieldXMax _ state.mediumXSize _ data.surfaceWidth/(data.xRes * inchesPerMeter); state.fieldYMax _ state.mediumYSize _ data.surfaceHeight/(data.yRes * inchesPerMeter); data.compositeClipper _ NIL; data.cachedColor _ NIL; }; DevicePathFromPathMap: PROC [pathMap: PathMapType, pathData: REF, m: TransformationRec, clipBox: DeviceRectangle] RETURNS [DevicePath] ~ { GenPath: ImagerScanConverter.PathProc ~ { 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]; }; RETURN [ImagerScanConverter.CreatePath[pathProc: GenPath, clipBox: clipBox]]; }; DevicePathFromStroke: PROC [context: Context, pathMap: PathMapType, pathData: REF, strokeWidth: REAL, strokeEnd: StrokeEnd, closed: BOOL, clipBox: DeviceRectangle] RETURNS [devicePath: DevicePath] ~ { data: Data ~ NARROW[context.data]; state: State ~ context.state; devicePath _ ImagerStroke.DevicePathFromStroke[ pathMap: pathMap, pathData: pathData, clientToDevice: CompositeT[data, state].FromRec, width: IF LOOPHOLE[strokeWidth, LONG CARDINAL] # LOOPHOLE[Imager.defaultStrokeWidth, LONG CARDINAL] THEN strokeWidth ELSE state.strokeWidth, strokeEnd: IF strokeEnd # nil THEN strokeEnd ELSE SELECT state.strokeEnd FROM 0 => square, 1 => butt, 2 => round, ENDCASE => nil, closed: closed, clipBox: ImagerManhattan.BoundingBox[data.viewClipper] ]; }; 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]] }; FormCompositeClipper: PROC [context: Context] ~ { data: Data ~ NARROW[context.data]; state: State ~ context.state; mp: ManhattanPolygon _ data.compositeClipper; IF mp = NIL OR data.clientClipper # state.clipper THEN { clipBox: DeviceRectangle _ ImagerManhattan.BoundingBox[data.viewClipper]; ConcatClippers: PROC [l: LIST OF ClientClipperItem] ~ { IF l#NIL THEN { t1, t2: ManhattanPolygon; ConcatClippers[l.rest]; t1 _ ImagerScanConverter.ConvertToManhattanPolygon[ devicePath: DevicePathFromPathMap[ pathMap: l.first.pathMap, pathData: l.first.pathData, m: ViewToDevice[data], clipBox: clipBox ], clipBox: clipBox ]; 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 _ state.clipper; mp _ ImagerManhattan.Copy[data.viewClipper]; ConcatClippers[data.clientClipper]; data.compositeClipper _ mp; }; }; ValidateClipper: PROC [context: Context, data: Data] ~ INLINE { IF data.compositeClipper = NIL OR data.clientClipper # context.state.clipper THEN FormCompositeClipper[context]; }; MaskStroke: PROC [context: Context, pathMap: PathMapType, pathData: REF, strokeWidth: REAL, strokeEnd: StrokeEnd] ~ { data: Data ~ NARROW[context.data]; devicePath: DevicePath _ DevicePathFromStroke[context, pathMap, pathData, strokeWidth, strokeEnd, FALSE, ImagerManhattan.BoundingBox[data.viewClipper]]; ValidateClipper[context, data]; data.displayClass.ApplyMask[data, context.state.color, devicePath, 0, 0]; }; MaskStrokeClosed: PROC [context: Context, pathMap: PathMapType, pathData: REF, strokeWidth: REAL] ~ { data: Data ~ NARROW[context.data]; devicePath: DevicePath _ DevicePathFromStroke[context, pathMap, pathData, strokeWidth, nil, TRUE, ImagerManhattan.BoundingBox[data.viewClipper]]; ValidateClipper[context, data]; data.displayClass.ApplyMask[data, context.state.color, devicePath, 0, 0]; }; MaskFill: PROC [context: Context, pathMap: PathMapType, pathData: REF] ~ { data: Data ~ NARROW[context.data]; devicePath: DevicePath _ DevicePathFromPathMap[pathMap, pathData, CompositeT[data, context.state], ImagerManhattan.BoundingBox[data.viewClipper]]; ValidateClipper[context, data]; data.displayClass.ApplyMask[data, context.state.color, devicePath, 0, 0]; }; specialCaseRectangles: BOOLEAN _ TRUE; Round: PROC [r: REAL] RETURNS [INTEGER] ~ { IF r > LAST[INTEGER]/2 THEN RETURN [LAST[INTEGER]/2]; IF r < FIRST[INTEGER]/2 THEN RETURN [FIRST[INTEGER]/2]; RETURN [Real.RoundI[r]]; }; MaskRectangle: PROC [context: Context, x, y, w, h: REAL] ~ { data: Data ~ NARROW[context.data]; trans: TransformationRec ~ CompositeT[data, context.state]; IF specialCaseRectangles AND trans.a = 0.0 AND trans.e = 0.0 THEN { s0: INTEGER ~ Round[trans.b * y + trans.c]; s1: INTEGER ~ Round[trans.b * (y+h) + trans.c]; f0: INTEGER ~ Round[trans.d * x + trans.f]; f1: INTEGER ~ Round[trans.d * (x+w) + trans.f]; sMin: INTEGER ~ MIN[s0, s1]; sMax: INTEGER ~ MAX[s0, s1]; fMin: INTEGER ~ MIN[f0, f1]; fMax: INTEGER ~ MAX[f0, f1]; t1: ManhattanPolygon; IF sMax<=sMin OR fMax<=fMin THEN RETURN; t1 _ ImagerManhattan.CreateFromBox[[sMin, fMin, sMax-sMin, fMax-fMin]]; ValidateClipper[context, data]; data.displayClass.ApplyMask[data, context.state.color, 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]; }; }; IntegerMaskRectangle: 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, context.state].FromRec; mask: REF _ ImagerMasks.FromPixelArray[pa, ImagerTransform.Concat[pa.m, trans]]; ValidateClipper[context, data]; data.displayClass.ApplyMask[data, context.state.color, 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 [context: Context, font: FONT] RETURNS [t: TransformationRec] ~ { data: Data ~ NARROW[context.data]; state: State ~ context.state; r: TransformationRec _ CompositeT[data, state]; 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, font: FONT] ~ { text: REF TEXT _ RefText.ObtainScratch[1]; text[0] _ char; text.length _ 1; ShowCharacters[context, text, font, 0, 1]; RefText.ReleaseScratch[text]; }; ShowCharacters: PROC [ context: Context, characters: REF, -- may be a ROPE or a REF TEXT font: FONT, start: INT _ 0, length: INT _ LAST[INT] ] ~ { data: Data ~ NARROW[context.data]; TransformDeviceToViewVec: PROC [d: DevicePair] RETURNS [v: Pair] ~ { v _ IF data.rotate THEN [x: Scaled.Float[d.f], y: -Scaled.Float[d.s]] ELSE [x: Scaled.Float[d.s], y: Scaled.Float[d.f]] }; state: State ~ context.state; showVec: FONT _ IF font = NIL THEN NARROW[state.showVec] ELSE font; transform: TransformationRec _ FontCompositeTransform[context, showVec]; 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, fontScalarData: 0, -- unused fontAnyData: showVec]]; noImage: BOOLEAN ~ state.noImage # 0; ValidateClipper[context, data]; IF state.correctPass = 0 THEN { DoChar: PROC [charCode: CARDINAL, charData: REF] ~ { loadInfo: REF CharLoadInfo ~ NARROW[charData]; sDelta: Scaled.Value _ loadInfo.sWidth; fDelta: Scaled.Value _ loadInfo.fWidth; IF NOT noImage THEN data.displayClass.ApplyMask[data, state.color, loadInfo.mask, Scaled.Round[cp.s], Scaled.Round[cp.f]]; IF charCode = ORD[' ] AND state.amplifySpace # 1.0 THEN { sDelta _ Scaled.FromReal[state.amplifySpace*Scaled.Float[sDelta]]; fDelta _ Scaled.FromReal[state.amplifySpace*Scaled.Float[fDelta]]; }; cp.s _ cp.s.PLUS[sDelta]; cp.f _ cp.f.PLUS[fDelta]; }; cp: DevicePair _ GetDeviceCP[data, state]; ImagerFontCache.GetStringData[DoChar, fontCache, fontCode, characters, start, length]; SetDeviceCP[data, state, cp]; } ELSE { CorrectingDoChar: PROC [charCode: CARDINAL, charData: REF] ~ { loadInfo: REF CharLoadInfo ~ NARROW[charData]; delta: Pair _ TransformDeviceToViewVec[[loadInfo.sWidth, loadInfo.fWidth]]; IF NOT noImage THEN { cp: DevicePair _ GetDeviceCP[data, state]; data.displayClass.ApplyMask[data, state.color, loadInfo.mask, Scaled.Round[cp.s], Scaled.Round[cp.f]]; }; IF charCode = ORD[' ] THEN { IF state.amplifySpace # 1.0 THEN { delta.x _ delta.x * state.amplifySpace; delta.y _ delta.y * state.amplifySpace; }; ImagerDefault.CorrectSpaceView[context, delta]; } ELSE { ImagerDefault.CorrectMask[context]; }; state.cpx _ state.cpx + delta.x; state.cpy _ state.cpy + delta.y; }; ImagerFontCache.GetStringData[CorrectingDoChar, fontCache, fontCode, characters, start, length]; }; }; ManhattanPolygonFromSurfaceRectangle: PROC [context: Context, box: IntRectangle] RETURNS [LIST OF DeviceRectangle] ~ { data: Data ~ NARROW[context.data]; IF data.rotate THEN { s0: INTEGER _ data.surfaceHeight-box.y; s1: INTEGER _ data.surfaceHeight-(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]]]]; } ELSE RETURN [ImagerManhattan.CreateFromBox[[MIN[box.x, box.x+box.w], MIN[box.y, box.y+box.h], ABS[box.w], ABS[box.w]]]]; }; 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 ~ IF data.rotate THEN [ x: deviceBox.fMin, y: data.surfaceHeight-(deviceBox.sMin+deviceBox.sSize), w: deviceBox.fSize, h: deviceBox.sSize ] ELSE [ x: deviceBox.sMin, y: deviceBox.fMin, w: deviceBox.sSize, h: deviceBox.fSize ]; 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, sMinSource, fMinSource, sSize, fSize: INTEGER; DoMove: PROC ~ { IF data.displayClass.viewUnitsPerPixel # 1 THEN { sMinDest _ sMinDest / data.displayClass.viewUnitsPerPixel; fMinDest _ fMinDest / data.displayClass.viewUnitsPerPixel; sMinSource _ sMinSource / data.displayClass.viewUnitsPerPixel; fMinSource _ fMinSource / data.displayClass.viewUnitsPerPixel; sSize _ sSize / data.displayClass.viewUnitsPerPixel; fSize _ fSize / data.displayClass.viewUnitsPerPixel; }; FOR i: NAT IN [0..data.numberOfSeparations) DO data[i].Clip[[sMinDest, fMinDest, sSize, fSize]].Transfer[data[i].ShiftMap[sMinSource-sMinDest, fMinSource-fMinDest]]; ENDLOOP; }; [[sMinDest, fMinDest, sSize, fSize]] _ ImagerTransform.TransformIntRectangle[[dest.x, dest.y, source.w, source.h], m]; [[sMinSource, fMinSource, sSize, fSize]] _ ImagerTransform.TransformIntRectangle[[source.x, source.y, source.w, source.h], m]; data.displayClass.DoUnderLock[data, DoMove, [MIN[sMinDest, sMinSource], MIN[fMinDest, fMinSource], sSize+ABS[sMinSource-sMinDest], fSize+ABS[fMinSource-fMinDest]]]; }; TestRectangle: PROC [context: Context, x, y, w, h: REAL] RETURNS [visibility: Visibility] ~ { data: Data ~ NARROW[context.data]; state: State ~ context.state; trans: TransformationRec ~ CompositeT[data, state]; manhattanPolygon: ImagerManhattan.Polygon _ NIL; IF specialCaseRectangles AND trans.a = 0.0 AND trans.e = 0.0 THEN { s0: INTEGER ~ Round[trans.b * y + trans.c]; s1: INTEGER ~ Round[trans.b * (y+h) + trans.c]; f0: INTEGER ~ Round[trans.d * x + trans.f]; f1: INTEGER ~ Round[trans.d * (x+w) + trans.f]; sMin: INTEGER ~ MIN[s0, s1]; sMax: INTEGER ~ MAX[s0, s1]; fMin: INTEGER ~ MIN[f0, f1]; fMax: INTEGER ~ MAX[f0, f1]; IF sMax<=sMin OR fMax<=fMin THEN RETURN [invisible]; manhattanPolygon _ ImagerManhattan.CreateFromBox[[sMin, fMin, sMax-sMin, fMax-fMin]]; } ELSE { PathMap: PathMapType ~ { move[[x, y]]; line[[x+w, y]]; line[[x+w, y+h]]; line[[x, y+h]]; }; bb: DeviceRectangle _ ImagerManhattan.BoundingBox[data.viewClipper]; devicePath: DevicePath _ DevicePathFromPathMap[PathMap, NIL, CompositeT[data, context.state], bb]; manhattanPolygon _ ImagerScanConverter.ConvertToManhattanPolygon[devicePath, bb]; }; ValidateClipper[context, data]; visibility _ ImagerManhattan.IsVisible[manhattanPolygon, data.compositeClipper]; ImagerManhattan.Destroy[manhattanPolygon]; }; GetSurfaceBounds: PROC [context: Context] RETURNS [IntRectangle] ~ { data: Data ~ NARROW[context.data]; RETURN [[0, 0, data.surfaceWidth, data.surfaceHeight]]; }; SpecialOp: PROC [context: Context, op: ATOM, data: REF] RETURNS [REF] ~ { SELECT op FROM ENDCASE => ERROR Imager.Error[$UnimplementedSpecialOp]; }; imagerClassTemplate: ImagerPrivate.Class _ NEW [ImagerPrivate.ClassRep _ [ deviceType: NIL, Init: Init, ISet: ImagerDefault.ISet, ISetReal: ImagerDefault.ISetReal, ISetInt: ImagerDefault.ISetInt, SetSampledColor: ImagerDefault.SetSampledColor, SetSampledBlack: ImagerDefault.SetSampledBlack, DoSave: ImagerDefault.DoSave, DoSaveAll: ImagerDefault.DoSaveAll, ConcatT: ImagerDefault.ConcatT, TranslateT: ImagerDefault.TranslateT, RotateT: ImagerDefault.RotateT, ScaleT: ImagerDefault.ScaleT, Scale2T: ImagerDefault.Scale2T, Move: ImagerDefault.Move, Trans: ImagerDefault.Trans, SetXY: ImagerDefault.SetXY, IntegerSetXY: ImagerDefault.IntegerSetXY, SetXYRel: ImagerDefault.SetXYRel, IntegerSetXYRel: ImagerDefault.IntegerSetXYRel, GetCP: ImagerDefault.GetCP, GetCPRounded: ImagerDefault.GetCPRounded, MaskFill: MaskFill, MaskStroke: MaskStroke, MaskStrokeClosed: MaskStrokeClosed, MaskVector: ImagerDefault.MaskVector, IntegerMaskVector: ImagerDefault.IntegerMaskVector, MaskRectangle: MaskRectangle, IntegerMaskRectangle: IntegerMaskRectangle, StartUnderline: ImagerDefault.StartUnderline, MaskUnderline: ImagerDefault.MaskUnderline, IntegerMaskUnderline: ImagerDefault.IntegerMaskUnderline, MaskPixel: MaskPixel, ClipOutline: ImagerDefault.ClipOutline, ExcludeOutline: ImagerDefault.ExcludeOutline, ClipRectangle: ImagerDefault.ClipRectangle, ExcludeRectangle: ImagerDefault.ExcludeRectangle, IntegerClipRectangle: ImagerDefault.IntegerClipRectangle, IntegerExcludeRectangle: ImagerDefault.IntegerExcludeRectangle, ShowChar: ShowChar, ShowCharacters: ShowCharacters, CorrectMask: ImagerDefault.CorrectMask, CorrectSpace: ImagerDefault.CorrectSpace, SetCorrectMeasure: ImagerDefault.SetCorrectMeasure, SetCorrectTolerance: ImagerDefault.SetCorrectTolerance, Space: ImagerDefault.Space, IntegerSpace: ImagerDefault.IntegerSpace, Correct: ImagerDefault.Correct, Reset: Reset, SetViewOrigin: SetViewOrigin, GetViewOrigin: GetViewOrigin, SetViewBox: SetViewBox, GetViewBox: GetViewBox, ClipView: ClipView, MoveSurfaceRectangle: MoveSurfaceRectangle, TestRectangle: TestRectangle, GetSurfaceBounds: GetSurfaceBounds, SpecialOp: SpecialOp ]]; END. ,ImagerDisplayImpl.mesa Michael Plass, March 19, 1984 5:16:59 pm PST concatenates T with the current view-to-device transformation move: PROC [s, f: REAL], line: PROC [s, f: REAL], curve: PROC [s1, f1, s2, f2, s3, f3: REAL] Transforms (x, y) to (s, f) Because of an apparent bug in Real.FScale. Êm˜Jšœ™J™,J˜šÏk ˜ J˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ J˜ J˜ J˜Jšœ˜J˜J˜Jšœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ˜J˜ Jšœ˜Jšœ˜Jšœ˜—J˜Jšœœ˜ Jšœ´˜»Jšœ˜šœœœ˜J˜—šœ œœ˜JšœSœ˜\J˜—šœ˜J˜—šÏnœœœ7œ˜VJ˜—Jšœœœ˜Jšœ œ˜*Jšœœ˜ Jšœœ˜1Jšœœ%˜Jšœ+˜+Jš˜—Jšœ1˜1Jšœ&œ˜*Jšœ˜—Jšœ+˜+Jšœ+˜+Jšœ˜Jšœ˜J˜—šžœœœœ˜=Jšœœœ˜*Jšœ˜Jšœ˜Jšœ*˜*Jšœ˜Jšœ˜J˜—šžœœ˜Jšœ˜Jšœ œŸ˜/Jšœœ˜ Jšœœ˜Jšœœœœ˜Jšœ˜Jšœ œ˜"šžœœœ˜Dšœœ œ.˜EJšœ-˜1—Jšœ˜—Jšœ˜Jš œ œœœœœœ˜CJšœH˜HšœB˜BJšœ˜Jšœe˜eJšœŸ ˜Jšœ˜—Jšœ œ˜%Jšœ˜šœœ˜šžœœ œ œ˜4Jšœ œœ ˜.Jšœ'˜'Jšœ'˜'šœœ ˜Jšœf˜f—šœ œœœ˜9JšœB˜BJšœB˜BJšœ˜—Jšœ œ ˜Jšœ œ ˜J˜—Jšœ*˜*J˜VJšœ˜Jšœ˜—šœ˜šžœœ œ œ˜>Jšœ œœ ˜.JšœK˜Kšœœ œ˜Jšœ*˜*Jšœf˜fJ˜—šœ œœ˜šœœ˜"Jšœ'˜'Jšœ'˜'J˜—Jšœ/˜/J˜—šœ˜Jšœ#˜#Jšœ˜—Jšœ ˜ Jšœ ˜ J˜—Jšœ`˜`J˜—Jšœ˜J˜—š ž$œœ'œœœ˜vJšœ œ˜"˜Jšœœ˜'Jšœœ$˜/Jšœœ ˜Jšœœ˜Jš œ!œ œ œ œ ˜[J˜—Jš œœ!œœœ œ ˜xJšœ˜J˜—šž œœ,˜?Jšœ œ˜"Jšœ˜Jšœ˜J˜—šž œœœ˜HJšœ œ˜"Jšœ˜Jšœ˜J˜—šž œœ.˜>Jšœ œ˜"šœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜—JšœZ˜ZJšœ/˜/Jšœœ˜Jšœ*˜*Jšœ˜Jšœ˜J˜—šž œœœ˜>Jšœ œ˜"JšœK˜Kšœ˜šœ œ˜Jšœ˜Jšœ7˜7Jšœ˜Jšœ˜J˜—šœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜——šœ˜Jšœ"˜"Jšœ"˜"Jšœ˜Jšœ˜Jšœ˜—Jšœ˜J˜—šžœœ4œ˜NJšœ œ˜"šœ˜Jšœ˜Jšœ˜Jšœ ˜ Jšœ ˜ Jšœ˜—Jšœ\˜\Jšœ0˜0Jšœ/˜/Jšœœ˜šœ˜Jšœ œ(˜7Jšœ+˜/—Jšœ˜Jšœ ˜ Jšœ˜J˜—šžœœ<˜VJšœ œ˜"Jšœ2˜2Jšœ:œ˜Bšžœœ˜šœ)œ˜1Jšœ:˜:Jšœ:˜:Jšœ>˜>Jšœ>˜>Jšœ4˜4Jšœ4˜4J˜—šœœœ˜.Jšœv˜vJš˜—J˜—Jšœv˜vJšœ~˜~Jš œ-œœœœ˜¤Jšœ˜J˜—šž œœ œœ˜]Jšœ œ˜"Jšœ˜Jšœ3˜3Jšœ,œ˜0šœœœœ˜CJšœœ ˜+Jšœœ$˜/Jšœœ ˜+Jšœœ$˜/Jšœœœ ˜Jšœœœ ˜Jšœœœ ˜Jšœœœ ˜Jšœ œ œœ ˜4JšœU˜UJšœ˜—šœ˜šžœ˜J˜ J˜J˜J˜Jšœ˜—JšœD˜DJšœ8œ'˜bJšœQ˜QJšœ˜—Jšœ˜JšœP˜PJšœ*˜*Jšœ˜J˜—šžœœœ˜DJšœ œ˜"Jšœ1˜7Jšœ˜J˜—š ž œœœœœœ˜Išœ˜Jšœœ'˜7—Jšœ˜J˜—šœ+œ˜JJšœ˜Jšœ ˜ Jšœ˜Jšœ!˜!Jšœ˜Jšœ/˜/Jšœ/˜/Jšœ˜Jšœ#˜#Jšœ˜Jšœ%˜%Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ)˜)Jšœ!˜!Jšœ/˜/Jšœ˜Jšœ)˜)Jšœ˜Jšœ˜Jšœ#˜#Jšœ%˜%Jšœ3˜3Jšœ˜Jšœ+˜+Jšœ-˜-Jšœ+˜+Jšœ9˜9Jšœ˜Jšœ'˜'Jšœ-˜-Jšœ+˜+Jšœ1˜1Jšœ9˜9Jšœ?˜?Jšœ˜Jšœ˜Jšœ'˜'Jšœ)˜)Jšœ3˜3Jšœ7˜7Jšœ˜Jšœ)˜)Jšœ˜Jšœ ˜ Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ˜Jšœ+˜+Jšœ˜Jšœ#˜#Jšœ˜Jšœ˜J˜—Jšœ˜—…—Zs«