ImagerStateImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Michael Plass, March 19, 1984 5:16:59 pm PST
Doug Wyatt, May 12, 1985 4:00:10 pm PDT
DIRECTORY
Imager USING [Context, DoSaveAll, Error, MakeGray, MaskRectangle, SetXY, Trans],
ImagerBackdoor USING [Clipper, IntKey, RealKey],
ImagerColor USING [Color, MakeSampledColor],
ImagerColorOperator USING [BlackColorModel, ColorOperator],
ImagerFont USING [Font, MapText, XChar, XStringProc],
ImagerPath USING [Outline, OutlineFromPath, PathProc],
ImagerPixelArray USING [PixelArray],
ImagerPrivate USING [StrokeDashes],
ImagerState USING [AndChangeFlags, ChangeFlags, NonPersistentVariables, notChanged, OrChangeFlags, PersistentVariables, State, StateRep],
ImagerTransformation USING [ApplyPreConcat, ApplyPreRotate, ApplyPreScale2, ApplyPreTranslate, ApplyTranslateTo, Concat, DRound, InverseTransform, Rectangle, Transform, Transformation, TransformationRep, TransformVec],
Rope USING [ROPE],
Vector2 USING [Add, Div, InlineAdd, InlineMulC, Length, Mul, Sub, VEC];
ImagerStateImpl: CEDAR PROGRAM
IMPORTS Imager, ImagerColor, ImagerColorOperator, ImagerFont, ImagerPath, ImagerState, ImagerTransformation, Vector2
EXPORTS Imager, ImagerState
~ BEGIN OPEN ImagerState;
Context: TYPE ~ Imager.Context;
State: TYPE ~ ImagerState.State;
StateRep: PUBLIC TYPE ~ ImagerState.StateRep; -- export to Imager.StateRep
ROPE: TYPE ~ Rope.ROPE;
VEC: TYPE ~ Vector2.VEC;
Transformation: TYPE ~ ImagerTransformation.Transformation;
TransformationRep: TYPE ~ ImagerTransformation.TransformationRep;
Rectangle: TYPE ~ ImagerTransformation.Rectangle;
Font: TYPE ~ ImagerFont.Font;
XChar: TYPE ~ ImagerFont.XChar;
XStringProc: TYPE ~ ImagerFont.XStringProc;
Color: TYPE ~ ImagerColor.Color;
ColorOperator: TYPE ~ ImagerColorOperator.ColorOperator;
PixelArray: TYPE ~ ImagerPixelArray.PixelArray;
PathProc: TYPE ~ ImagerPath.PathProc;
Outline: TYPE ~ ImagerPath.Outline;
Clipper: TYPE ~ ImagerBackdoor.Clipper;
StrokeDashes: TYPE ~ ImagerPrivate.StrokeDashes;
Changed: PROC[state: State, changed: ChangeFlags] ~ INLINE {
state.changed ← OrChangeFlags[state.changed, changed];
state.np.changed ← OrChangeFlags[state.np.changed, changed];
};
refChanges: ChangeFlags ~ [T: TRUE, font: TRUE, color: TRUE, clipper: TRUE];
StateDoSave: PUBLIC PROC[context: Context, action: PROC, all: BOOLFALSE] ~ {
state: State ~ context.state;
p: PersistentVariables ~ state.p;
np: NonPersistentVariables ~ state.np;
T: TransformationRep ~ state.T^;
font: Font ~ state.font;
color: Color ~ state.color;
clipper: Clipper ~ state.clipper;
strokeDashes: StrokeDashes ~ state.strokeDashes;
Restore: PROC ~ {
state.changed ← OrChangeFlags[state.changed, state.np.changed];
IF all THEN state.p ← p;
state.np ← np;
state.T^ ← T;
state.font ← font;
state.color ← color;
state.clipper ← clipper;
state.strokeDashes ← strokeDashes;
};
state.np.changed ← notChanged;
action[! UNWIND => Restore[]];
IF AndChangeFlags[state.np.changed, refChanges]=notChanged THEN {
state.changed ← OrChangeFlags[state.changed, state.np.changed];
IF all THEN state.p ← p;
state.np ← np;
}
ELSE Restore[];
};
StateSetInt: PUBLIC PROC[context: Context, key: ImagerBackdoor.IntKey, val: INT] ~ {
state: State ~ context.state;
SELECT key FROM
priorityImportant => { state.np.priorityImportant ← val; Changed[state, [priority: TRUE]] };
noImage => state.np.noImage ← val;
strokeEnd => state.np.strokeEnd ← val;
strokeJoint => state.np.strokeJoint ← val;
correctPass => state.np.correctPass ← val;
ENDCASE => ERROR Imager.Error[[$unimplemented, "Unknown IntKey"]];
};
StateSetReal: PUBLIC PROC[context: Context, key: ImagerBackdoor.RealKey, val: REAL] ~ {
state: State ~ context.state;
SELECT key FROM
DCScpx => state.p.cp.x ← val;
DCScpy => state.p.cp.y ← val;
correctMX => state.p.correctMeasure.x ← val;
correctMY => state.p.correctMeasure.y ← val;
mediumXSize => state.np.mediumSize.x ← val;
mediumYSize => state.np.mediumSize.y ← val;
fieldXMin => state.np.fieldMin.x ← val;
fieldYMin => state.np.fieldMin.y ← val;
fieldXMax => state.np.fieldMax.x ← val;
fieldYMax => state.np.fieldMax.y ← val;
strokeWidth => state.np.strokeWidth ← val;
underlineStart => state.np.underlineStart ← val;
amplifySpace => state.np.amplifySpace ← val;
correctShrink => state.np.correctShrink ← val;
correctTX => state.np.correctTolerance.x ← val;
correctTY => state.np.correctTolerance.y ← val;
ENDCASE => ERROR Imager.Error[[$unimplemented, "Unknown RealKey"]];
};
StateSetT: PUBLIC PROC[context: Context, m: Transformation] ~ {
state: State ~ context.state;
state.T^ ← m^;
Changed[state, [T: TRUE]];
};
StateSetClipper: PUBLIC PROC[context: Context, clipper: Clipper] ~ {
state: State ~ context.state;
state.clipper ← clipper;
Changed[state, [clipper: TRUE]];
};
StateSetFont: PUBLIC PROC[context: Context, font: Font] ~ {
state: State ~ context.state;
state.font ← font;
Changed[state, [font: TRUE]];
};
StateSetColor: PUBLIC PROC[context: Context, color: Color] ~ {
state: State ~ context.state;
state.color ← color;
Changed[state, [color: TRUE]];
};
StateSetStrokeDashes: PUBLIC PROC[context: Context, strokeDashes: StrokeDashes] ~ {
state: State ~ context.state;
state.strokeDashes ← strokeDashes;
};
StateGetInt: PUBLIC PROC[context: Context, key: ImagerBackdoor.IntKey] RETURNS[INT] ~ {
state: State ~ context.state;
SELECT key FROM
priorityImportant => RETURN[state.np.priorityImportant];
noImage => RETURN[state.np.noImage];
strokeEnd => RETURN[state.np.strokeEnd];
strokeJoint => RETURN[state.np.strokeJoint];
correctPass => RETURN[state.np.correctPass];
ENDCASE => ERROR Imager.Error[[$unimplemented, "Unknown IntKey"]];
};
StateGetReal: PUBLIC PROC[context: Context, key: ImagerBackdoor.RealKey] RETURNS[REAL] ~ {
state: State ~ context.state;
SELECT key FROM
DCScpx => RETURN[state.p.cp.x];
DCScpy => RETURN[state.p.cp.y];
correctMX => RETURN[state.p.correctMeasure.x];
correctMY => RETURN[state.p.correctMeasure.y];
mediumXSize => RETURN[state.np.mediumSize.x];
mediumYSize => RETURN[state.np.mediumSize.y];
fieldXMin => RETURN[state.np.fieldMin.x];
fieldYMin => RETURN[state.np.fieldMin.y];
fieldXMax => RETURN[state.np.fieldMax.x];
fieldYMax => RETURN[state.np.fieldMax.y];
strokeWidth => RETURN[state.np.strokeWidth];
underlineStart => RETURN[state.np.underlineStart];
amplifySpace => RETURN[state.np.amplifySpace];
correctShrink => RETURN[state.np.correctShrink];
correctTX => RETURN[state.np.correctTolerance.x];
correctTY => RETURN[state.np.correctTolerance.y];
ENDCASE => ERROR Imager.Error[[$unimplemented, "Unknown RealKey"]];
};
StateGetT: PUBLIC PROC[context: Context] RETURNS[Transformation] ~ {
state: State ~ context.state;
RETURN[NEW[TransformationRep ← state.T^]];
};
StateGetClipper: PUBLIC PROC[context: Context] RETURNS[Clipper] ~ {
state: State ~ context.state;
RETURN[state.clipper];
};
StateGetFont: PUBLIC PROC[context: Context] RETURNS[Font] ~ {
state: State ~ context.state;
RETURN[state.font];
};
StateGetColor: PUBLIC PROC[context: Context] RETURNS[Color] ~ {
state: State ~ context.state;
RETURN[state.color];
};
StateGetStrokeDashes: PUBLIC PROC[context: Context] RETURNS[StrokeDashes] ~ {
state: State ~ context.state;
RETURN[state.strokeDashes];
};
StateGetCP: PUBLIC PROC[context: Context, rounded: BOOL] RETURNS[VEC] ~ {
state: State ~ context.state;
p: VEC ← state.p.cp;
IF rounded THEN p ← ImagerTransformation.DRound[p];
RETURN[state.T.InverseTransform[p]];
};
StateConcatT: PUBLIC PROC[context: Context, m: Transformation] ~ {
state: State ~ context.state;
state.T.ApplyPreConcat[m];
Changed[state, [T: TRUE]];
};
StateScale2T: PUBLIC PROC[context: Context, s: VEC] ~ {
state: State ~ context.state;
state.T.ApplyPreScale2[s];
Changed[state, [T: TRUE]];
};
StateRotateT: PUBLIC PROC[context: Context, a: REAL] ~ {
state: State ~ context.state;
state.T.ApplyPreRotate[a];
Changed[state, [T: TRUE]];
};
StateTranslateT: PUBLIC PROC[context: Context, t: VEC] ~ {
state: State ~ context.state;
state.T.ApplyPreTranslate[t];
Changed[state, [T: TRUE]];
};
StateMove: PUBLIC PROC[context: Context, rounded: BOOLTRUE] ~ {
state: State ~ context.state;
p: VEC ← state.p.cp;
IF rounded THEN p ← ImagerTransformation.DRound[p];
state.T.ApplyTranslateTo[p];
Changed[state, [T: TRUE]];
};
StateSetXY: PUBLIC PROC[context: Context, p: VEC] ~ {
state: State ~ context.state;
state.p.cp ← state.T.Transform[p];
};
StateSetXYRel: PUBLIC PROC[context: Context, v: VEC] ~ {
state: State ~ context.state;
state.p.cp ← state.p.cp.InlineAdd[state.T.TransformVec[v]];
};
StateSetGray: PUBLIC PROC[context: Context, f: REAL] ~ {
state: State ~ context.state;
state.color ← Imager.MakeGray[f];
Changed[state, [color: TRUE]];
};
StateSetSampledColor: PUBLIC PROC[context: Context,
pa: PixelArray, m: Transformation, colorOperator: ColorOperator] ~ {
state: State ~ context.state;
um: Transformation ~ m.Concat[state.T]; -- color to view
state.color ← ImagerColor.MakeSampledColor[pa: pa, um: um, colorOperator: colorOperator];
Changed[state, [color: TRUE]];
};
StateSetSampledBlack: PUBLIC PROC[context: Context,
pa: PixelArray, m: Transformation, clear: BOOL] ~ {
state: State ~ context.state;
um: Transformation ~ m.Concat[state.T]; -- color to view
colorOperator: ColorOperator ~ ImagerColorOperator.BlackColorModel[clear];
state.color ← ImagerColor.MakeSampledColor[pa: pa, um: um, colorOperator: colorOperator];
Changed[state, [color: TRUE]];
};
StateStartUnderline: PUBLIC PROC[context: Context] ~ {
state: State ~ context.state;
p: VEC ~ state.T.InverseTransform[state.p.cp];
state.np.underlineStart ← p.x;
};
StateMaskUnderline: PUBLIC PROC[context: Context, dy, h: REAL] ~ {
state: State ~ context.state;
p2: VEC ~ state.T.InverseTransform[state.p.cp]; -- current position (client coords)
p1: VEC ~ [state.np.underlineStart, p2.y-dy-h]; -- starting corner (client coords)
underline: PROC ~ {
Imager.SetXY[context, p1];
Imager.Trans[context];
Imager.MaskRectangle[context, [0, 0, p2.x-p1.x, h]];
};
Imager.DoSaveAll[context, underline];
};
StateClip: PUBLIC PROC[context: Context, path: PathProc, parity: BOOL, exclude: BOOL] ~ {
state: State ~ context.state;
outline: Outline ~ ImagerPath.OutlineFromPath[path: path, m: state.T];
state.clipper ← CONS[[outline: outline, parity: parity, exclude: exclude], state.clipper];
Changed[state, [clipper: TRUE]];
};
StateClipRectangle: PUBLIC PROC[context: Context, r: Rectangle, exclude: BOOL] ~ {
path: PathProc ~ {
moveTo[[r.x, r.y]];
lineTo[[r.x+r.w, r.y]];
lineTo[[r.x+r.w, r.y+r.h]];
lineTo[[r.x, r.y+r.h]];
};
StateClip[context: context, path: path, parity: FALSE, exclude: exclude];
};
StateClipRectangleI: PUBLIC PROC[context: Context, x, y, w, h: INTEGER, exclude: BOOL] ~ {
path: PathProc ~ {
moveTo[[x, y]];
lineTo[[x+w, y]];
lineTo[[x+w, y+h]];
lineTo[[x, y+h]];
};
StateClip[context: context, path: path, parity: FALSE, exclude: exclude];
};
StateCorrectMask: PUBLIC PROC[context: Context] ~ {
state: State ~ context.state;
IF state.np.correctPass#0 THEN {
SELECT state.np.correctPass FROM
1 => state.p.correctMaskCount ← state.p.correctMaskCount+1;
2 => IF state.p.correctMaskCount#0 THEN {
state.p.cp ← state.p.cp.InlineAdd[state.p.correctMask];
state.p.correctMaskCount ← state.p.correctMaskCount-1;
};
ENDCASE;
};
};
StateCorrectSpace: PUBLIC PROC[context: Context, v: VEC] ~ {
state: State ~ context.state;
IF state.np.correctPass#0 THEN {
s: VEC ~ state.T.TransformVec[v];
SELECT state.np.correctPass FROM
1 => state.p.correctSum ← state.p.correctSum.InlineAdd[s];
2 => state.p.cp ← state.p.cp.InlineAdd[state.p.correctSpace.InlineMulC[s]];
ENDCASE;
};
};
StateSpace: PUBLIC PROC[context: Context, x: REAL] ~ {
state: State ~ context.state;
s: VEC ~ state.T.TransformVec[[x, 0]];
state.p.cp ← state.p.cp.InlineAdd[s];
SELECT state.np.correctPass FROM
0 => NULL;
1 => state.p.correctSum ← state.p.correctSum.InlineAdd[s];
2 => state.p.cp ← state.p.cp.InlineAdd[state.p.correctSpace.InlineMulC[s]];
ENDCASE;
};
StateSetCorrectMeasure: PUBLIC PROC[context: Context, v: VEC] ~ {
state: State ~ context.state;
state.p.correctMeasure ← state.T.TransformVec[v];
};
StateSetCorrectTolerance: PUBLIC PROC[context: Context, v: VEC] ~ {
state: State ~ context.state;
state.np.correctTolerance ← state.T.TransformVec[v];
};
StateCorrect: PUBLIC PROC[context: Context, action: PROC] ~ {
state: State ~ context.state;
shrink: REAL ~ state.np.correctShrink;
tolerance: VEC ~ state.np.correctTolerance;
start, end, measure, target, correction: VEC;
mask, space: VEC ← [0, 0];
state.p.correctMaskCount ← 0;
state.p.correctSum ← [0, 0];
state.np.noImage ← 1;
state.np.correctPass ← 1;
start ← state.p.cp; -- starting position
StateDoSave[context, action]; -- pass 1
end ← state.p.cp; -- ending position
measure ← state.p.correctMeasure; -- desired measure (note: may be set during pass 1)
target ← start.Add[measure]; -- target position
correction ← target.Sub[end]; -- amount of correction needed (end + correction = target)
IF correction.Length<=tolerance.Length THEN NULL -- close enough
ELSE IF end.Sub[start].Length<measure.Length THEN { -- must expand
space ← correction;
}
ELSE { -- must shrink
space ← correction;
IF space.Length>(shrink*state.p.correctSum.Length) THEN {
mask ← correction.Add[state.p.correctSum.Mul[shrink]];
space ← correction.Sub[mask];
};
};
IF state.p.correctSum.x#0 THEN space.x ← space.x/state.p.correctSum.x
ELSE IF space.x#0 THEN { mask.x ← mask.x+space.x; space.x ← 0 };
IF state.p.correctSum.y#0 THEN space.y ← space.y/state.p.correctSum.y
ELSE IF space.y#0 THEN { mask.y ← mask.y+space.y; space.y ← 0 };
IF state.p.correctMaskCount#0 THEN {
IF mask.x=0 AND mask.y=0 THEN state.p.correctMaskCount ← 0
ELSE IF state.p.correctMaskCount>1 THEN {
state.p.correctMaskCount ← state.p.correctMaskCount-1;
mask ← mask.Div[state.p.correctMaskCount];
};
};
state.p.correctMask ← mask;
state.p.correctSpace ← space;
state.np.noImage ← 0;
state.np.correctPass ← 2;
state.p.cp ← start;
StateDoSave[context, action]; -- pass 2
state.np.correctPass ← 0;
end ← state.p.cp; -- ending position
state.p.cp ← target;
IF target.Sub[end].Length>tolerance.Length THEN
ERROR Imager.Error[$UnableToProperlyAdjustMaskPositions];
};
StateDontCorrect: PUBLIC PROC[context: Context, action: PROC, saveCP: BOOL] ~ {
state: State ~ context.state;
correctPass: INT ~ state.np.correctPass;
cp: VEC ~ state.p.cp;
Restore: PROC ~ INLINE { state.np.correctPass ← correctPass; IF saveCP THEN state.p.cp ← cp };
action[! UNWIND => Restore[]];
Restore[];
};
StateShow: PUBLIC PROC[context: Context, string: XStringProc, xrel: BOOL] ~ {
state: State ~ context.state;
font: Font ~ state.font;
charAction: PROC[char: XChar] ~ {
doSaveAction: PROC ~ {
width: VEC ← font.Width[char];
IF font.Amplified[char] THEN width ← width.Mul[state.np.amplifySpace];
StateTrans[context];
ImagerFontClass.MaskChar[font, char, context];
StateSetXYRel[context, width];
SELECT font.Correction[char] FROM
none => NULL;
space => StateCorrectSpace[context, width];
mask => StateCorrectMask[context];
ENDCASE => ERROR Imager.Error[$Bug];
};
StateDoSave[context, doSaveAction];
};
string[charAction];
};
StateShowText: PUBLIC PROC[context: Context, text: REF READONLY TEXT,
start, len: NAT, xrel: BOOL] ~ {
string: XStringProc ~ { ImagerFont.MapText[text, start, len, charAction] };
StateShow[context, string, xrel];
};
StateMaskFill: PROC[context: Context, path: PathProc, parity: BOOL] ~ {
ERROR Imager.Error[[$unimplemented, "MaskFill not implemented"]];
};
StateMaskRectangle: PROC[context: Context, x, y, w, h: REAL] ~ {
path: PathProc ~ { moveTo[[x, y]]; lineTo[[x+w, y]]; lineTo[[x+w, y+h]]; lineTo[[x, y+h]] };
Imager.MaskFill[context, path];
};
StateMaskRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ~ {
path: PathProc ~ { moveTo[[x, y]]; lineTo[[x+w, y]]; lineTo[[x+w, y+h]]; lineTo[[x, y+h]] };
Imager.MaskFill[context, path];
};
StateMaskStroke: PROC[context: Context, path: PathProc, closed: BOOLFALSE] ~ {
ERROR Imager.Error[[$unimplemented, "MaskStroke not implemented"]];
};
StateMaskVector: PUBLIC PROC[context: Context, p1, p2: VEC] ~ {
path: PathProc ~ { moveTo[p1]; lineTo[p2] };
Imager.MaskStroke[context, path];
};
StateMaskVectorI: PUBLIC PROC[context: Context, p1, p2: IVEC] ~ {
path: PathProc ~ { moveTo[[p1.x, p1.y]]; lineTo[[p2.x, p2.y]] };
Imager.MaskStroke[context, path];
};
StateMaskPixel: PROC[context: Context, pa: PixelArray] ~ {
ERROR Imager.Error[[$unimplemented, "MaskPixel not implemented"]];
};
StateMaskBits: PROC[context: Context, base: LONG POINTER, wordsPerLine: NAT,
sMin, fMin, sSize, fSize: NAT, sOffset, fOffset: INTEGER ← 0] ~ {
ERROR Imager.Error[[$unimplemented, "MaskBits not implemented"]];
};
CreateClass: PUBLIC PROC[type: ATOM] RETURNS[ImagerClass.Class] ~ {
class: ImagerClass.Class ~ NEW[ImagerClass.ClassRep ← stateClass^];
class.type ← type;
RETURN[class];
};
CreateState: PUBLIC PROC RETURNS[State] ~ {
state: State ~ NEW[StateRep ← []];
state.T ← ImagerTransformation.Scale[1];
state.color ← ImagerColor.MakeGray[1];
RETURN[state];
};
stateClass: ImagerClass.Class ~ NEW[ImagerClass.ClassRep ← [
type: $State,
DoSave: StateDoSave,
SetInt: StateSetInt,
SetReal: StateSetReal,
SetT: StateSetT,
SetClipper: StateSetClipper,
SetFont: StateSetFont,
SetColor: StateSetColor,
SetStrokeDashes: StateSetStrokeDashes,
GetInt: StateGetInt,
GetReal: StateGetReal,
GetT: StateGetT,
GetClipper: StateGetClipper,
GetFont: StateGetFont,
GetColor: StateGetColor,
GetStrokeDashes: StateGetStrokeDashes,
GetCP: StateGetCP,
ConcatT: StateConcatT,
Scale2T: StateScale2T,
RotateT: StateRotateT,
TranslateT: StateTranslateT,
Trans: StateTrans,
SetXY: StateSetXY,
SetXYI: StateSetXYI,
SetXYRel: StateSetXYRel,
SetXYRelI: StateSetXYRelI,
SetGray: StateSetGray,
SetSampledColor: StateSetSampledColor,
StartUnderline: StateStartUnderline,
Clip: StateClip,
ClipRectangle: StateClipRectangle,
ClipRectangleI: StateClipRectangleI,
CorrectMask: StateCorrectMask,
CorrectSpace: StateCorrectSpace,
Space: StateSpace,
SpaceI: StateSpaceI,
SetCorrectMeasure: StateSetCorrectMeasure,
SetCorrectTolerance: StateSetCorrectTolerance,
Correct: StateCorrect,
Show: StateShow,
ShowText: StateShowText,
MaskFill: StateMaskFill,
MaskRectangle: StateMaskRectangle,
MaskRectangleI: StateMaskRectangleI,
MaskStroke: StateMaskStroke,
MaskVector: StateMaskVector,
MaskVectorI: StateMaskVectorI,
MaskUnderline: StateMaskUnderline,
MaskUnderlineI: StateMaskUnderlineI,
MaskPixel: StateMaskPixel,
MaskBits: StateMaskBits,
props: NIL
]];
END.