DIRECTORY Real USING [FixI, Float, RoundLI], Imager USING [Context, Transformation, Clipper], ImagerBasic USING [Path, Pair, IntPair, IntRectangle, Rectangle, Visibility, Transformation], ImagerDisplay USING [ImagingSpace, ContextData, SetViewerTransform], ImagerTransform USING [Transform, TransformRectangle, TransformIntRectangle, Invert], ImagerMasks USING [Mask, Create, IsVisible, Difference, And, InlineBox], ImagerScanConverter USING [ConvertToRuns, DevicePath, CreatePath, DeviceRectangle]; ImagerDisplayClipperImpl: CEDAR PROGRAM IMPORTS ImagerTransform, Real, ImagerDisplay, ImagerMasks, ImagerScanConverter EXPORTS Imager, ImagerDisplay ~ BEGIN OPEN ImagerBasic; Context: TYPE ~ Imager.Context; Transformation: TYPE ~ Imager.Transformation; ImagingSpace: TYPE ~ ImagerDisplay.ImagingSpace; Mask: TYPE ~ ImagerMasks.Mask; DisplayContext: TYPE ~ ImagerDisplay.ContextData; NonRectangularClipper: PUBLIC SIGNAL ~ CODE; NotImplementedYet: PUBLIC SIGNAL ~ CODE; GetClipper: PUBLIC PROC [context: Context] RETURNS [Imager.Clipper] ~ { displayContext: DisplayContext = NARROW[context.data]; clipper: REF Mask _ NEW[ Mask _ displayContext.clientClipper ]; RETURN [ clipper ]; }; SetClipper: PUBLIC PROC [context: Context, clipper: Imager.Clipper] ~ { displayContext: DisplayContext = NARROW[context.data]; mask: REF Mask = NARROW[clipper]; displayContext.clientClipper _ mask^; ValidateCompositeClipper[displayContext]; }; ClipPath: PUBLIC PROC [context: Context, outline: Path, exclude: BOOLEAN _ FALSE] ~ { displayContext: DisplayContext = NARROW[context.data]; displayContext.clientClipper _ ClipMask[ displayContext.clientClipper, MaskFromPath[displayContext, outline], exclude ]; ValidateCompositeClipper[displayContext]; }; ClipRectangle: PUBLIC PROC [context: Context, outline: Rectangle, exclude: BOOLEAN _ FALSE] ~ { displayContext: DisplayContext = NARROW[context.data]; IF NOT EasyClipper[displayContext, exclude] THEN displayContext.clientClipper _ ClipMask[ displayContext.clientClipper, MaskFromRectangle[displayContext, outline], exclude ] ELSE { -- easy case, transform the outline rectangle and clip it to clip rectangle OPEN displayContext.clientClipper; sMax, fMax: INTEGER; outline _ ImagerTransform.TransformRectangle[outline, displayContext.transform]; fMin _ MAX[fMin, Real.FixI[outline.x]]; sMin _ MAX[sMin, Real.FixI[outline.y]]; fMax _ MIN[fMin + fSize, Real.FixI[outline.x + outline.w]]; sMax _ MIN[sMin + sSize, Real.FixI[outline.y + outline.h]]; fSize _ IF fMax > fMin THEN fMax - fMin + 1 ELSE 0; sSize _ IF sMax > sMin THEN sMax - sMin + 1 ELSE 0; }; ValidateCompositeClipper[displayContext]; }; TestRectangle: PUBLIC PROC [context: Context, area: Rectangle] RETURNS [Visibility] ~ { displayContext: DisplayContext = NARROW[context.data]; IF NOT EasyClipper[displayContext, FALSE] THEN RETURN[ ImagerMasks.IsVisible[ MaskFromRectangle[displayContext, area], displayContext.clipper ] ] ELSE { OPEN displayContext.clipper; -- easy case, real rectangle, clip rectangle area _ ImagerTransform.TransformRectangle[area, displayContext.transform]; IF (fMin + fSize <= Real.FixI[area.x]) OR (fMin >= Real.FixI[area.x + area.w]) OR (sMin + sSize <= Real.FixI[area.y]) OR (sMin >= Real.FixI[area.y + area.h]) THEN RETURN[ invisible ] ELSE IF (fMin + fSize <= Real.FixI[area.x + area.w]) AND (fMin >= Real.FixI[area.x]) AND (sMin + sSize <= Real.FixI[area.y + area.h]) AND (sMin >= Real.FixI[area.y]) THEN RETURN[ visible ] ELSE RETURN[ partlyVisible ]; }; }; ClipIntRectangle: PUBLIC PROC [context: Context, outline: IntRectangle, exclude: BOOLEAN _ FALSE] ~ { displayContext: DisplayContext = NARROW[context.data]; IF NOT EasyClipper[displayContext, exclude] THEN ClipRectangle[context, FloatRect[outline], exclude] ELSE { -- easy case, transform the outline rectangle and clip it to clip rectangle OPEN displayContext.clientClipper; sMax, fMax: INTEGER; outline _ ImagerTransform.TransformIntRectangle[outline,displayContext.clientTransform]; fMin _ MAX[fMin, outline.x]; sMin _ MAX[sMin, outline.y]; fMax _ MIN[fMin + fSize, outline.x + outline.w]; sMax _ MIN[sMin + sSize, outline.y + outline.h]; fSize _ IF fMax > fMin THEN fMax - fMin + 1 ELSE 0; sSize _ IF sMax > sMin THEN sMax - sMin + 1 ELSE 0; }; ValidateCompositeClipper[displayContext]; }; TestIntRectangle: PUBLIC PROC [context: Context, area: IntRectangle] RETURNS [Visibility] ~ { displayContext: DisplayContext = NARROW[context.data]; IF NOT EasyClipper[displayContext, FALSE] THEN RETURN[ TestRectangle[context, FloatRect[area]] ] ELSE { OPEN displayContext.clipper; -- easy case, int rectangle, clip rectangle area _ ImagerTransform.TransformIntRectangle[area, displayContext.clientTransform]; IF (fMin + fSize <= area.x) OR (fMin >= area.x + area.w) OR (sMin + sSize <= area.y) OR (sMin >= area.y + area.h) THEN RETURN[ invisible ] ELSE IF (fMin + fSize <= area.x + area.w) AND (fMin >= area.x) AND (sMin + sSize <= area.y + area.h) AND (sMin >= area.y) THEN RETURN[ visible ] ELSE RETURN[ partlyVisible ]; }; }; DoWithoutClipping: PUBLIC PROC [context: Context, bounds: IntRectangle, callBack: PROC[Context]] ~ { displayContext: DisplayContext = NARROW[context.data]; IF TestIntRectangle[context, bounds] = visible THEN displayContext.noClip _ TRUE; callBack[ context ]; displayContext.noClip _ FALSE; }; SetView: PUBLIC PROC [context: Context, box: IntRectangle, halftoneOrigin: IntPair _ [0, 0]] ~ { SetViewerClipper[context, box]; ImagerDisplay.SetViewerTransform[context, [1., 0., box.x, 0., 1., box.y, identity]]; }; ClipView: PUBLIC PROC [context: Context, box: IntRectangle, exclude: BOOLEAN] ~ { displayContext: DisplayContext = NARROW[context.data]; IF exclude = FALSE THEN ClipViewerClipper[context, box] ELSE displayContext.viewerClipper _ ClipMask[ displayContext.clientClipper, MaskFromRectangle[ displayContext, FloatRect[box] ], exclude ]; }; GetSurfaceBounds: PUBLIC PROC [context: Context] RETURNS [IntRectangle] ~ { displayContext: DisplayContext = NARROW[context.data]; { OPEN displayContext.deviceClipper; RETURN [ [fMin, sMin, fSize, sSize] ]; }; }; GetViewBounds: PUBLIC PROC [context: Context] RETURNS [IntRectangle] ~ { displayContext: DisplayContext = NARROW[context.data]; { OPEN displayContext.viewerClipper; RETURN [ ImagerTransform.TransformIntRectangle[ [fMin, sMin, fSize, sSize], ImagerTransform.Invert[ displayContext.deviceTransform ] ] ]; }; }; SetViewerClipper: PUBLIC PROC [context: Context, outline: IntRectangle] ~ { displayContext: DisplayContext = NARROW[context.data]; outline _ ImagerTransform.TransformIntRectangle[outline, displayContext.deviceTransform]; displayContext.viewerClipper _ [outline.y, outline.x, outline.h, outline.w, NIL]; ValidateCompositeClipper[displayContext]; }; ClipViewerClipper: PUBLIC PROC [context: Context, outline: IntRectangle] ~ { displayContext: DisplayContext = NARROW[context.data]; outline _ ImagerTransform.TransformIntRectangle[outline, displayContext.deviceTransform]; { OPEN displayContext.viewerClipper; sMax, fMax: INTEGER; fMin _ MAX[fMin, outline.x]; sMin _ MAX[sMin, outline.y]; fMax _ MIN[fMin + fSize, outline.x + outline.w]; sMax _ MIN[sMin + sSize, outline.y + outline.h]; fSize _ IF fMax > fMin THEN fMax - fMin + 1 ELSE 0; sSize _ IF sMax > sMin THEN sMax - sMin + 1 ELSE 0; }; ValidateCompositeClipper[displayContext]; }; SetDeviceClipper: PUBLIC PROC [context: Context, outline: IntRectangle] ~ { displayContext: DisplayContext = NARROW[context.data]; displayContext.deviceClipper _ [outline.y, outline.x, outline.h, outline.w, NIL]; ValidateCompositeClipper[displayContext]; }; FloatRect: PROC [rect: IntRectangle] RETURNS [Rectangle] ~ INLINE { RETURN[ [ Real.Float[rect.x], Real.Float[rect.y], Real.Float[rect.w], Real.Float[rect.h] ] ]; }; EasyClipper: PROC [displayContext: DisplayContext, exclude: BOOLEAN] RETURNS [BOOLEAN] ~ INLINE { RETURN [ IF displayContext.clientTransform.b # 0. -- Rotation or Skew? OR displayContext.clientTransform.d # 0. OR exclude -- Exclusion? OR displayContext.clientClipper.refRep # NIL THEN FALSE ELSE TRUE ]; }; ClipMask: PROC [clpr, new: Mask, exclude: BOOLEAN] RETURNS [Mask] ~ { IF clpr.refRep = NIL AND new.refRep = NIL AND exclude = FALSE THEN { fMax, sMax, fMin, sMin, fSize, sSize: INTEGER; fMin _ MAX[clpr.fMin, new.fMin]; sMin _ MAX[clpr.sMin, new.sMin]; fMax _ MIN[clpr.fMin + clpr.fSize, new.fMin + new.fSize]; sMax _ MIN[clpr.sMin + clpr.sSize, new.sMin + new.sSize]; fSize _ IF fMax > clpr.fMin THEN fMax - clpr.fMin ELSE 0; sSize _ IF sMax > clpr.sMin THEN sMax - clpr.sMin ELSE 0; RETURN [ [sMin, fMin, sSize, fSize, NIL] ]; } ELSE IF exclude THEN RETURN[ ImagerMasks.Difference[clpr, new] ] ELSE RETURN[ ImagerMasks.And[clpr, new] ]; }; BoxFromMask: PROC [mask: Mask] RETURNS [ ImagerScanConverter.DeviceRectangle ] ~ { RETURN [ [mask.sMin, mask.fMin, mask.sSize, mask.fSize] ]; }; MaskFromPath: PROC [displayContext: DisplayContext, area: Path] RETURNS [Mask] ~ { GenPath: PROC [move: PROC[s, f: REAL], line: PROC[s, f: REAL], curve: PROC[s1, f1, s2, f2, s3, f3: REAL]] = { m: ImagerBasic.Transformation _ displayContext.transform; Xform: PROC [p: Pair] RETURNS [Pair] ~ {RETURN[[ m.d * p.x + m.e * p.y + m.f, m.a * p.x + m.b * p.y + m.c ]]}; Xmove: PROC [p: Pair] ~ { pp: Pair ~ Xform[p]; move[pp.y, pp.x] }; Xline: PROC [p: Pair] ~ { pp: Pair ~ Xform[p]; line[pp.y, pp.x] }; Xcurve: PROC [p1, p2, p3: Pair] ~ { pp1: Pair ~ Xform[p1]; pp2: Pair ~ Xform[p2]; pp3: Pair ~ Xform[p3]; curve[pp1.x, pp1.y, pp2.x, pp2.y, pp3.x, pp3.y] }; area.generateProc[area, Xmove, Xline, Xcurve]; }; Runs: PROC[run: PROC[s, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] ~ { RunFromScanConverter: PROC [sMin, fMin: INTEGER, fSize: NAT] = { run[s: sMin, fMin: fMin, fSize: fSize]; }; ImagerScanConverter.ConvertToRuns[ devicePath: devicePath, runProc: RunFromScanConverter, clipBox: BoxFromMask[displayContext.deviceClipper] ]; }; devicePath: ImagerScanConverter.DevicePath _ ImagerScanConverter.CreatePath[ pathProc: GenPath, clipBox: BoxFromMask[displayContext.deviceClipper] ]; RETURN[ ImagerMasks.Create[Runs] ]; }; MaskFromRectangle: PROC [displayContext: DisplayContext, area: Rectangle] RETURNS [Mask] = { GenPath: PROC [move: PROC[s, f: REAL], line: PROC[s, f: REAL], curve: PROC[s1, f1, s2, f2, s3, f3: REAL]] = { m: ImagerBasic.Transformation _ displayContext.transform; Xform: PROC [p: Pair] RETURNS [Pair] ~ {RETURN[[ m.d * p.x + m.e * p.y + m.f, m.a * p.x + m.b * p.y + m.c ]]}; p: Pair _ Xform[[area.x, area.y]]; move[p.y, p.x]; p _ Xform[[area.x + area.w, area.y]]; line[p.y, p.x]; p _ Xform[[area.x + area.w, area.y + area.h]]; line[p.y, p.x]; p _ Xform[[area.x, area.y + area.h]]; line[p.y, p.x]; }; Runs: PROC[run: PROC[s, fMin: INTEGER, fSize: NAT], repeat: PROC[timesToRepeatScanline: NAT]] ~ { RunFromScanConverter: PROC [sMin, fMin: INTEGER, fSize: NAT] = { run[s: sMin, fMin: fMin, fSize: fSize]; }; ImagerScanConverter.ConvertToRuns[ devicePath: devicePath, runProc: RunFromScanConverter, clipBox: BoxFromMask[displayContext.deviceClipper] ]; }; devicePath: ImagerScanConverter.DevicePath; IF displayContext.transform.type # hard THEN { p1: Pair _ ImagerTransform.Transform[[area.x, area.y], displayContext.transform]; p2: Pair _ ImagerTransform.Transform[[area.x+area.w, area.y+area.h], displayContext.transform]; sMin: INTEGER _ Real.RoundLI[MAX[MIN[p1.x, p2.x], -LAST[INTEGER]/2]]; sMax: INTEGER _ Real.RoundLI[MIN[MAX[p1.x, p2.x], LAST[INTEGER]/2]]; fMin: INTEGER _ Real.RoundLI[MAX[MIN[p1.y, p2.y], -LAST[INTEGER]/2]]; fMax: INTEGER _ Real.RoundLI[MIN[MAX[p1.y, p2.y], LAST[INTEGER]/2]]; RETURN [ImagerMasks.InlineBox[sMin: sMin, fMin: fMin, sSize: sMax-sMin, fSize: fMax-fMin]]; }; devicePath _ ImagerScanConverter.CreatePath[ pathProc: GenPath, clipBox: BoxFromMask[displayContext.deviceClipper] ]; RETURN[ ImagerMasks.Create[Runs] ]; }; MaskFromIntRectangle: PROC [displayContext: DisplayContext, area: IntRectangle] RETURNS [Mask] ~ { RETURN[ MaskFromRectangle[ displayContext, FloatRect[area] ] ]; }; ValidateCompositeClipper: PROC [displayContext: DisplayContext] ~ { OPEN displayContext; clipper _ ClipMask[ ClipMask[clientClipper, viewerClipper, FALSE], deviceClipper, FALSE ]; }; END. ,ImagerDisplayClipperImpl.mesa Created April 28, 1983 Last Edited by: Crow, August 31, 1983 6:14 pm Exported Definitions Client-called Procedures (exported to Imager) Client clipping areas are first transformed by the client transform to fix them on the viewer Modifies old clipping region by supplied outline. Exclude sets clipping outside path rather than inside. Modifies old clipping region by supplied outline. Exclude sets clipping outside path rather than inside. Fast Track procedures Modifies old clipping region by supplied outline. Exclude sets clipping outside path rather than inside. If area is all visible then execute callBack without clipping otherwise clip Window Package Procedures (exported to Imager) Display Procedures (exported to ImagerDisplay) easy case assumed, set outline rectangle (in device space) to clip rectangle easy case assumed, clip outline rectangle (in device space) to clip rectangle Internal Procedures Transforms (x, y) to (s. f) Transforms (x, y) to (s. f) Assemble composite clipper, leave result in device space Κ ˜head™J™J™.šΟk ˜ Jšœ œ˜'Jšœ œ$˜4Jšœœ;˜OJšœ˜Jšœœ1˜FJšœœ7˜MJšœ˜Jšœœ7˜KJšœœ:˜S——head2šœ ˜'JšœG˜NJšœ˜J˜Jšœœœ ˜J˜Jšœ œ˜Jšœœ˜-Jšœœ˜0Jšœœ˜Jšœœ˜1—™Iašœœœœ˜,Jšœœœœ˜(—™-J™]unitšΟn œ œœ˜GMšœ!œ˜6Mšœ œœ(˜?Mšœ ˜Mšœ˜—šž œ œ0˜GMšœ!œ˜6Mšœœœ ˜!Mšœ%˜%Mšœ)˜)Mšœ˜—šžœ œ+œœ˜UJšœi™iJšœ!œ˜6šœ)˜)Icšœ˜Jšœ&˜&Jšœ ˜ —Jšœ)˜)J˜—š ž œœœ1œœ˜_Jšœi™iJšœ!œ˜6Nšœœ%˜+šœ*˜.Ošœ˜Ošœ,˜,Ošœ ˜ —šœΟcL˜TOšœ˜"Ošœ œ˜MšœP˜PJšœœ˜'Jšœœ!˜+Jšœœ1˜;Jšœœ1˜;Jšœœ œœ˜3Jšœœ œœ˜3J˜—Jšœ)˜)Jšœ˜—šž œ œ%œ˜WJšœ!œ˜6Nšœœœ˜)šœœ˜ šœ˜Jšœ)˜)Jšœ˜Jšœ˜—Jšœ˜—šœŸœŸ,˜TMšœJ˜JJšœ&œ%˜OJšœœ%œ&˜PJšœœ ˜šœœ1œ˜XJšœœ.œ˜QJšœœ ˜Jšœœ˜—J˜—J˜—NšΟi™šžœ œ3œœ˜eJšœi™iJšœ!œ˜6Nšœœ&˜,Jšœ4˜8šœŸL˜TJšœ˜"Ošœ œ˜OšœX˜XJšœœ˜Jšœœ˜ Jšœœ&˜0Jšœœ&˜0Jšœœ œœ˜3Jšœœ œœ˜3J˜—Jšœ)˜)J˜—šžœœœ(œ˜]Jšœ!œ˜6Nšœœœ˜)Jšœœ+˜6šœœŸ+˜SJšœS˜SJšœœ˜:Jšœœœ˜:Jšœœ ˜šœœ&œ˜BJšœœ#œ˜;Jšœœ ˜Jšœœ˜—J˜—J˜—šžœœœ4œ˜dJšœL™LJšœ!œ˜6Nšœ-œœ˜QJšœ˜Jšœœ˜Jšœ˜——™.šžœ œL˜`Mšœ˜MšœT˜TMšœ˜—šžœ œ0œ˜QMšœ!œ˜6Nšœ œ˜Mšœ ˜$šœ*˜.Ošœ˜Ošœ5˜5Ošœ ˜ —Mšœ˜—šžœ œœ˜KMšœ!œ˜6šœœ˜%Mšœ ˜&Mšœ˜—Mšœ˜—šž œ œœ˜HNšœ!œ˜6šœœ˜%šœ˜ šœ&˜&Mšœ˜Mšœ8˜8M˜—Mšœ˜—Mšœ˜—Mšœ˜——™.šžœœœ.˜Kšœ!œ˜6MšœL™L—MšœY˜YMšœLœ˜QJšœ)˜)J˜—šžœœœ.˜Lšœ!œ˜6JšœM™M—JšœY˜Yšœœ˜$Ošœ œ˜Jšœœ˜Jšœœ˜ Jšœœ&˜0Jšœœ&˜0Jšœœ œœ˜3Jšœœ œœ˜3J˜—Jšœ)˜)M˜—šžœœœ.˜KJšœ!œ˜6NšœLœ˜QJšœ)˜)J˜——™šž œœœœ˜CJšœW˜]Jšœ˜—š ž œœ+œœœœ˜ašœ˜Jšœ.Ÿ˜HOšœœ(˜+OšœœŸ ˜'Ošœœ'œ˜.Ošœ˜ Ošœœ˜ —J˜—šžœœœœ ˜EJš œœœœœ ˜=šœ˜Jšœ&œ˜.Jšœœ˜ Jšœœ˜$Jšœœ/˜9Jšœœ/˜9Jšœœœœ˜9Jšœœœœ˜9Jšœœ˜+Jšœ˜—šœœ ˜Jšœœ%˜0Jšœœ˜+—J˜—šž œœœ,˜RMšœ:˜:Mšœ˜—šž œœ.œ ˜Ršžœœœœ œœ œœ˜mJšœ9˜9šžœœ œ œ˜0Jšœ™Jšœ˜Jšœ˜Jšœ˜—Jšžœœ;˜GJšžœœ;˜Hšžœœ˜#JšœK˜KJšœ/˜/Jšœ˜—Jšœ.˜.Jšœ˜—šžœœœ œ œ œœ˜ašžœœœ œ˜@Jšœ'˜'Jšœ˜—šœ"˜"Jšœ˜Jšœ˜Jšœ5˜5—Jšœ˜—šœL˜LJšœ˜Jšœ5˜5—Jšœ˜#Jšœ˜—šžœœ3œ ˜\šžœœœœ œœ œœ˜mJšœ9˜9šžœœ œ œ˜0Jšœ™Jšœ˜Jšœ˜Jšœ˜—Jšœ6˜6Jšœ8˜8Jšœ>˜>Jšœ8˜8Jšœ˜—šžœœœ œ œ œœ˜ašžœœœ œ˜@Jšœ'˜'Jšœ˜—šœ"˜"Jšœ˜Jšœ˜Jšœ5˜5—Jšœ˜—Jšœ+˜+šœ&œ˜.JšœQ˜QJšœD˜DJšœ,˜,Jš œœœœœœ˜EJš œœœœœœ˜DJš œœœœœœ˜EJš œœœœœœ˜DJšœU˜[Jšœ˜—šœ,˜,Jšœ˜Jšœ5˜5—Jšœ˜#Jšœ˜—Nšžœœ6˜Pšœœ ˜Jšœ9˜?J˜—šžœœ%˜CJ™8Jšœ˜šœ ˜ šœ ˜ Jšœ'œ˜.Jšœ˜Jš˜Jšœ˜——Jšœ˜—J˜Jšœ˜——…—0TA‰