CDVDraw.mesa
Copyright © 1983, 1984 by Xerox Corporation. All rights reserved.
Christian Jacobi August 5, 1983 11:07 am
last edited by Christian Jacobi November 5, 1984 10:24:10 am PST
DIRECTORY
Basics USING [BITSHIFT, bitsPerWord, LongMult],
CD,
CDApplications,
CDBasics,
CDColors,
CDOps,
CDOrient,
CDPrivate,
CDTexts,
CDVPrivate,
CDVScale,
Graphics,
GraphicsBasic,
GraphicsColor,
GraphicsOps,
PrincOps USING [BBptr, BitAddress, BBTable, SrcDesc, BitBltFlags, GrayParm],
PrincOpsUtils USING [BITBLT],
Real,
Rope,
RuntimeError,
Terminal,
TerminalExtras,
ViewerClasses,
ViewerSpecs;
CDVDraw: CEDAR MONITOR
IMPORTS Basics, CD, CDApplications, CDBasics, CDOps, CDOrient, CDVPrivate, CDVScale, Graphics, GraphicsOps, PrincOpsUtils, Real, RuntimeError, Terminal, TerminalExtras
EXPORTS CDVPrivate, CD --DrawRef's private fields-- =
BEGIN
ViewerPrivateRep: PUBLIC TYPE ~ CDVPrivate.MyGraphicRec;
ViewerSaveRep: PUBLIC TYPE ~ INTEGER; -- XXX placeholder
MyGraphicRef: TYPE ~ CDVPrivate.MyGraphicRef;
MyGraphicRec: TYPE ~ CDVPrivate.MyGraphicRec;
maxInfluence: CD.DesignNumber ~ 0;
virtual: Terminal.Virtual ~ Terminal.Current[];
defaultFont: Graphics.FontRef ~ GraphicsOps.DefaultFont[];
errrorReport: RECORD [
text: Rope.ROPE,
me: MyGraphicRef,
r: CD.Rect,
color: REF CDColors.Brick
];
bitBltFlagsForPaint: PrincOps.BitBltFlags = PrincOps.BitBltFlags[
direction: forward,
disjoint: TRUE,
disjointItems: TRUE,
gray: TRUE,
srcFunc: null,
dstFunc: or
];
bitBltFlagsForOutline: PrincOps.BitBltFlags = PrincOps.BitBltFlags[
direction: forward,
disjoint: TRUE,
disjointItems: TRUE,
gray: TRUE,
srcFunc: null,
dstFunc: or
];
bitBltFlagsForClearPattern: PrincOps.BitBltFlags = PrincOps.BitBltFlags[
direction: forward,
disjoint: TRUE,
disjointItems: TRUE,
gray: TRUE,
srcFunc: complement,
dstFunc: and
];
blackBrick: REF CDColors.Brick = NEW[CDColors.Brick←ALL[LAST[CARDINAL]]];
whiteBrick: REF CDColors.Brick = NEW[CDColors.Brick←ALL[0]];
BitBlitDraw: PROC[me: MyGraphicRef, r: CD.Rect, color: REF CDColors.Brick] =
TRUSTED
-- r ALLREADY CLIPPED
INLINE BEGIN
ENABLE {
UNWIND => NULL;
RuntimeError.UNCAUGHT => {
errrorReport.text ← "BitBlitDraw";
errrorReport.me ← me;
errrorReport.r←r;
errrorReport.color𡤌olor;
IF CDVPrivate.catchAny THEN GOTO SomeError ELSE REJECT;
};
};
xBit, x1, x2, y1, y2: CARDINAL;
vr: CD.Rect;
--DONE OUTSIDE r ← CDBasics.Intersection[r, me.deviceDrawRef.worldClip];
IF ~CDBasics.NonEmpty[r] THEN RETURN;
vr ← CDVScale.DesignToViewerRect[me.scale, r];
x1 ← MAX[vr.x1, 0];
y1 ← MAX[vr.y1, 0];
IF vr.x2<=0 OR vr.y2<=0 THEN RETURN;
x2 ← MIN[vr.x2, me.viewer.cw];  
y2 ← MIN[vr.y2, me.viewer.ch];
IF x1>=x2 OR y1>=y2 THEN RETURN;
xBit ← Basics.BITSHIFT[x1+me.vx, me.logbpp];
me.pBBptr.width ← Basics.BITSHIFT[x2-x1, me.logbpp];
me.pBBptr.height ← y2-y1;
y1 ← me.vy-y2;
me.pBBptr.dst ← [
me.screen
+ Basics.LongMult[y1, me.scWidthWords]
+ LONG[(xBit/Basics.bitsPerWord)],,
xBit MOD Basics.bitsPerWord
];
me.pBBptr.src ← [
LOOPHOLE[
LOOPHOLE[color, LONG CARDINAL] +
y1 MOD 4, LONG POINTER],,
xBit MOD Basics.bitsPerWord];
me.pBBptr.srcDesc.gray.yOffset ← y1 MOD 4;
IF me.bpp=1 THEN PrincOpsUtils.BITBLT[me.pBBptr]
ELSE {
TerminalExtras.LockColorFrame[vt: virtual,
xmin: x1+me.vx,
ymin: y1,
xmax: x2+me.vx,
ymax: y1+me.pBBptr.height
];
PrincOpsUtils.BITBLT[me.pBBptr];
TerminalExtras.UnlockColorFrame[virtual]
};
EXITS
SomeError => NULL;
END;
BitBlitSave: ENTRY PROC[me: MyGraphicRef, r: CD.Rect, color: REF CDColors.Brick, clearPattern: REF CDColors.Brick←NIL] =
TRUSTED BEGIN
ENABLE {
UNWIND => NULL;
RuntimeError.UNCAUGHT => {
errrorReport.text ← "BitBlitSave";
errrorReport.me ← me;
errrorReport.r←r;
errrorReport.color𡤌olor;
IF CDVPrivate.catchAny THEN GOTO SomeError ELSE REJECT;
};
};
xBit, x1, x2, y1, y2: CARDINAL;
vr: CD.Rect;
r ← CDBasics.Intersection[r, me.deviceDrawRef.worldClip];
IF ~CDBasics.NonEmpty[r] THEN RETURN;
vr ← CDVScale.DesignToViewerRect[me.scale, r];
x1 ← MAX[vr.x1, 0];
y1 ← MAX[vr.y1, 0];
IF vr.x2<=0 OR vr.y2<=0 THEN RETURN;
x2 ← MIN[vr.x2, me.viewer.cw];
y2 ← MIN[vr.y2, me.viewer.ch];
IF x1>=x2 OR y1>=y2 THEN RETURN;
xBit ← Basics.BITSHIFT[x1+me.vx, me.logbpp];
me.xBBptr.width ← Basics.BITSHIFT[x2-x1, me.logbpp];
me.xBBptr.height ← y2-y1;
y1 ← me.vy-y2; -- now y1 is device top pixel
me.xBBptr.srcDesc ← PrincOps.SrcDesc[gray[PrincOps.GrayParm[
yOffset: y1 MOD 4,
widthMinusOne: 0, --words
heightMinusOne: 3 --lines
]]];
me.xBBptr.dst ← [
me.screen
+ Basics.LongMult[y1, me.scWidthWords]
+ LONG[(xBit/Basics.bitsPerWord)],,
xBit MOD Basics.bitsPerWord
];
IF me.bpp#1 THEN TerminalExtras.LockColorFrame[vt: virtual,
xmin: x1+me.vx,
ymin: y1,
xmax: x2+me.vx,
ymax: y1+me.xBBptr.height
];
IF clearPattern#NIL THEN {
me.xBBptr.flags ← bitBltFlagsForClearPattern;
me.xBBptr.src ← [
LOOPHOLE[
LOOPHOLE[clearPattern, LONG CARDINAL] +
y1 MOD 4, LONG POINTER],,
xBit MOD Basics.bitsPerWord];
PrincOpsUtils.BITBLT[me.xBBptr];
};
me.xBBptr.src ← [
LOOPHOLE[
LOOPHOLE[color, LONG CARDINAL] +
y1 MOD 4, LONG POINTER],,
xBit MOD Basics.bitsPerWord];
me.xBBptr.flags ← bitBltFlagsForOutline;
PrincOpsUtils.BITBLT[me.xBBptr];
IF me.bpp#1 THEN TerminalExtras.UnlockColorFrame[virtual];
EXITS
SomeError => NULL;
END;
BitBlitOutLine: ENTRY PROC[r: CD.Rect, pr: CD.DrawRef] =
BEGIN
ENABLE {
UNWIND => NULL;
RuntimeError.UNCAUGHT => {
errrorReport.text ← "BitBlitOutLine";
errrorReport.me ← pr.viewerPrivate;
errrorReport.r←r;
IF CDVPrivate.catchAny THEN GOTO SomeError ELSE REJECT;
};
};
me: MyGraphicRef ~ pr.viewerPrivate;
vr, clipr: CD.Rect;
DrawBlack: --INTERNAL-- PROC[me: MyGraphicRef, x1, y1, x2, y2: INTEGER] =
--draw exclusive high border pixels
TRUSTED INLINE BEGIN
--no empty test; is guaranteed by caller
xBits: CARDINAL ~ Basics.BITSHIFT[x1+INTEGER[me.vx], me.logbpp];
me.xBBptr.width ← Basics.BITSHIFT[x2-x1, me.logbpp];
me.xBBptr.height ← y2-y1;
me.xBBptr.dst ← [
me.screen
+ Basics.LongMult[INTEGER[me.vy]-y2, me.scWidthWords]
+ LONG[(xBits/Basics.bitsPerWord)],,
xBits MOD Basics.bitsPerWord
];
PrincOpsUtils.BITBLT[me.xBBptr];
END;
--clip to area where
--1) small enogh: it does not crash on scaling later
--2) big enogh: if drawn, it does not draw artificial lines
IF r.x2>me.dClip.x2 THEN r.x2←me.dClip.x2+1;
IF r.y2>me.dClip.y2 THEN r.y2←me.dClip.y2+1;
IF r.x1<me.dClip.x1 THEN r.x1←me.dClip.x1-1;
IF r.y1<me.dClip.y1 THEN r.y1←me.dClip.y1-1;
vr ← CDVScale.DesignToViewerRect[me.scale, r];
clipr ← CDBasics.Intersection[
CDVScale.DesignToViewerRect[me.scale, me.deviceDrawRef.worldClip],
vr
];
clipr.x1 ← MAX[clipr.x1, 0];
clipr.y1 ← MAX[clipr.y1, 0];
clipr.x2 ← MIN[clipr.x2, LONG[me.viewer.cw]];
clipr.y2 ← MIN[clipr.y2, LONG[me.viewer.ch]];
IF clipr.x1>=clipr.x2 OR clipr.y1>=clipr.y2 THEN RETURN;
--harder empty test than CDBasics
--necessary because we add/subtract one
TRUSTED {
me.xBBptr.src ← [LOOPHOLE[blackBrick, LONG POINTER],,0];
me.xBBptr.flags ← bitBltFlagsForOutline;
me.xBBptr.srcDesc ← PrincOps.SrcDesc[gray[PrincOps.GrayParm[
yOffset: 0,
widthMinusOne: 0, --words
heightMinusOne: 0 --lines
]]];
};
IF me.bpp#1 THEN {
TerminalExtras.LockColorFrame[vt: virtual,
xmin: clipr.x1+me.vx,
ymin: me.vy+1-clipr.y2,
xmax: clipr.x2+me.vx-1,
ymax: me.vy-clipr.y1
];
};
IF vr.x1>=clipr.x1 THEN DrawBlack[me, clipr.x1, clipr.y1, clipr.x1+1, clipr.y2]; --left
IF vr.y2<=clipr.y2 THEN DrawBlack[me, clipr.x1, clipr.y2-1, clipr.x2, clipr.y2]; --top
IF vr.x2<=clipr.x2 THEN DrawBlack[me, clipr.x2-1, clipr.y1, clipr.x2, clipr.y2]; --right
IF vr.y1>=clipr.y1 THEN DrawBlack[me, clipr.x1, clipr.y1, clipr.x2, clipr.y1+1]; --bottom
IF me.bpp#1 THEN TerminalExtras.UnlockColorFrame[virtual];
EXITS
SomeError => NULL;
END;
BitBlitDrawRectForViewers: ENTRY PROC[r: CD.Rect, l: CD.Level, pr: CD.DrawRef] =
BEGIN
ENABLE UNWIND => NULL;
me: MyGraphicRef = pr.viewerPrivate;
BitBlitDraw[me, CDBasics.Intersection[r, pr.worldClip], me.colorTable[l]];
END;
SaveRectForViewers: ENTRY PROCEDURE[r: CD.Rect, l: CD.Level, pr: CD.DrawRef] =
BEGIN
ENABLE UNWIND => NULL;
me: MyGraphicRef = pr.viewerPrivate;
IF me.saveList=NIL OR me.saveList.first.next>=CDVPrivate.saveListSize THEN
me.saveList ← CONS[CDVPrivate.SavedRectArraySeq[next: 0], me.saveList];
me.saveList.first.x[me.saveList.first.next] ← [r: CDBasics.Intersection[r, pr.worldClip], l: l];
me.saveList.first.next ← me.saveList.first.next+1
END;
SetGround: --CD.SetGroundProc-- PROC [pr: CD.DrawRef, pushedOut: BOOL] =
BEGIN
WITH pr.devicePrivate SELECT FROM
me: MyGraphicRef =>
me.colorTable ← me.personalColors[me.display][IF pushedOut THEN back ELSE normal]
ENDCASE => NULL;
END;
DrawCommentForViewers: PUBLIC PROC[r: CD.DesignRect, comment: Rope.ROPE, pr: CD.DrawRef] =
BEGIN
topToFontLine: NAT ~ 9+2;
fontHeight: NAT ~ 12;
leftMargin: NAT ~ 2;
bothMargin: NAT ~ 2*leftMargin;
me: MyGraphicRef ← NARROW[pr.devicePrivate];
vr: CD.Rect ← CDVScale.DesignToViewerRect[me.scale, r];
IF vr.y2-vr.y1>fontHeight THEN {
xw: REAL ~ Graphics.RopeWidth[font: defaultFont, rope: comment].xw;
IF vr.x2-vr.x1>xw+bothMargin THEN {
me.viewerContext.SetColor[Graphics.black];
me.viewerContext.SetCP[vr.x1+leftMargin, vr.y2-topToFontLine];
me.viewerContext.DrawRope[comment];
}
};
END;
RepaintRectAreaInViewer: PUBLIC PROC[me: MyGraphicRef, rect: CD.DesignRect, eraseFirst: BOOL] =
BEGIN
ENABLE {
RuntimeError.UNCAUGHT => IF CDVPrivate.catchAny THEN GOTO SomeError ELSE REJECT
};
interestRect: CD.DesignRect;
UpdateDrawInformation[me];
me.deviceDrawRef.worldClip ← interestRect ← CDBasics.Intersection[rect, me.dClip];
IF CDBasics.NonEmpty[interestRect] THEN {
[] ← Graphics.SetPaintMode[me.viewerContext, transparent];
RepaintBackground[me, interestRect, eraseFirst];
CDOps.QuickDrawDesign[me.actualDesign, me.deviceDrawRef];
[] ← Graphics.SetPaintMode[me.viewerContext, opaque];
IF me.saveList#NIL THEN {
l: CDVPrivate.SaveList ← me.saveList;
me.saveList ← NIL;
WHILE l#NIL DO
FOR i: INTEGER IN [0..l.first.next) DO
BitBlitSave[me, l.first.x[i].r, me.colorTable[l.first.x[i].l], me.greyTable[l.first.x[i].l]];
ENDLOOP;
l ← l.rest
ENDLOOP;
};
FOR pl: CDVPrivate.PainterList ← me.painterList, pl.rest WHILE pl#NIL DO
IF CDBasics.Intersect[interestRect, pl.first.rect] THEN
pl.first.proc[me, pl.first, interestRect !
RuntimeError.UNCAUGHT => IF CDVPrivate.catchAny THEN CONTINUE ELSE REJECT
]
ENDLOOP
}
EXITS SomeError=> NULL
END;
RepaintBackground: PUBLIC ENTRY PROC[me: MyGraphicRef, r: CD.DesignRect, eraseFirst: BOOL] =
BEGIN
ENABLE {
UNWIND => NULL;
RuntimeError.UNCAUGHT => {
errrorReport.text ← "background";
errrorReport.me ← me;
errrorReport.r ← r;
IF CDVPrivate.catchAny THEN GOTO SomeError ELSE REJECT
};
};
DrawOutside: --INTERNAL-- PROC [r: CD.DesignRect] =
BEGIN
BitBlitDraw[me, CDBasics.Intersection[r, me.dClip], me.colorTable[CD.backGround]];
END;
--RepaintBackground
IF eraseFirst THEN {
TRUSTED {me.pBBptr.flags.dstFunc ← null};
BitBlitDraw[me, CDBasics.Intersection[r, me.dClip], whiteBrick];
TRUSTED {me.pBBptr.flags.dstFunc ← or};
};
IF me.actualDesign.actual.first.mightReplace#NIL AND ~me.suppressOutsidePushedCell AND
me.actualDesign.actual.first.mightReplace.ob#NIL THEN
CDBasics.DecomposeRect[r: r,
test: CDApplications.ARectO[me.actualDesign.actual.first.mightReplace],
outside: DrawOutside
];
EXITS
SomeError => NULL;
END;
InitForBBLT: PROC [me: MyGraphicRef] =
BEGIN
x, y: REAL;
IF me.viewer.column=color THEN TRUSTED {
m: Terminal.ColorMode = Terminal.GetColorMode[virtual];
IF m.full OR m.bitsPerPixelChannelA=0 THEN ERROR CDVPrivate.notSupportedColorMode;
me.bpp ← m.bitsPerPixelChannelA;
me.screen ← virtual.colorBitmapA;
me.scWidth ← virtual.colorWidth; -- pixels
me.scWidthBits ← virtual.colorWidth*me.bpp;
me.scHeight ← virtual.colorHeight;
IF me.bpp=4 THEN {
me.display ← bit4;
me.logbpp ← 2;
}
ELSE IF me.bpp=8 THEN {
me.display ← bit8;
me.logbpp ← 3;
}
ELSE ERROR;
}
ELSE { -- b+w
me.display ← bw;
me.bpp ← 1;
me.logbpp ← 0;
me.scWidth ← ViewerSpecs.screenW/Basics.bitsPerWord;
me.scWidthBits ← ViewerSpecs.screenW;
me.scHeight ← ViewerSpecs.screenH;
me.screen ← Terminal.GetBitBltTable[virtual].bbt.dst.word;
};
me.colorTable ← me.personalColors[me.display][normal];
me.greyTable ← me.personalColors[me.display][grey];
[x, y] ← GraphicsOps.UserToDevice[me.viewerContext, 0, 0]; -- in device in pixels
me.vx ← Real.RoundI[x];
me.vy ← Real.RoundI[y]; --bottom most pixel of viewer
me.scWidthWords ← me.scWidthBits/Basics.bitsPerWord;
----------
--fixed pBBptr initializations
--done in viewerprocess: me.pBBptr ← PrincOpsUtils.AlignedBBTable[@bBTableSpace];
TRUSTED BEGIN
me.pBBptr^ ← PrincOps.BBTable[
dst: TRASH,
dstBpl: LOOPHOLE[me.scWidthBits, INTEGER],
src: TRASH,
srcDesc: PrincOps.SrcDesc[gray[PrincOps.GrayParm[
yOffset: 0, --is actually trash
widthMinusOne: 0, --words
heightMinusOne: 3 --lines
]]],
width: TRASH,
height: TRASH,
flags: bitBltFlagsForPaint
];
me.xBBptr^ ← me.pBBptr^;
END;
END;
InternalCreateDrawInformation: INTERNAL PROC [me: MyGraphicRef] =
BEGIN
s: REAL;
pr: CD.DrawRef ~ CD.NewNullDeviceDrawRef[me.actualDesign];
pr.drawRect ← BitBlitDrawRectForViewers;
pr.outLineProc ← BitBlitOutLine;
pr.drawComment ← DrawCommentForViewers;
pr.deviceContext ← Graphics.CopyContext[me.viewerContext];
s ← CDVScale.DesignToViewerFactor[me.scale];
pr.scaleHint ← s*me.suppressFactorForCells;
Graphics.Scale[pr.deviceContext, s, s];
Graphics.Translate[pr.deviceContext, -me.scale.off.x, -me.scale.off.y];
pr.contextFilter ← defaultContextFilter;
pr.devicePrivate ← me;
pr.stopFlag ← me.stoprequest;
pr.suppressOutsidePushedCell ← me.suppressOutsidePushedCell;
pr.setGround ← SetGround;
me.dClip ← pr.worldClip ← CDVScale.GetClipRecord[me.scale, me.viewer.cw, me.viewer.ch];
pr.minimalSize ← --XXX--
MIN[(me.dClip.x2-me.dClip.x1)/8, (me.dClip.y2-me.dClip.y1)/8];
InitForBBLT[me];
pr.saveRect ← (IF me.display=bit8 THEN BitBlitDrawRectForViewers ELSE SaveRectForViewers);
me.deviceDrawRef ← pr;
pr.viewerPrivate ← me; -- this line last! it tells DummyNotify that the rest is initialized
END;
UpdateDrawInformation: ENTRY PROC [me: MyGraphicRef] =
BEGIN ENABLE UNWIND => NULL;
s: REAL;
pr: CD.DrawRef;
IF me.deviceDrawRef=NIL THEN InternalCreateDrawInformation[me];
pr ← me.deviceDrawRef;
pr.deviceContext ← Graphics.CopyContext[me.viewerContext];
s ← CDVScale.DesignToViewerFactor[me.scale];
Graphics.Scale[pr.deviceContext, s, s];
Graphics.Translate[pr.deviceContext, -me.scale.off.x, -me.scale.off.y];
pr.contextFilter ← defaultContextFilter;
END;
CreateDrawInformation: PUBLIC ENTRY PROC [me: MyGraphicRef] =
BEGIN ENABLE UNWIND => NULL;
InternalCreateDrawInformation[me]
END;
defaultContextFilter: REF CD.ContextFilter = NEW[CD.ContextFilter];
FOR l: CD.Level IN CD.Level DO
defaultContextFilter[l].paintMode ← transparent;
defaultContextFilter[l].doit ← TRUE;
ENDLOOP;
defaultContextFilter[CD.backGround].doit ← FALSE;
END.