DIRECTORY Imager, ImagerBackdoor, ImagerColor, ImagerPath, IO, Pipal, PipalInt, PipalPaint, PipalReal, Rope, TerminalIO; PipalPaintImpl: CEDAR MONITOR LOCKS queue USING queue: Queue IMPORTS Imager, ImagerBackdoor, ImagerColor, IO, Pipal, PipalInt, PipalReal, Rope, TerminalIO EXPORTS PipalPaint = BEGIN OPEN PipalPaint; debugPrintEnqueued: BOOL _ FALSE; -- When TRUE, prints all enqueued requests debugPrintDequeued: BOOL _ FALSE; -- When TRUE, prints all dequeued requests debugOptimize: BOOL _ TRUE; debugConservativeClip: BOOL _ TRUE; debugTestForEmpty: BOOL _ FALSE; debugClipArea: BOOL _ FALSE; -- set to TRUE to see the area redisplayed! debugContext: Imager.Context _ NIL; paintMethod: PUBLIC Pipal.Method _ Pipal.RegisterMethod["Paint"]; Paint: PUBLIC PaintProc = { data: REF _ Pipal.ObjectMethod[object, paintMethod]; debugContext _ context; IF data=NIL THEN PaintFromEnumerate[object, context] ELSE (NARROW [data, REF PaintProc]^)[object, context]; }; PaintFromEnumerate: PaintProc = { EachChild: PipalReal.EachChildProc = { TransformAndPaint: PROC = { Imager.ConcatT[context, transformation]; Paint[child, context]; }; Imager.DoSave[context, TransformAndPaint]; }; transformation: PipalReal.Transformation _ PipalReal.CreateTransformation[]; [] _ PipalReal.Enumerate[object, EachChild, transformation]; PipalReal.DestroyTransformation[transformation]; }; paintMethodProp: PUBLIC ATOM _ $PaintMethodAnnotation; CreatePaintMethodAnnotation: PUBLIC PROC [child: Pipal.Object, paint: PaintProc] RETURNS [annotation: Pipal.Annotation] = { annotation _ Pipal.CreateAnnotation[child, paintMethodProp, NEW [PaintProc _ paint]]; }; PaintAnnotation: PaintProc = { annotation: Pipal.Annotation _ NARROW [object]; paint: PaintProc _ IF annotation.key=paintMethodProp THEN (NARROW [annotation.value, REF PaintProc]^) ELSE Paint; paint[annotation.child, context]; }; Rectangle: TYPE = PipalReal.Rectangle; Rectangles: TYPE = LIST OF Rectangle; enumerateAreaMethod: PUBLIC Pipal.Method _ Pipal.RegisterMethod["EnumerateArea"]; EnumerateArea: PUBLIC EnumerateAreaProc = { data: REF _ Pipal.ObjectMethod[area, enumerateAreaMethod]; quit _ (IF data=NIL THEN AreaFromEnumerate ELSE (NARROW [data, REF EnumerateAreaProc]^))[area, each, transformation]; }; AreaFromEnumerate: EnumerateAreaProc = { EachChild: PipalReal.EachChildProc = {quit _ EnumerateArea[child, each, transformation]}; quit _ PipalReal.Enumerate[area, EachChild, transformation]; }; emptyArea: PUBLIC Area = Pipal.void; fullArea: PUBLIC Area = CreateExplicitArea[PipalReal.fullRectangle]; -- anything would do ... IsEmptyArea: PUBLIC PROC [area: Area] RETURNS [empty: BOOL] = { transformation: PipalReal.Transformation _ PipalReal.CreateTransformation[]; empty _ NOT EnumerateArea[area, PipalReal.AlwaysQuit, transformation]; PipalReal.DestroyTransformation[transformation]; }; AreaToRope: PUBLIC PROC [area: Area] RETURNS [rope: Pipal.ROPE] = { transformation: PipalReal.Transformation _ PipalReal.CreateTransformation[]; EachRect: PipalReal.RectangleProc = { rope _ Rope.Cat[rope, PipalReal.RectangleToRope[rect], " "]; }; rope _ "{"; [] _ EnumerateArea[area, EachRect, transformation]; PipalReal.DestroyTransformation[transformation]; RETURN [Rope.Cat[rope, "}"]]; }; ExplicitArea: TYPE = REF ExplicitAreaRec; ExplicitAreaRec: TYPE = RECORD [rectangle: Rectangle]; explicitAreaClass: PRIVATE Pipal.Class _ Pipal.RegisterClass[name: "ExplicitArea", type: CODE [ExplicitAreaRec]]; AreaExplicitArea: EnumerateAreaProc = { ea: ExplicitArea _ NARROW [area]; quit _ each[ea.rectangle]; }; BBoxExplicitArea: PipalReal.BBoxProc = { ea: ExplicitArea _ NARROW [object]; bbox _ PipalReal.TransformRectangle[transformation, ea.rectangle]; }; CreateExplicitArea: PUBLIC PROC [rectangle: PipalReal.Rectangle] RETURNS [area: Area] = { area _ NEW [ExplicitAreaRec _ [rectangle]]; }; ConsRect: PROC [rect: Rectangle, rects: Rectangles] RETURNS [Rectangles] = { RETURN [IF PipalReal.IsDegeneratedRectangle[rect] THEN rects ELSE CONS [rect, rects]]; }; CollectRects: PROC [area: Area, transformation: PipalReal.Transformation] RETURNS [rects: Rectangles _ NIL] = { InsertEach: PipalReal.RectangleProc = {rects _ ConsRect[rect, rects]}; [] _ EnumerateArea[area, InsertEach, transformation]; }; IntersectRects: PROC [rects1, rects2: Rectangles] RETURNS [rects: Rectangles _ NIL] = { FOR list1: Rectangles _ rects1, list1.rest WHILE list1#NIL DO rect1: Rectangle _ list1.first; FOR list2: Rectangles _ rects2, list2.rest WHILE list2#NIL DO rects _ ConsRect[PipalReal.IntersectBox[rect1, list2.first], rects]; ENDLOOP; ENDLOOP; }; DecomposeRects: PROC [r, clip: Rectangle] RETURNS [union: Rectangles _ NIL] = { InsertEach: PipalReal.RectangleProc = {union _ CONS [rect, union]}; [] _ PipalReal.DecomposeRect[r: r, clip: clip, outside: InsertEach]; }; ComplementRects: PROC [rects1, rects2: Rectangles] RETURNS [rects: Rectangles _ NIL] = { FOR list1: Rectangles _ rects1, list1.rest WHILE list1#NIL DO rect1: Rectangle _ list1.first; inter: Rectangles _ LIST [rect1]; FOR list2: Rectangles _ rects2, list2.rest WHILE list2#NIL DO inter _ IntersectRects[inter, DecomposeRects[r: list2.first, clip: rect1]]; ENDLOOP; FOR list2: Rectangles _ inter, list2.rest WHILE list2#NIL DO rects _ ConsRect[list2.first, rects]; ENDLOOP; ENDLOOP; }; IntersectionArea: TYPE = REF IntersectionAreaRec; IntersectionAreaRec: TYPE = RECORD [sub: BOOL, area1, area2: Area]; intersectionAreaClass: PRIVATE Pipal.Class _ Pipal.RegisterClass[name: "IntersectionArea", type: CODE [IntersectionAreaRec]]; AreaIntersectionArea: EnumerateAreaProc = { ia: IntersectionArea = NARROW [area]; subRects1, subRects2: Rectangles; subRects1 _ CollectRects[ia.area1, transformation]; subRects2 _ CollectRects[ia.area2, transformation]; FOR list: Rectangles _ (IF ia.sub THEN ComplementRects ELSE IntersectRects)[subRects1, subRects2], list.rest WHILE list#NIL DO IF each[list.first] THEN RETURN [TRUE]; ENDLOOP; }; BBoxIntersectionArea: PipalReal.BBoxProc = { ia: IntersectionArea = NARROW [object]; bbox _ PipalReal.BBox[ia.area1, transformation]; IF NOT ia.sub THEN bbox _ PipalReal.BoundingBox[PipalReal.BBox[ia.area2, transformation], bbox]; }; IntersectArea: PUBLIC PROC [area1, area2: Area] RETURNS [area: Area] = { area _ NEW [IntersectionAreaRec _ [FALSE, area1, area2]]; }; SubArea: PUBLIC PROC [area1, area2: Area] RETURNS [area: Area] = { area _ NEW [IntersectionAreaRec _ [TRUE, area1, area2]]; }; ChildishArea: TYPE = REF ChildishAreaRec; ChildishAreaRec: TYPE = RECORD [child: Pipal.Object, option: AreaOption]; childishAreaClass: PRIVATE Pipal.Class _ Pipal.RegisterClass[name: "ChildishArea", type: CODE [ChildishAreaRec]]; ApplyOnEdges: PROC [rect: Rectangle, each: PipalReal.RectangleProc] RETURNS [quit: BOOL _ FALSE] = { IF each[[[rect.base.x, rect.base.y], [rect.size.x, 0]]] THEN RETURN [TRUE]; IF each[[[rect.base.x, rect.base.y], [0, rect.size.y]]] THEN RETURN [TRUE]; IF each[[[rect.base.x+rect.size.x, rect.base.y], [0, rect.size.y]]] THEN RETURN [TRUE]; IF each[[[rect.base.x, rect.base.y+rect.size.y], [rect.size.x, 0]]] THEN RETURN [TRUE]; }; AreaChildishArea: EnumerateAreaProc = { ca: ChildishArea _ NARROW [area]; bbox: Rectangle = PipalReal.BBox[ca.child, transformation]; ExtendedEach: PipalReal.RectangleProc = {quit _ each[PipalReal.Extend[rect, 1.0]]}; EachChildEdge: PipalReal.RectangleProc ~ {quit _ ApplyOnEdges[rect, ExtendedEach]}; SELECT ca.option FROM bboxChild => quit _ ExtendedEach[bbox]; edgesChild => quit _ ApplyOnEdges[bbox, ExtendedEach]; edgesChildren => quit _ EnumerateArea[ca.child, EachChildEdge, transformation]; ENDCASE => ERROR; }; BBoxChildishArea: PipalReal.BBoxProc = { ca: ChildishArea = NARROW [object]; bbox _ PipalReal.Extend[PipalReal.BBox[ca.child, transformation], 1.0]; }; ChildArea: PUBLIC PROC [child: Pipal.Object, option: AreaOption] RETURNS [area: Area] = { area _ NEW [ChildishAreaRec _ [child, option]]; }; PaintAreaOutlineAnnotation: PaintProc = { PaintAreaOutline[context, object]; }; CreatePaintAreaOutline: PUBLIC PROC [area: Area] RETURNS [annotation: Pipal.Annotation] = { annotation _ CreatePaintMethodAnnotation[area, PaintAreaOutlineAnnotation]; }; nullRequest: Request = [none, emptyArea]; -- all what is important here is that referencing/copying it does not cause a memory fault. RequestToRope: PUBLIC PROC [request: Request] RETURNS [Pipal.ROPE] = { RETURN [Rope.Cat[ "Request { ", SELECT request.type FROM none => "none", clearArea => Rope.Cat["clearArea ", AreaToRope[request.area]], paintArea => Rope.Cat["paintArea ", Pipal.DescribeToRope[request.data], " ", AreaToRope[request.area]], clearAndPaint => Rope.Cat["clearAndPaint ", Pipal.DescribeToRope[request.data], " ", AreaToRope[request.area]], scale => Rope.Cat["scale ", PipalReal.TransformationToRope[NARROW [request.data]]], other => "other", ENDCASE => ERROR, " }" ]]; }; Mod: PROC [index: NAT, max: NAT] RETURNS [NAT] = INLINE { RETURN [IF index requests[index] _ ClipRequest[requests[index], area]; scale => RETURN; none, other => {}; ENDCASE => ERROR; ENDLOOP; }; Enqueue: PUBLIC ENTRY PROC [queue: Queue, request: Request, reverse: BOOL _ FALSE] = { ENABLE UNWIND => NULL; new: NAT; max: NAT _ queue.requests.max; IF queue.size>=max THEN { requests: REF Requests _ NEW [Requests[max*2]]; FOR i: NAT IN [0 .. max) DO requests[i] _ queue.requests[i] ENDLOOP; FOR i: NAT IN [max .. max*2) DO requests[i] _ nullRequest ENDLOOP; queue.requests _ requests; max _ max*2; }; new _ Mod[queue.start+(IF reverse THEN max-1 ELSE queue.size), max]; IF debugPrintEnqueued THEN TerminalIO.PutF["Enqueued: %g\n", IO.rope[RequestToRope[request]]]; queue.requests[new] _ request; queue.size _ queue.size+1; IF reverse THEN queue.start _ new; IF NOT debugOptimize THEN RETURN; SELECT request.type FROM clearArea, clearAndPaint => IF NOT reverse THEN OptimizeClear[queue, request.area, queue.start, queue.size-1]; ENDCASE => {}; }; Dequeue: PUBLIC ENTRY PROC [queue: Queue] RETURNS [empty: BOOL, request: Request] = { ENABLE UNWIND => NULL; Decr: PROC = { queue.start _ Mod[queue.start+1, queue.requests.max]; queue.size _ queue.size-1; }; SkipNone: PROC = { WHILE queue.size#0 AND queue.requests[queue.start].type=none DO Decr[] ENDLOOP; }; SkipNone[]; IF queue.size=0 THEN RETURN [TRUE, nullRequest]; request _ queue.requests[queue.start]; Decr[]; empty _ FALSE; SkipNone[]; WHILE queue.size#0 DO next: Request _ queue.requests[queue.start]; IF request.type#clearAndPaint OR next.type#clearAndPaint OR request.data#next.data THEN EXIT; -- hack, of course! request.area _ Pipal.CreateOverlay[LIST [request.area, next.area]]; Decr[]; SkipNone[]; ENDLOOP; IF debugPrintDequeued THEN TerminalIO.PutF["Dequeued: %g\n", IO.rope[RequestToRope[request]]]; }; PaintIntTranslation: PaintProc = { translation: PipalInt.Translation _ NARROW [object]; Imager.TranslateT[context, PipalReal.IntToRealVector[translation.vector]]; Paint[translation.child, context]; Imager.TranslateT[context, PipalReal.IntToRealVector[PipalInt.Neg[translation.vector]]]; }; PaintOverlay: PaintProc = { transformation: PipalReal.Transformation _ PipalReal.CreateTransformation[]; -- changed the day PaintProcs have a transformation! bounds: Imager.Rectangle _ ImagerBackdoor.GetBounds[context]; clip: Rectangle _ [[bounds.x, bounds.y], [bounds.w, bounds.h]]; overlay: Pipal.Overlay _ NARROW [object]; FOR i: NAT DECREASING IN [0..overlay.size) DO IF PipalReal.DoRectanglesIntersect[clip, PipalReal.BBox[overlay[i], transformation]] THEN Paint[overlay[i], context]; ENDLOOP; PipalReal.DestroyTransformation[transformation]; }; RectanglePath: PROC [r: Rectangle, moveTo: ImagerPath.MoveToProc, lineTo: ImagerPath.LineToProc] = { moveTo[r.base]; lineTo[[r.base.x+r.size.x, r.base.y]]; lineTo[[r.base.x+r.size.x, r.base.y+r.size.y]]; lineTo[[r.base.x, r.base.y+r.size.y]]; }; AreaPath: PROC [area: Area, moveTo: ImagerPath.MoveToProc, lineTo: ImagerPath.LineToProc] = { transformation: PipalReal.Transformation _ PipalReal.CreateTransformation[]; EachRect: PipalReal.RectangleProc = {RectanglePath[rect, moveTo, lineTo]}; [] _ EnumerateArea[area, EachRect, transformation]; PipalReal.DestroyTransformation[transformation]; }; white: Imager.ConstantColor = ImagerColor.Find["Xerox/Research/ChipNDale/CD/InitialColor"]; ClearArea: PUBLIC PROC [context: Imager.Context, area: Area] = { Path: Imager.PathProc ~ {AreaPath[area, moveTo, lineTo]}; ClearAreaInternal: PROC = { SetColor[context, IF debugClipArea THEN Imager.MakeGray[0.25] ELSE white]; Imager.MaskFill[context: context, path: Path, oddWrap: FALSE]; }; Imager.DoSave[context, ClearAreaInternal]; }; ClipAndPaint: PUBLIC PROC [context: Imager.Context, object: Pipal.Object, clipArea: Area] = { Path: Imager.PathProc ~ {AreaPath[clipArea, moveTo, lineTo]}; ClipAndPaintInternal: PROC = { Imager.Clip[context: context, path: Path, oddWrap: FALSE]; Paint[object, context]; }; Imager.DoSave[context, ClipAndPaintInternal]; }; ClearClipAndPaint: PUBLIC PROC [context: Imager.Context, object: Pipal.Object, clipArea: Area] = { Path: Imager.PathProc ~ {AreaPath[clipArea, moveTo, lineTo]}; ClearClipAndPaintInternal: PROC = { SetColor[context, IF debugClipArea THEN Imager.MakeGray[0.25] ELSE white]; Imager.MaskFill[context: context, path: Path, oddWrap: FALSE]; Imager.Clip[context: context, path: Path, oddWrap: FALSE]; Paint[object, context]; }; Imager.DoSave[context, ClearClipAndPaintInternal]; }; PaintOutline: PUBLIC PROC [context: Imager.Context, r: Rectangle, color: Color _ Imager.black] = { SetColor[context, color]; Imager.MaskVector[context, [r.base.x, r.base.y], [r.base.x+r.size.x, r.base.y]]; Imager.MaskVector[context, [r.base.x, r.base.y], [r.base.x, r.base.y+r.size.y]]; Imager.MaskVector[context, [r.base.x+r.size.x, r.base.y], [r.base.x+r.size.x, r.base.y+r.size.y]]; Imager.MaskVector[context, [r.base.x, r.base.y+r.size.y], [r.base.x+r.size.x, r.base.y+r.size.y]]; }; PaintAreaOutline: PUBLIC PROC [context: Imager.Context, area: Area, color: Color _ Imager.black] = { transformation: PipalReal.Transformation _ PipalReal.CreateTransformation[]; Each: PipalReal.RectangleProc ~ {PaintOutline[context, rect, color]}; [] _ EnumerateArea[area, Each, transformation]; PipalReal.DestroyTransformation[transformation]; }; PaintArea: PUBLIC PROC [context: Imager.Context, area: Area, color: Color _ Imager.black] = { transformation: PipalReal.Transformation _ PipalReal.CreateTransformation[]; EachRect: PipalReal.RectangleProc ~ { Imager.MaskRectangle[context, [rect.base.x, rect.base.y, rect.size.x, rect.size.y]]; }; SetColor[context, color]; [] _ EnumerateArea[area, EachRect, transformation]; PipalReal.DestroyTransformation[transformation]; }; SetColor: PUBLIC PROC [context: Imager.Context, color: Color] = { IF ImagerBackdoor.GetColor[context]#color THEN Imager.SetColor[context, color]; }; Pipal.PutClassMethod[explicitAreaClass, enumerateAreaMethod, NEW [EnumerateAreaProc _ AreaExplicitArea]]; Pipal.PutClassMethod[explicitAreaClass, PipalReal.bboxMethod, NEW [PipalReal.BBoxProc _ BBoxExplicitArea]]; Pipal.PutClassMethod[intersectionAreaClass, enumerateAreaMethod, NEW [EnumerateAreaProc _ AreaIntersectionArea]]; Pipal.PutClassMethod[intersectionAreaClass, PipalReal.bboxMethod, NEW [PipalReal.BBoxProc _ BBoxIntersectionArea]]; Pipal.PutClassMethod[childishAreaClass, enumerateAreaMethod, NEW [EnumerateAreaProc _ AreaChildishArea]]; Pipal.PutClassMethod[childishAreaClass, PipalReal.bboxMethod, NEW [PipalReal.BBoxProc _ BBoxChildishArea]]; Pipal.PutClassMethod[Pipal.annotationClass, paintMethod, NEW [PaintProc _ PaintAnnotation]]; Pipal.PutClassMethod[PipalInt.translationClass, paintMethod, NEW [PaintProc _ PaintIntTranslation]]; -- speed up Pipal.PutClassMethod[Pipal.overlayClass, paintMethod, NEW [PaintProc _ PaintOverlay]]; -- speed up END. <PipalPaintImpl.mesa Copyright Σ 1988 by Xerox Corporation. All rights reserved. Louis Monier February 2, 1988 2:31:30 am PST Bertrand Serlet May 19, 1988 6:32:34 pm PDT Debug Flags Painting Procedures Paint Method Annotation Areas Special Area Classes Compensating for the thickness of the outline Paint Queue We look around to see if the next request can be collapsed with request Speed-up hacks This one is more than a speed up since it does clipping. Maybe the clipping could be put in enumerate, and we could get rid of this one. Utilities Initialization Κ»– "cedar" style˜codešœ™Kšœ<™K˜—Kšœ*˜*K˜K˜—šž œœœD˜]Kšžœ9˜=šžœœ˜Kšœ3œ˜:Kšœ˜K˜—Kšœ-˜-K˜K˜—šžœœœD˜bKšžœ9˜=šžœœ˜#Kšœœœœ˜JKšœ7œ˜>Kšœ3œ˜:Kšœ˜K˜—Kšœ2˜2K˜K˜—šž œœœI˜bKšœ˜KšœP˜PKšœP˜PKšœb˜bKšœb˜bK˜K˜—šžœœœG˜dKšœL˜LKšžœA˜EKšœ/˜/Kšœ0˜0K˜K˜—šž œœœG˜]KšœL˜Lšžœ˜%KšœT˜TK˜—Kšœ˜Kšœ3˜3Kšœ0˜0K˜K˜—šžœ œ,˜AKšœ(œ!˜OK˜——™Kšœ=œ)˜išœ>œ*˜kK˜—KšœAœ-˜qšœBœ.˜sK˜—Kšœ=œ)˜išœ>œ*˜kK˜—šœ9œ ˜\K˜—Kšœ=œ%Ÿ ˜pKšœ6œŸ ˜bK˜K˜—Kšœ˜—…—CUω