ArtworkInterpressImpl.mesa
Copyright Ó 1985, 1986, 1989, 1990, 1992 by Xerox Corporation. All rights reserved.
Michael Plass, March 24, 1992 12:13 pm PST
Pier, October 9, 1985 2:39:15 pm PDT
Doug Wyatt, October 10, 1990 1:59 pm PDT
DIRECTORY
Basics USING [IsBound],
Commander USING [CommandProc, Register],
Convert USING [RealFromLiteral],
FunctionCache USING [Cache, CompareProc, GlobalCache, Insert, Lookup],
Imager USING [Box, ConcatT, Context, DoSave, ScaleT, Trans, Transformation, Warning],
ImagerMemory USING [GetContextSize, NewMemoryContext, Replay],
ImagerTransformation USING [ApplyPreTranslate, Scale],
InterpressInterpreter USING [classAppearanceError, classAppearanceWarning, classComment, classMasterError, classMasterWarning, DoPage, FromRope, LogProc, Master],
IO USING [PutFR1, PutRope, STREAM],
NodeProps USING [DeclarePropertyAttribute, GetProp],
NodeStyle USING [GetLineFormatting, GetReal, Ref],
ProcessProps USING [GetProp],
Real USING [Round],
Rope USING [Equal, Fetch, Match, ROPE, Run, Size],
RuntimeError USING [UNCAUGHT],
Scaled USING [Float, Floor, FromReal],
SimpleFeedback USING [Append, Blink],
TEditFormat,
TextEdit USING [Size],
TextNode USING [Ref],
ViewerOps USING [PaintEverything];
ArtworkInterpressImpl: CEDAR PROGRAM
IMPORTS Basics, Commander, Convert, FunctionCache, Imager, ImagerMemory, ImagerTransformation, InterpressInterpreter, IO, NodeProps, NodeStyle, ProcessProps, Real, Rope, RuntimeError, Scaled, SimpleFeedback, TEditFormat, TextEdit, ViewerOps
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
GetBounds: PROC [prop: REF, nodeStyle: NodeStyle.Ref] RETURNS [box: Imager.Box ¬ [0,0,0,0]] ~ {
rope: ROPE ~ WITH prop SELECT FROM r: ROPE => r, ENDCASE => NIL;
size: INT ~ Rope.Size[rope];
IF size # 0 THEN {
i: INT ¬ -1;
Getc: PROC RETURNS [CHAR] ~ {i¬i+1; RETURN [IF i<size THEN rope.Fetch[i] ELSE ' ]};
c: CHAR ¬ Getc[];
Invariant: c = (IF i<size THEN rope.Fetch[i] ELSE ' )
startTok: INT ¬ 0;
sizeTok: INT ¬ 0;
GetTok: PROC ~ {
startTok ¬ i;
UNTIL c = ' DO c ¬ Getc[] ENDLOOP;
sizeTok ¬ i-startTok;
WHILE c = ' AND i<size DO c ¬ Getc[] ENDLOOP;
};
Match: PROC [key: ROPE] RETURNS [BOOL] ~ {
k: INT ~ Rope.Size[key];
RETURN [sizeTok = k AND Rope.Run[rope, startTok, key, 0, FALSE] = k]
};
WHILE c = ' AND i<size DO c ¬ Getc[] ENDLOOP;
UNTIL i>=size DO
r: REAL ¬ 1.0;
IF c = '- THEN {r ¬ -r; c ¬ Getc[]};
GetTok[];
r ¬ r*Convert.RealFromLiteral[rope, startTok];
GetTok[];
SELECT TRUE FROM
Match["mm"] => r ¬ r*0.001;
Match["cm"] => r ¬ r*0.01;
Match["in"] => r ¬ r*0.0254;
Match["pt"] => r ¬ r*0.0254/72.27;
Match["bp"] => r ¬ r*0.0254/72;
ENDCASE => ERROR;
r ¬ r*pointsPerMeter;
GetTok[];
SELECT TRUE FROM
Match["xmin"] => box.xmin ¬ r;
Match["xmax"] => box.xmax ¬ r;
Match["ymin"] => box.ymin ¬ r;
Match["ymax"] => box.ymax ¬ r;
ENDCASE => ERROR;
ENDLOOP;
}
ELSE {
box.ymax ¬ NodeStyle.GetReal[nodeStyle, $topLeading];
box.ymin ¬ -NodeStyle.GetReal[nodeStyle, $bottomLeading];
box.xmax ¬ NodeStyle.GetReal[nodeStyle, $lineLength];
};
};
Floor: PROC [r: REAL] RETURNS [i: INT] ~ {
i ¬ Real.Round[r];
IF i > r THEN i ¬ i-1;
};
Ceiling: PROC [r: REAL] RETURNS [i: INT] ~ {
i ¬ Real.Round[r];
IF i < r THEN i ¬ i+1;
};
PositiveMin: PROC [a, b: REAL] RETURNS [REAL] ~ {
IF a < 0 THEN RETURN [MAX[b, 0.01]];
IF b < 0 THEN RETURN [a];
RETURN [MIN[a, b]]
};
HasFit: PROC [node: TextNode.Ref] RETURNS [BOOL] ~ {
WITH NodeProps.GetProp[n: node, name: $Fit] SELECT FROM
b: REF BOOL => RETURN [b­];
rope: ROPE => RETURN [Rope.Equal[rope, "TRUE"]];
ENDCASE => RETURN [FALSE];
};
DetermineScaleFactor: PROC [box: Imager.Box, lineWidth: REAL] RETURNS [REAL] ~ {
size: REAL ~ MAX[box.xmax-box.xmin, 1];
scaleFactor: REAL ~ lineWidth/size;
RETURN [scaleFactor]
};
ReportUncaught: PROC [who: Rope.ROPE] ~ {
SimpleFeedback.Append[$Artwork, begin, $Error,
"Artwork Interpress UNCAUGHT ERROR during "];
SimpleFeedback.Append[$Artwork, end, $Error, who];
SimpleFeedback.Blink[$Artwork, $Error];
};
Format: TEditFormat.FormatProc ~ {
inner: PROC ~ {
extraIndent: REAL ~ nodeStyle.GetReal[$firstIndent];
leftIndent: REAL ~ nodeStyle.GetReal[$leftIndent] + extraIndent;
rightIndent: REAL ~ nodeStyle.GetReal[$rightIndent];
clippedLineWidth: REAL ~ PositiveMin[nodeStyle.GetReal[$lineLength], Scaled.Float[lineWidth]];
trimmedLineWidth: REAL ~ MAX[clippedLineWidth-leftIndent-rightIndent, 0];
box: Imager.Box ¬ GetBounds[NodeProps.GetProp[n: node, name: $Bounds], nodeStyle];
lineInfo.artworkData ¬ NIL;
IF HasFit[node] THEN {
scaleFactor: REAL ~ DetermineScaleFactor[box, trimmedLineWidth];
m: Imager.Transformation ¬ ImagerTransformation.Scale[scaleFactor];
ImagerTransformation.ApplyPreTranslate[m, [-box.xmin, -box.ymin]];
box.xmax ¬ (box.xmax-box.xmin)*scaleFactor;
box.ymax ¬ (box.ymax-box.ymin)*scaleFactor;
box.xmin ¬ 0;
box.ymin ¬ 0;
lineInfo.artworkData ¬ m;
};
lineInfo.xmin ¬ Floor[box.xmin];
lineInfo.ymin ¬ Floor[box.ymin];
lineInfo.xmax ¬ Ceiling[box.xmax];
lineInfo.ymax ¬ Ceiling[box.ymax];
SELECT nodeStyle.GetLineFormatting[] FROM
FlushLeft => {lineInfo.xOffset ¬ Scaled.FromReal[leftIndent]};
FlushRight => {lineInfo.xOffset ¬ Scaled.FromReal[MAX[Scaled.Float[lineWidth]-leftIndent-box.xmax, 0]]};
Centered, Justified => {lineInfo.xOffset ¬ Scaled.FromReal[leftIndent+(trimmedLineWidth-box.xmax)/2]};
ENDCASE => ERROR;
};
lineInfo.startPos ¬ [node, 0];
lineInfo.nextPos ¬ [node, TextEdit.Size[node]];
lineInfo.nChars ¬ TextEdit.Size[node];
inner[ ! RuntimeError.UNCAUGHT =>
IF NOT debug THEN { ReportUncaught["Format"]; CONTINUE };
];
};
Resolve: TEditFormat.ResolveProc ~ {
loc ¬ lineInfo.startPos;
xmin ¬ lineInfo.xmin+Scaled.Floor[lineInfo.xOffset];
width ¬ lineInfo.xmax;
rightOfLine ¬ FALSE;
};
CharPosition: TEditFormat.CharPositionProc ~ {
x ¬ lineInfo.xmin+Scaled.Floor[lineInfo.xOffset];
width ¬ lineInfo.xmax;
};
BoundingBox: TEditFormat.BoundingBoxProc ~ {
RETURN [[lineInfo.xmin, lineInfo.ymin, lineInfo.xmax, lineInfo.ymax]]
};
debug: BOOL ¬ FALSE;
useFSRope: BOOL ¬ TRUE;
pointsPerMeter: REAL ¬ 72/0.0254;
memoryCache: FunctionCache.Cache ¬ FunctionCache.GlobalCache[];
cacheID: ROPE ~ "Art";
GetCachedMemoryContext: PROC [ipRope: ROPE] RETURNS [memory: Imager.Context] ~ {
Log: InterpressInterpreter.LogProc = {
[class: INT, code: ATOM, explanation: ROPE]
tag: ROPE ~ SELECT class FROM
InterpressInterpreter.classMasterError => "Artwork Interpress Master Error: ",
InterpressInterpreter.classMasterWarning => "Artwork Interpress Master Warning: ",
InterpressInterpreter.classAppearanceError => "Artwork Interpress Appearance Error: ",
InterpressInterpreter.classAppearanceWarning => "Artwork Interpress Appearance Warning: ",
InterpressInterpreter.classComment => "Artwork Interpress Comment: ",
ENDCASE => IO.PutFR1["Artwork Interpress Error class %g: ", [integer[class]]];
WITH ProcessProps.GetProp[$StdOut] SELECT FROM
errout: IO.STREAM => {
IO.PutRope[errout, tag];
IO.PutRope[errout, explanation];
IO.PutRope[errout, "\n"];
};
ENDCASE => {
msgClass: ATOM ~ SELECT class FROM
InterpressInterpreter.classMasterError => $Error,
InterpressInterpreter.classMasterWarning => $Warning,
InterpressInterpreter.classAppearanceError => $Error,
InterpressInterpreter.classAppearanceWarning => $Warning,
InterpressInterpreter.classComment => $Comment,
ENDCASE => $Error;
SimpleFeedback.Append[$Artwork, begin, msgClass, tag];
SimpleFeedback.Append[$Artwork, end, msgClass, explanation];
};
};
compare: FunctionCache.CompareProc ~ {good ¬ argument = ipRope};
memory ¬ NARROW[FunctionCache.Lookup[memoryCache, compare, cacheID].value];
IF memory = NIL THEN {
proc: PROC ~ {
ipMaster: InterpressInterpreter.Master ~ InterpressInterpreter.FromRope[rope: ipRope, log: Log];
InterpressInterpreter.DoPage[master: ipMaster, page: 1, context: memory, log: Log];
};
memory ¬ ImagerMemory.NewMemoryContext[];
proc[ ! RuntimeError.UNCAUGHT =>
IF NOT debug THEN { ReportUncaught["GetCachedMemoryContext"]; CONTINUE };
];
FunctionCache.Insert[memoryCache, ipRope, memory, ImagerMemory.GetContextSize[memory], cacheID];
};
};
Paint: TEditFormat.PaintProc ~ {
prevMsg: ROPE ¬ NIL;
ipRope: ROPE ¬ NARROW[NodeProps.GetProp[lineInfo.startPos.node, $Interpress]];
compare: FunctionCache.CompareProc ~ {good ¬ argument = ipRope};
memory: Imager.Context ~ GetCachedMemoryContext[ipRope];
proc: PROC ~ {
Imager.Trans[context];
WITH lineInfo.artworkData SELECT FROM
m: Imager.Transformation => Imager.ConcatT[context, m];
ENDCASE => NULL;
Imager.ScaleT[context, pointsPerMeter];
ImagerMemory.Replay[c: memory, into: context !
Imager.Warning => {
IF error.explanation # prevMsg THEN {
SimpleFeedback.Append[$Artwork, begin, $Warning, "Artwork Interpress Warning: "];
SimpleFeedback.Append[$Artwork, end, $Warning, error.explanation];
prevMsg ¬ error.explanation;
};
RESUME;
};
];
};
Imager.DoSave[context, proc ! RuntimeError.UNCAUGHT =>
IF NOT debug THEN { ReportUncaught["Paint"]; CONTINUE };
];
};
class: TEditFormat.ArtworkClass ~ NEW[TEditFormat.ArtworkClassRep ¬ [
name: $Interpress,
format: Format,
paint: Paint,
resolve: Resolve,
charPosition: CharPosition,
boundingBox: BoundingBox
]];
Command: Commander.CommandProc ~ {
oldState: BOOL ¬ TEditFormat.ArtworkEnabled[];
newState: BOOL ¬ oldState;
SELECT TRUE FROM
Rope.Match["*on*", cmd.commandLine, FALSE] => {
newState ¬ TRUE;
};
Rope.Match["*off*", cmd.commandLine, FALSE] => {
newState ¬ FALSE;
};
ENDCASE => {
cmd.out.PutRope["Please say on or off.\n"];
};
oldState ¬ TEditFormat.SetArtworkEnabled[newState];
IF newState#oldState AND Basics.IsBound[ViewerOps.PaintEverything] THEN ViewerOps.PaintEverything[];
};
NodeProps.DeclarePropertyAttribute[$Interpress, $ClientOnly];
NodeProps.DeclarePropertyAttribute[$Fit, $Visible];
TEditFormat.RegisterArtwork[class];
Commander.Register["Artwork", Command, "Turn Artwork on or off"];
Commander.Register["ArtworkInterpress", Command, "Turn Artwork on or off"];
END.