JaMImagerImpl.mesa
Last changed by Maureen Stone March 3, 1984 4:08:09 pm PST
Michael Plass, February 20, 1984 12:29:37 pm PST
DIRECTORY
Imager,
ImagerBasic USING [Rectangle, State, StateRep],
ImagerBridge USING [SetViewFromGraphicsContext],
ImagerTransform USING [InverseTransform, Invert, TransformRectangle, TransformationRec, FromRec],
Font,
Real USING [LargestNumber],
Graphics USING [Context],
CGVector USING [Vec, Sub, Cross],
Rope USING [ActionType, Match, Fetch, Cat, Map, Length, ROPE],
ViewerOps USING[PaintViewer],
ViewerClasses USING [Viewer],
JaM USING [State, PopInt, PushReal, PopReal, PopRope, Register],
JaMImager,
JaMImagerContexts,
JaMIPrivate;
JaMImagerImpl: CEDAR MONITOR
IMPORTS ImagerBridge, JaM, JaMImager, JP: JaMIPrivate, Imager, ImagerTransform, Font, CGVector, Rope, ViewerOps, JaMImagerContexts
EXPORTS JaMImager, JaMIPrivate = {
Vec: TYPE = CGVector.Vec;
GProc: TYPE = JaMImagerContexts.GProc;
FONT: TYPE = Imager.FONT;
ROPE: TYPE = Rope.ROPE;
State: TYPE = JaM.State;
Info: TYPE = JP.Info;
GetVec: PROCEDURE [state: State] RETURNS[Vec] = {
y: REAL ← JaM.PopReal[state];
x: REAL ← JaM.PopReal[state];
RETURN[[x,y]];
};
GetPoint: PROCEDURE [state: State] RETURNS[x,y: REAL] = {
y ← JaM.PopReal[state]; x ← JaM.PopReal[state]; RETURN[x,y] };
PutPoint: PROCEDURE[state: State, x,y: REAL] = {
JaM.PushReal[state,x]; JaM.PushReal[state,y] };
Box: TYPE = RECORD[xmin,ymin,xmax,ymax,w,h: REAL];
GetBox: PROC [state: State] RETURNS[Box] = {
b: Box;
[b.xmax,b.ymax] ← GetPoint[state];
[b.xmin,b.ymin] ← GetPoint[state];
IF b.ymax< b.ymin THEN {t: REAL ← b.ymin; b.ymin ← b.ymax; b.ymax ← t};
IF b.xmax< b.xmin THEN {t: REAL ← b.xmin; b.xmin ← b.xmax; b.xmax ← t};
b.w ← b.xmax-b.xmin;
b.h ← b.ymax-b.ymin;
RETURN[b];
};
PutFontBox: PROCEDURE[state: State, b: Font.Box] = {
PutPoint[state,b.xmin,b.ymin];
PutPoint[state,b.xmax,b.ymax];
};
ViewToUser: PUBLIC PROC[context: Imager.Context, vx,vy: REAL] RETURNS [x,y: REAL] = {
transformation: Imager.Transformation ← context.state.T;
[[x,y]] ← ImagerTransform.InverseTransform[p: [vx,vy], transform: transformation];
};
ViewToUserRectangle: PROC[context: Imager.Context, vBox: ImagerBasic.Rectangle] RETURNS [uBox: ImagerBasic.Rectangle] = {
transformation: Imager.Transformation ← context.state.T;
uBox ← ImagerTransform.TransformRectangle[rect: vBox, transform: ImagerTransform.Invert[transformation]];
};
Paint: PUBLIC ENTRY SAFE PROCEDURE [self: ViewerClasses.Viewer, context: Graphics.Context,
whatChanged: REF ANY, clear: BOOL] = TRUSTED {
ENABLE UNWIND => NULL;
info: Info ← NARROW[self.data];
IF whatChanged=NIL THEN { -- reset context
--a priori knowledge of World and Viewer coordinates makes this work
ImagerBridge.SetViewFromGraphicsContext[info.vdc, context];
Imager.Reset[info.vdc];
Imager.ConcatT[info.vdc, Imager.pointsToMeters]; --we like to think in points
info.vw ← self.cw;
info.vh ← self.ch;
}
ELSE info.proc[info.vdc];
};
Painter: PUBLIC PROCEDURE[proc: PROC [Imager.Context], state: State] = {
info: Info ← JP.GetInfo[state];
SetProc: PROC = TRUSTED {info.proc ← proc};
JaMImagerContexts.ForAllDCs[info.dcList,proc];
IF info.venabled THEN {
SetProc[]; --safe version of info.proc ← proc;
ViewerOps.PaintViewer[viewer: info.viewer, hint: client, whatChanged: info, clearClient: FALSE];
};
};
stateStack: LIST OF ImagerBasic.State;
PushDC: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
new: ImagerBasic.State ← NEW[ImagerBasic.StateRep ← info.vdc.state^];
we will only restore some of this. Look at PopDC for details
stateStack ← CONS[new,stateStack];
};
PopDC: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
old: ImagerBasic.State;
IF stateStack#NIL THEN old ← stateStack.first ELSE RETURN;
stateStack ← stateStack.rest;
info.vdc.state.T ← old.T;
info.vdc.state.priorityImportant← old.priorityImportant;
info.vdc.state.color← old.color;
info.vdc.state.noImage← old.noImage;
info.vdc.state.strokeWidth← old.strokeWidth;
info.vdc.state.strokeEnd← old.strokeEnd;
info.vdc.state.clipper ← old.clipper;
};
JClipArea: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
paint: GProc ={Imager.ClipOutline[context: dc, outline: Imager.MakeOutline[info.trajectory]]};
Painter[paint,state];
};
JClipBox: PROCEDURE [state: State] = {
paint: GProc ={Imager.ClipRectangle[dc, box.xmin, box.ymin, box.w, box.h]};
box: Box ← GetBox[state];
Painter[paint,state];
};
JClipXArea: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
paint: GProc ={Imager.ExcludeOutline[dc, Imager.MakeOutline[info.trajectory]]};
Painter[paint,state];
};
JClipXBox: PROCEDURE [state: State] = {
paint: GProc ={Imager.ExcludeRectangle[dc, box.xmin, box.ymin, box.w, box.h]};
box: Box ← GetBox[state];
Painter[paint,state];
};
JTranslate: PROCEDURE [state: State] = {
paint: GProc ={Imager.TranslateT[dc,tx,ty]};
tx,ty: REAL;
[tx,ty]←GetPoint[state];
Painter[paint,state];
};
JScale: PROCEDURE [state: State] = {
paint: GProc ={ Imager.Scale2T[dc,sx,sy]};
sx,sy: REAL;
[sx,sy]←GetPoint[state];
Painter[paint,state];
};
JRotate: PROCEDURE [state: State] = {
paint: GProc ={Imager.RotateT[dc,a]};
a: REAL ← JaM.PopReal[state];
Painter[paint,state];
};
JSixPoint: PROCEDURE [state: State] = {
paint: GProc ={
Imager.TranslateT[dc,t1.x,t1.y];
Imager.ConcatT[dc,t.FromRec];
Imager.TranslateT[dc,-f1.x,-f1.y];
};
f1,f2,f3,t1,t2,t3,df1,df2,dt1,dt2: Vec;
adet: REAL;
t: ImagerTransform.TransformationRec ← [0,0,0,0,0,0];
t3←GetVec[state];
t2←GetVec[state];
t1←GetVec[state];
f3←GetVec[state];
f2←GetVec[state];
f1←GetVec[state];
dt1𡤌GVector.Sub[t2,t1];
df1𡤌GVector.Sub[f2,f1];
dt2𡤌GVector.Sub[t3,t1];
df2𡤌GVector.Sub[f3,f1];
adet𡤁.0/CGVector.Cross[df1,df2];
t.a←(dt1.x*df2.y-dt2.x*df1.y)*adet; --m11
t.d←(dt1.y*df2.y-dt2.y*df1.y)*adet;  --m12
t.b←(df1.x*dt2.x-df2.x*dt1.x)*adet; --m21
t.e←(df1.x*dt2.y-df2.x*dt1.y)*adet; --m22
Painter[paint,state];
};
JConcat: PROCEDURE [state: State] = {
paint: GProc ={Imager.ConcatT[dc,t.FromRec]};
t: ImagerTransform.TransformationRec ← [0,0,0,0,0,0];
t.e ← JaM.PopReal[state]; --m22
t.b ← JaM.PopReal[state]; --m21
t.d ← JaM.PopReal[state]; --m12
t.a ← JaM.PopReal[state]; --m11
Painter[paint,state];
};
note multiple display context behavior
JGetPos: PROCEDURE [state: State] = {
paint: GProc ={[[x,y]] ← Imager.GetCP[dc]};
x,y: REAL;
Painter[paint,state];
PutPoint[state,x,y];
};
JSetPos: PROCEDURE [state: State] = {
paint: GProc ={Imager.SetXY[dc,[x,y]]};
x,y: REAL; [x,y] ← GetPoint[state];
Painter[paint,state];
};
JRelSetPos: PROCEDURE [state: State] = {
paint: GProc ={ Imager.SetXYRel[dc,[x,y]]};
x,y: REAL;
[x,y]←GetPoint[state];
Painter[paint,state];
};
JDrawTo: PROCEDURE [state: State] = {
paint: GProc ={
x0,y0: REAL;
[[x0,y0]] ← Imager.GetCP[dc];
Imager.MaskVector[dc,[x0,y0],[x,y]];
Imager.SetXY[dc,[x,y]];
};
x,y: REAL;
[x,y]←GetPoint[state];
Painter[paint,state];
};
JRelDrawTo: PROCEDURE [state: State] = {
paint: GProc ={
x0,y0: REAL;
[[x0,y0]] ← Imager.GetCP[dc];
Imager.MaskVector[dc,[x0,y0],[x0+x,y0+y]];
Imager.SetXY[dc,[x0+x,y0+y]];
};
x,y: REAL;
[x,y]←GetPoint[state];
Painter[paint,state];
};
JDrawBox: PROCEDURE [state: State] = {
paint: GProc ={Imager.MaskRectangle[dc,box.xmin,box.ymin,box.w,box.h]};
box: Box ← GetBox[state];
Painter[paint,state];
};
JCover: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
paint: GProc ={
box: ImagerBasic.Rectangle ← ViewToUserRectangle[dc,[x:0, y:0, w: info.vw, h: info.vh]]; --only works for viewers
Imager.MaskRectangle[dc, box.x, box.y, box.w, box.h];
};
Painter[paint,state];
};
Erase: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
paint: GProc ={
erase: SAFE PROC = TRUSTED {
box: ImagerBasic.Rectangle ← ViewToUserRectangle[dc,[x:0, y:0, w: info.vw, h: info.vh]]; --only works for viewers
Imager.SetColor[dc, Imager.white];
Imager.MaskRectangle[dc, box.x, box.y, box.w, box.h];
};
Imager.DoSaveAll[dc,erase];
};
FOR l: JaMImagerContexts.DCList ← info.dcList, l.next UNTIL l=NIL DO
IF l.enabled THEN l.dc ← l.callMe[l.dc, erase];
ENDLOOP;
JaMImager.Painter[paint,state];
};
JSetInvert: PROCEDURE [state: State] = {
paint: GProc ={[] ← Imager.SetColor[dc, Imager.XOR]};
Painter[paint,state];
};
defaultPath: ROPE ← "Xerox/PressFonts/";
defaultFace: ROPE ← "/MRR";
JSetFont: PROCEDURE [state: State] = {
size: REAL ← JaM.PopReal[state];
name: ROPE ← JaM.PopRope[state];
IF ~Rope.Match["*/*",name] THEN name ← Rope.Cat[defaultPath,name,defaultFace];
JP.GetInfo[state].font ← Imager.MakeFont[name,size];
};
JDrawChar: PROCEDURE [state: State] = {
paint: GProc ={Imager.ShowChar[context: dc, char: char, font: info.font]};
info: Info ← JP.GetInfo[state];
char: CHAR ← Rope.Fetch[JaM.PopRope[state]];
Painter[paint,state];
};
JDrawText: PROCEDURE [state: State] = {
paint: GProc ={Imager.ShowCharacters[context: dc, characters: rope, font: info.font]};
info: Info ← JP.GetInfo[state];
rope: ROPE ← JaM.PopRope[state];
Painter[paint,state];
};
JCharBox: PROCEDURE [state: State] = {
PutFontBox[state,
Font.BoundingBox[font: JP.GetInfo[state].font, char: Rope.Fetch[JaM.PopRope[state]]]];
};
JFontBox: PROCEDURE [state: State] = {
PutFontBox[state, Font.FontBoundingBox[JP.GetInfo[state].font]];
};
JTextBox: PROCEDURE [state: State] = {
PutFontBox[state, RopeBox[JP.GetInfo[state].font, JaM.PopRope[state]]];
};
JCharWidth: PROCEDURE [state: State] = {
x,y: REAL;
[[x,y]] ← Font.WidthVector[font: JP.GetInfo[state].font, char: Rope.Fetch[JaM.PopRope[state]]];
PutPoint[state,x,y];
};
JTextWidth: PROCEDURE [state: State] = {
x,y: REAL;
[x,y] ← RopeWidth[JP.GetInfo[state].font, JaM.PopRope[state]];
PutPoint[state,x,y];
};
RopeBox: PROC[font: FONT, rope: ROPE] RETURNS[ropeBox: Font.Box]= {
collect: Rope.ActionType = TRUSTED {
box: Font.Box ← Font.BoundingBox[font: font, char: c];
ropeBox.xmin ← MIN[ropeBox.xmin,box.xmin];
ropeBox.ymin ← MIN[ropeBox.ymin,box.ymin];
ropeBox.xmax ← MAX[ropeBox.xmax,box.xmax];
ropeBox.ymax ← MAX[ropeBox.ymax,box.ymax];
};
ropeBox ← [xmin: Real.LargestNumber, ymin: Real.LargestNumber, xmax: 0, ymax: 0];
[] ← Rope.Map[base: rope, action: collect, len: Rope.Length[rope]];
};
RopeWidth: PROC[font: FONT, rope: ROPE] RETURNS[wx,wy: REAL]= {
collect: Rope.ActionType = TRUSTED {
vec: Font.Pair ← Font.WidthVector[font: font, char: c];
wx ← wx+vec.x;
wy ← wy+vec.y;
};
wx ← wy ← 0;
[] ← Rope.Map[base: rope, action: collect, len: Rope.Length[rope]];
};
JFlushPath: PROCEDURE [state: State] = {
JP.GetInfo[state].trajectory ← NIL;
};
JMoveTo: PROCEDURE [state: State] = {
x,y: REAL;
[x,y]←GetPoint[state];
JP.GetInfo[state].trajectory ← LIST[Imager.MoveTo[[x,y]]];
};
JMoveToNext: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
x,y: REAL; [x,y]←GetPoint[state];
info.trajectory ← CONS[Imager.MoveTo[[x,y]],info.trajectory];
};
JLineTo: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
x,y: REAL; [x,y]←GetPoint[state];
IF info.trajectory=NIL THEN info.trajectory ← LIST[Imager.MoveTo[[0,0]]];
info.trajectory.first ← Imager.LineTo[info.trajectory.first,[x,y]];
};
JCurveTo: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
x1,y1,x2,y2,x3,y3: REAL;
[x3,y3]←GetPoint[state];
[x2,y2]←GetPoint[state];
[x1,y1]←GetPoint[state];
IF info.trajectory=NIL THEN info.trajectory ← LIST[Imager.MoveTo[[0,0]]];
info.trajectory.first ← Imager.CurveTo[info.trajectory.first,[x1,y1],[x2,y2],[x3,y3]];
};
JRectangle: PROCEDURE [state: State] = {
box: Box ← GetBox[state];
paint: GProc = {Imager.MaskRectangle[dc, box.xmin,box.ymin,box.w,box.h]};
Painter[paint,state];
};
JDrawArea: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
paint: GProc = {Imager.MaskFill[dc, Imager.MakeOutline[info.trajectory]]};
Painter[paint,state];
};
JDrawStroke: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
paint: GProc = {Imager.MaskStroke[dc,info.trajectory.first,width,ends]};
i: INT ← JaM.PopInt[state];
width: REAL ← JaM.PopReal[state];
ends: Imager.StrokeEnd ← (IF i=1 THEN square ELSE IF i=2 THEN round ELSE butt);
IF info.trajectory#NIL THEN Painter[paint,state];
};
JDrawStrokeClosed: PROCEDURE [state: State] = {
info: Info ← JP.GetInfo[state];
paint: GProc = {Imager.MaskStrokeClosed[dc,info.trajectory.first,width]};
width: REAL ← JaM.PopReal[state];
IF info.trajectory#NIL THEN Painter[paint,state];
};
Initialization starts here
RegisterGraphics: PUBLIC PROC[state: State] = {
JaM.Register[state,".pushdc",PushDC];
JaM.Register[state,".popdc",PopDC];
JaM.Register[state,".translate",JTranslate];
JaM.Register[state,".scale",JScale];
JaM.Register[state,".rotate",JRotate];
JaM.Register[state,".sixpoint",JSixPoint];
JaM.Register[state,".concat",JConcat];
JaM.Register[state,".getpos",JGetPos];
JaM.Register[state,".setpos",JSetPos];
JaM.Register[state,".rsetpos",JRelSetPos];
JaM.Register[state,".drawto",JDrawTo];
JaM.Register[state,".rdrawto",JRelDrawTo];
JaM.Register[state,".drawbox",JDrawBox];
JaM.Register[state,".cover",JCover];
JaM.Register[state,".erase",Erase];
JaM.Register[state,".setinvert",JSetInvert];
JaM.Register[state,".setfont",JSetFont];
JaM.Register[state,".drawchar",JDrawChar];
JaM.Register[state,".drawtext",JDrawText];
JaM.Register[state,".charbox",JCharBox];
JaM.Register[state,".textbox",JTextBox];
JaM.Register[state,".charwidth",JCharWidth];
JaM.Register[state,".textwidth",JTextWidth];
JaM.Register[state,".fontbox",JFontBox];
JaM.Register[state,".cliparea",JClipArea];
JaM.Register[state,".clipbox",JClipBox];
JaM.Register[state,".clipxarea",JClipXArea];
JaM.Register[state,".clipxbox",JClipXBox];
JaM.Register[state,".flushpath",JFlushPath];
JaM.Register[state,".moveto",JMoveTo];
JaM.Register[state,".movetonext",JMoveToNext];
JaM.Register[state,".lineto",JLineTo];
JaM.Register[state,".curveto",JCurveTo];
JaM.Register[state,".rect",JRectangle];
JaM.Register[state,".drawarea",JDrawArea];
JaM.Register[state,".drawstroke",JDrawStroke];
JaM.Register[state,".drawstrokeclosed",JDrawStrokeClosed];
};
}.
JGetYMode: PROCEDURE [state: State] = {
paint: GProc ={mode ← ImagerOps.GetYMode[dc]};
mode: ImagerOps.YMode;
Painter[paint,state];
JaM.PushInteger[state, IF mode=topDown THEN 1 ELSE 0];
};
JSetYMode: PROCEDURE [state: State] = {
mode: LONG INTEGER ← JaM.PopInt[state];
paint: GProc ={ImagerOps.SetYMode[dc,IF mode>0 THEN topDown ELSE bottomUp]};
Painter[paint,state];
};
JStartBoxing: PROCEDURE [state: State] = {
info: Info ← GetInfo[state];
ImagerOps.BeginBox[dc];
};
JStopBoxing: PROCEDURE [state: State] = {
info: Info ← GetInfo[state];
b: Imager.Box ← ImagerOps.EndBox[dc];
PutBox[state,b];
};
JPushBox: PROCEDURE [state: State] = {
b: Imager.Box ← GetBox[state];
Imager.PushClipBox[dc,b];
**** temporarily removed ****
};
JPopBox: PROCEDURE [state: State] = {
Imager.PopClipBox[dc];
**** temporarily removed ****
};
PutBox: PROC[state: State, b: Box] = {
PutPoint[state,b.xmin,b.ymin];
PutPoint[state,b.xmax,b.ymax];
};
JDrawEOArea: PROCEDURE [state: State] = {
info: Info ← GetInfo[state];
paint: GProc = {Imager.DrawArea[dc,info.trajectory,TRUE]};
Painter[paint,state];
};
GetRect: PROCEDURE [state: State] RETURNS[r: Rect] = {
[r.xmax,r.ymax] ← GetPoint[state];
[r.xmin,r.ymin] ← GetPoint[state];
RETURN[r];
};
PutRect: PROCEDURE[state: State, r: Rect] = {
PutPoint[state,r.xmin,r.ymin];
PutPoint[state,r.xmax,r.ymax];
};
JSetFat: PROCEDURE [state: State] = {
paint: GProc ={[] ← Imager.SetFat[dc,b]};
b: BOOLEAN ← JaM.PopBoolean[state];
Painter[paint,state];
};
JSetOpaque: PROCEDURE [state: State] = {
paint: GProc ={[] ← Imager.SetPaintMode[dc,IF b THEN opaque ELSE transparent]};
b: BOOLEAN ← JaM.PopBoolean[state];
Painter[paint,state];
};
JVisible: PROCEDURE [state: State] = {
b: BOOLEAN;
paint: GProc = {b ← Imager.Visible[dc]};
Painter[paint,state];
JaM.PushBoolean[state,b];
};
JScreenCoords: PROCEDURE [state: State] = {
y: REAL ← JaM.PopReal[state];
x: REAL ← JaM.PopReal[state];
paint: GProc = {[x, y] ← Imager.UserToWorld[dc, x, y]}; -- get screen coordinates
Painter[paint,state];
JaM.PushReal[state,x];
JaM.PushReal[state,y];
};
JUserCoords: PROCEDURE [state: State] = {
y: REAL ← JaM.PopReal[state];
x: REAL ← JaM.PopReal[state];
paint: GProc = {[x, y] ← Imager.WorldToUser[dc, x, y]}; -- get user coordinates
Painter[paint,state];
JaM.PushReal[state,x];
JaM.PushReal[state,y];
};
JKnot: PROCEDURE [state: State] = {
info: Info ← GetInfo[state];
y: REAL ← JaM.PopReal[state];
x: REAL ← JaM.PopReal[state];
Spline.Knot[info.spline,x,y];
};
JSpline: PROCEDURE [state: State] = {
info: Info ← GetInfo[state];
Spline.Enter[info.spline,info.trajectory,FALSE];
};
JCSpline: PROCEDURE [state: State] = {
info: Info ← GetInfo[state];
Spline.Enter[info.spline,info.trajectory,TRUE];
};
JaM.Register[state,".setview",JSetVw];
JaM.Register[state,".setfat",JSetFat];
JaM.Register[state,".setopaque",JSetOpaque];
JaM.Register[state,".initboxer",JStartBoxing];
JaM.Register[state,".stopboxer",JStopBoxing];
JaM.Register[state,".pushbox",JPushBox];
JaM.Register[state,".popbox",JPopBox];
JaM.Register[state,".visible",JVisible];
JaM.Register[state,".setymode",JSetYMode];
JaM.Register[state,".getymode",JGetYMode];
JaM.Register[state,".screencoords",JScreenCoords];
JaM.Register[state,".usercoords",JUserCoords];
JaM.Register[state,".settarget",JSetTarget];
JaM.Register[state,".draweoarea",JDrawEOArea];
JaM.Register[state,".clipeoarea",JClipEOArea];
JaM.Register[state,".bitmap",JBitmap];
JaM.Register[state,".knot",JKnot];
JaM.Register[state,".spline",JSpline];
JaM.Register[state,".cspline",JCSpline];