Copyright (C) 1994, Digital Equipment Corp.
UNSAFE MODULE; IMPORT VBT, Point, Rect, Path, PathPrivate, Batch, BatchUtil, BatchRep, PaintPrivate, PaintExt, Word, Math; TYPE Com = PaintPrivate.PaintCommand; CONST MiterLimit = 11.0d0; (* in degrees *) ToRadians = 3.14159265358979324d0 / 180.0d0; VAR (* CONST *) MiterFactor: LONGREAL; (* 1.0 / sin((ToRadians * MiterLimit) / 2.0) *) PROCEDURE DblBufferUtil Tighten (ba: Batch.T) = VAR cptr: PaintPrivate.CommandPtr := BatchUtil.Succ(ba, NIL); doClip := ba.clipped = BatchUtil.ClipState.Unclipped; baClip := ba.clip; res := Rect.Empty; BEGIN WHILE cptr # NIL DO IF doClip AND NOT Rect.Subset(cptr.clip, baClip) THEN (* clip the command's "clip" to the batch's "clip" *) IF cptr.command = Com.TextCom THEN VAR tptr := LOOPHOLE(cptr, PaintPrivate.TextPtr); BEGIN tptr.props := tptr.props + PaintPrivate.Props{PaintPrivate.Prop.Clipped} END END; cptr.clip := Rect.Meet(cptr.clip, baClip) END; IF cptr.command = Com.ExtensionCom THEN VAR eptr := LOOPHOLE(cptr, PaintPrivate.ExtensionPtr); rect := ExtensionBB(eptr); BEGIN cptr.clip := Rect.Meet(cptr.clip, rect); res := Rect.Join(res, cptr.clip); (* clip any following "RepeatCom"'s by "rect" *) LOOP cptr := BatchUtil.Succ(ba, cptr); IF cptr = NIL OR cptr.command # Com.RepeatCom THEN EXIT END; IF doClip THEN cptr.clip := Rect.Meet(cptr.clip, baClip) END; cptr.clip := Rect.Meet(cptr.clip, rect); res := Rect.Join(res, cptr.clip) END END ELSE res := Rect.Join(res, cptr.clip); cptr := BatchUtil.Succ(ba, cptr) END; END; ba.clip := res; ba.clipped := BatchUtil.ClipState.Tight END Tighten; PROCEDUREExtensionBB (eptr: PaintPrivate.ExtensionPtr): Rect.T = VAR res: Rect.T; BEGIN CASE eptr.subCommand OF PaintExt.FillCommand => VAR fptr := LOOPHOLE(eptr, PaintExt.FillPtr); BEGIN res := PathBB(eptr, ADR(fptr.path)) END | PaintExt.StrokeCommand => VAR sptr := LOOPHOLE(eptr, PaintExt.StrokePtr); grow: INTEGER; BEGIN res := PathBB(eptr, ADR(sptr.path)); IF sptr.width # 0 THEN grow := (sptr.width + 1) DIV 2; IF sptr.join = VBT.JoinStyle.Miter THEN grow := CEILING(FLOAT(grow, LONGREAL) * MiterFactor) END; res := Rect.Inset(res, -grow) END END | PaintExt.LineCommand => VAR lptr := LOOPHOLE(eptr, PaintExt.LinePtr); BEGIN res := RectHull(lptr.p, lptr.q); IF lptr.width # 0 THEN res := Rect.Inset(res, -((lptr.width + 1) DIV 2)) END END ELSE RETURN Rect.Full END; RETURN Rect.Add(res, eptr.delta) END ExtensionBB; PROCEDURERectHull (READONLY p, q: Point.T): Rect.T = BEGIN RETURN Rect.T{ MIN(p.h, q.h), MAX(p.h, q.h) + 1, MIN(p.v, q.v), MAX(p.v, q.v) + 1} END RectHull; PROCEDUREPathBB ( eptr: PaintPrivate.ExtensionPtr; pptr: PaintExt.PathPtr) : Rect.T = <* FATAL Path.Malformed *> VAR path := NEW(Path.T); BEGIN path.curveCount := pptr.curveCount; path.start := pptr + ADRSIZE(pptr^); (* skip "curveCount" field *) VAR end := eptr + (eptr.szOfRec * ADRSIZE(Word.T)); BEGIN path.next := end; path.end := end; path.current := end END; RETURN Path.BoundingBox(path) END PathBB; BEGIN (* initialize MiterFactor *) MiterFactor := 1.0d0 / Math.sin((ToRadians * MiterLimit) / 2.0d0); END DblBufferUtil.