ArtworkInterpressImpl.mesa
Copyright © 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, August 22, 1986 3:47:04 pm PDT
Pier, October 9, 1985 2:39:15 pm PDT
Doug Wyatt, July 23, 1986 11:27:11 am PDT
DIRECTORY
Commander USING [CommandProc, Register],
Convert USING [RealFromLiteral],
FSRope USING [StreamFromRope],
FunctionCache USING [Cache, CompareProc, GlobalCache, Insert, Lookup],
Imager USING [Box, ConcatT, Context, DoSave, ScaleT, Trans, Transformation],
ImagerMemory USING [GetContextSize, NewMemoryContext, Replay],
ImagerTransformation USING [ApplyPreTranslate, Scale],
Interpress USING [DoPage, FromStream, Master],
IO USING [PutRope, RIS, STREAM],
NodeProps USING [GetProp],
NodePropsExtras USING [DeclarePropertyAttribute],
NodeStyle USING [GetBottomLeading, GetFirstIndent, GetLeftIndent, GetLineFormatting, GetLineLength, GetRightIndent, GetTopLeading, Ref],
Real USING [Round],
Rope USING [Equal, Fetch, Match, ROPE, Run, Size],
RuntimeError USING [UNCAUGHT],
Scaled USING [Float, FromReal],
TEditFormat USING [ArtworkClass, ArtworkClassRep, BoundingBoxProc, CharPositionProc, FormatProc, GetArtworkClass, PaintProc, RegisterArtwork, ResolveProc, UnRegisterArtwork],
TextEdit USING [Size],
TextNode USING [Ref],
ViewerOps USING [BlinkDisplay, PaintEverything];
ArtworkInterpressImpl: CEDAR PROGRAM
IMPORTS Commander, Convert, FSRope, FunctionCache, Imager, ImagerMemory, ImagerTransformation, Interpress, IO, NodeProps, NodePropsExtras, NodeStyle, Real, Rope, RuntimeError, Scaled, 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.GetTopLeading[nodeStyle];
box.ymin ← -NodeStyle.GetBottomLeading[nodeStyle];
box.xmax ← NodeStyle.GetLineLength[nodeStyle];
};
};
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]
};
Format: TEditFormat.FormatProc ~ {
inner: PROC ~ {
extraIndent: REAL ~ nodeStyle.GetFirstIndent;
leftIndent: REAL ~ nodeStyle.GetLeftIndent + extraIndent;
rightIndent: REAL ~ nodeStyle.GetRightIndent;
clippedLineWidth: REAL ~ PositiveMin[nodeStyle.GetLineLength, lineWidth.Float];
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[lineWidth.Float-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 {ViewerOps.BlinkDisplay[]; CONTINUE}}];
};
Resolve: TEditFormat.ResolveProc ~ {
loc ← lineInfo.startPos;
xmin ← lineInfo.xmin+lineInfo.xOffset.integerPart;
width ← lineInfo.xmax;
rightOfLine ← FALSE;
};
CharPosition: TEditFormat.CharPositionProc ~ {
x ← lineInfo.xmin+lineInfo.xOffset.integerPart;
width ← lineInfo.xmax;
};
BoundingBox: TEditFormat.BoundingBoxProc ~ {
RETURN [[lineInfo.xmin, lineInfo.ymin, lineInfo.xmax, lineInfo.ymax]]
};
debug: BOOLFALSE;
useFSRope: BOOLTRUE;
pointsPerMeter: REAL ← 72/0.0254;
memoryCache: FunctionCache.Cache ← FunctionCache.GlobalCache[];
cacheID: ROPE ~ "Art";
GetCachedMemoryContext: PROC [ipRope: ROPE] RETURNS [memory: Imager.Context] ~ {
compare: FunctionCache.CompareProc ~ {good ← argument = ipRope};
memory ← NARROW[FunctionCache.Lookup[memoryCache, compare, cacheID].value];
IF memory = NIL THEN {
ipStream: IO.STREAMIF useFSRope THEN FSRope.StreamFromRope[ipRope] ELSE IO.RIS[ipRope];
proc: PROC ~ {
ipMaster: Interpress.Master ~ Interpress.FromStream[stream: ipStream, log: NIL];
Interpress.DoPage[master: ipMaster, page: 1, context: memory, log: NIL];
};
memory ← ImagerMemory.NewMemoryContext[];
proc[ ! RuntimeError.UNCAUGHT => {IF NOT debug THEN {ViewerOps.BlinkDisplay[]; CONTINUE}}];
FunctionCache.Insert[memoryCache, ipRope, memory, ImagerMemory.GetContextSize[memory], cacheID];
};
};
Paint: TEditFormat.PaintProc ~ {
ipRope: ROPENARROW[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.DoSave[context, proc];
};
class: TEditFormat.ArtworkClass ~ NEW[TEditFormat.ArtworkClassRep ← [
name: $Interpress,
format: Format,
paint: Paint,
resolve: Resolve,
charPosition: CharPosition,
boundingBox: BoundingBox
]];
Command: Commander.CommandProc ~ {
old, new: TEditFormat.ArtworkClass ← NIL;
old ← TEditFormat.GetArtworkClass[class.name];
SELECT TRUE FROM
Rope.Match["*on*", cmd.commandLine, FALSE] => {
TEditFormat.RegisterArtwork[class];
new ← class;
};
Rope.Match["*off*", cmd.commandLine, FALSE] => {
TEditFormat.UnRegisterArtwork[class.name];
new ← NIL;
};
ENDCASE => {
cmd.out.PutRope["Please say on or off.\n"];
new ← old;
};
IF new#old THEN ViewerOps.PaintEverything[];
};
NodePropsExtras.DeclarePropertyAttribute[$Fit, $Visible];
Commander.Register["ArtworkInterpress", Command, "Turn ArtworkInterpress on or off"];
END.