GGFromImagerImpl.mesa
Copyright c 1985 by Xerox Corporation. All rights reserved.
Michael Plass, October 19, 1985 3:55:31 pm PDT
Pier, February 3, 1987 12:13:41 pm PST
Bier, January 30, 1987 6:52:13 pm PST
DIRECTORY
Basics, Convert, FileNames, GGBasicTypes, GGFromImager, GGModelTypes, GGObjects, GGOutline, GGParseIn, GGSegment, GGSegmentTypes, GGSlice, GGTraj, GGUtility, GGVector, Imager, ImagerBackdoor, ImagerColor, ImagerFont, ImagerFontPrivate, ImagerInterpress, ImagerPath, ImagerPrivate, ImagerRasterPrivate, ImagerState, ImagerTransformation, Interpress, IO, RefText, Rope, ViewerClasses;
GGFromImagerImpl: CEDAR PROGRAM
IMPORTS Convert, FileNames, GGParseIn, GGObjects, GGOutline, GGSegment, GGSlice, GGTraj, GGUtility, GGVector, Imager, ImagerBackdoor, ImagerFont, ImagerInterpress, ImagerPath, ImagerRasterPrivate, ImagerState, ImagerTransformation, Interpress, IO, RefText, Rope
EXPORTS GGFromImager, Imager, ImagerFont = BEGIN
BYTE: TYPE ~ Basics.BYTE;
ROPE: TYPE ~ Rope.ROPE;
Class: TYPE ~ REF ClassRep;
ClassRep: PUBLIC TYPE ~ ImagerPrivate.ClassRep; -- export to Imager.ClassRep
Context: TYPE ~ Imager.Context;
Color: TYPE ~ Imager.Color;
ColorOperator: TYPE ~ Imager.ColorOperator;
Clipper: TYPE ~ ImagerBackdoor.Clipper;
Font: TYPE ~ ImagerFont.Font;
PathProc: TYPE ~ ImagerPath.PathProc;
PixelArray: TYPE ~ Imager.PixelArray;
Point: TYPE ~ GGBasicTypes.Point;
Rectangle: TYPE ~ ImagerTransformation.Rectangle;
Slice: TYPE ~ GGModelTypes.Slice;
State: TYPE ~ REF StateRep;
StateRep: PUBLIC TYPE ~ ImagerState.StateRep;
Transformation: TYPE ~ ImagerTransformation.Transformation;
VEC: TYPE ~ Imager.VEC;
Viewer: TYPE ~ ViewerClasses.Viewer;
XChar: TYPE ~ ImagerFont.XChar;
XStringProc: TYPE ~ ImagerFont.XStringProc;
FontImpl: TYPE ~ ImagerFontPrivate.FontImpl;
FontImplRep: PUBLIC TYPE ~ ImagerFontPrivate.FontImplRep; -- export to to ImagerFont
Data: TYPE ~ REF DataRep;
DataRep: TYPE ~ RECORD [
scene: GGModelTypes.Scene,
feedback: Viewer
];
Warning: PUBLIC SIGNAL [context: Context, code: ATOM, message: ROPE] ~ CODE;
Create: PROC [feedback: Viewer] RETURNS [Context] ~ {
data: Data ~ NEW[DataRep ← [scene: GGObjects.CreateScene[], feedback: feedback]];
state: State ~ NEW[StateRep ← []];
state.T ← ImagerTransformation.Scale[1.0]; -- allocate storage for a transformation and initialize to the identity
state.T ← ImagerTransformation.Scale[72/0.0254];
state.color ← Imager.black;
RETURN[NEW[Imager.ContextRep ← [class: gargoyleClass, state: state, data: data]]];
};
Capture: PUBLIC PROC [action: PROC [Context], feedback: Viewer ← NIL] RETURNS [GGModelTypes.Scene] ~ {
context: Context ~ Create[feedback];
action[context];
WITH context.data SELECT FROM data: Data => RETURN [data.scene]; ENDCASE => ERROR;
};
ProcessStateChanges: PUBLIC PROC [context: Context] ~ {
state: State ~ context.state;
changed: ImagerState.ChangeFlags ~ state.changed;
state.changed ← ImagerState.notChanged;
IF changed.clipper AND state.clipper # NIL THEN SIGNAL Warning[context, $Clipping, "NotImplemented: Clipping"];
};
RopeFromXStringProc: PROC [string: XStringProc] RETURNS [rope: ROPENIL] ~ {
text: REF TEXT ← RefText.ObtainScratch[256];
set: BYTE ← 0;
action: PROC [char: XChar] ~ {
IF char.set#set THEN {
text ← RefText.AppendChar[to: text, from: VAL[255]];
text ← RefText.AppendChar[to: text, from: VAL[set ← char.set]];
};
text ← RefText.AppendChar[to: text, from: VAL[char.code]];
};
text.length ← 0;
string[action];
rope ← Rope.FromRefText[text];
RefText.ReleaseScratch[text];
RETURN [rope];
};
UnpackComplexFontName: PROC [fontName: Rope.ROPE] RETURNS [prefix, family, face: Rope.ROPE, fontSize: REAL] = {
Takes a complex name like "xerox/pressfonts/Helvetica-MIR" and a font size and returns components.
May already have a simple name like xerox/tiogafonts/Helvetica10I. KAP August 8, 1986
DigitProc: IO.BreakProc = {
SELECT char FROM
IO.TAB, IO.CR, IO.SP => RETURN [break];
'0, '1, '2, '3, '4, '5, '6, '7, '8, '9 => RETURN [break];
ENDCASE => RETURN [other];
};
AlphaProc: IO.BreakProc = {
SELECT char FROM
IO.TAB, IO.CR, IO.SP => RETURN [break];
IN ['a .. 'z], IN ['A .. 'Z] => RETURN [break];
ENDCASE => RETURN [other];
};
new, sizeRope: Rope.ROPE;
prefix ← FileNames.Directory[path: fontName]; -- "xerox/*fonts/"
new ← FileNames.GetShortName[fontName]; -- get family "name"
face ← FileNames.Tail[new, '-]; -- get face component (MIR, BRR, ...)
IF Rope.Equal[face, new] THEN { -- have a name like Helvetica10I OR TERMINAL
endOfName: BOOL;
nameStream: IO.STREAMIO.RIS[new];
family ← IO.GetTokenRope[nameStream, DigitProc].token; -- get the leading alpha characters
sizeRope ← IO.GetTokenRope[nameStream, AlphaProc ! IO.EndOfStream, IO.Error => {endOfName ← TRUE; CONTINUE;};].token; -- get any digit characters
fontSize ← Convert.RealFromRope[sizeRope];
IF endOfName THEN face ← "" -- because face = new
ELSE face ← Rope.Concat["-", GGParseIn.ReadBlankAndWord[nameStream]];
}
ELSE { -- have a name like Helvetica-MIR
family ← Rope.Substr[base: new, start: 0, len: Rope.SkipTo[s: new, pos: 0, skip: "-"]]; -- throw away "-XXX"
face ← SELECT TRUE FROM
Rope.Equal[face, "MRR", FALSE] => "",
Rope.Equal[face, "BRR", FALSE] => "-B",
Rope.Equal[face, "Bold", FALSE] => "-B",
Rope.Equal[face, "MIR", FALSE] => "-I",
Rope.Equal[face, "Italic", FALSE] => "-I",
Rope.Equal[face, "BIR", FALSE] => "-BI",
ENDCASE => ERROR;
fontSize ← 1.0;
};
};
SetSegColor: PROC [context: Context, seg: GGSegmentTypes.Segment] = {
A kludge for the moment to avoid segments with sampled colors
seg.color ← IF ISTYPE[context.state.color, ImagerColor.ConstantColor] THEN context.state.color ELSE Imager.black;
};
OutlineFromPath: PROC[context: Context, path: PathProc, m: Transformation, closed: BOOL] RETURNS [GGModelTypes.Outline] ~ {
curOutline: GGModelTypes.Outline ← NIL;
curTraj: GGModelTypes.Traj ← NIL;
curSeg: GGSegmentTypes.Segment ← NIL;
lp: VEC ← [0,0];
firstPoint: VEC ← [0,0];
Finish: PROC ~ {
IF curTraj # NIL THEN {
IF curSeg # NIL THEN {
IF closed THEN {
IF curSeg.hi = firstPoint THEN GGTraj.CloseWithSegment[curTraj, curSeg, lo]
IF curSeg.hi = firstPoint THEN {
[] ← GGTraj.AddSegment[curTraj, hi, curSeg, lo];
GGTraj.CloseByDistorting[curTraj, hi];
}
ELSE {
[] ← GGTraj.AddSegment[curTraj, hi, curSeg, lo];
curSeg ← GGSegment.MakeLine[curSeg.hi, firstPoint, NIL];
curSeg.strokeWidth ← GGVector.Magnitude[ImagerTransformation.TransformVec[m, [context.state.np.strokeWidth, 0.0] ] ];
SetSegColor[context, curSeg];
GGTraj.CloseWithSegment[curTraj, curSeg, lo];
};
}
ELSE [] ← GGTraj.AddSegment[curTraj, hi, curSeg, lo];
}
ELSE { -- unlikely but legal case: Traj with a single point, no segment
[] ← GGTraj.AddSegment[curTraj, lo, GGSegment.MakeLine[[lp.x, lp.y], [lp.x, lp.y], NIL], lo];
};
curSeg ← NIL;
IF curOutline = NIL THEN curOutline ← GGOutline.CreateOutline[curTraj]
ELSE curOutline ← GGOutline.AddHole[curOutline, curTraj];
curTraj ← NIL;
};
};
Move: PROC [p: VEC] ~ {
Finish[];
curTraj ← GGTraj.CreateTraj[[p.x, p.y]];
firstPoint ← lp ← p;
};
Line: PROC [p1: VEC] ~ {
IF curSeg # NIL THEN [] ← GGTraj.AddSegment[curTraj, hi, curSeg, lo];
curSeg ← GGSegment.MakeLine[[lp.x, lp.y], [p1.x, p1.y], NIL];
curSeg.strokeWidth ← GGVector.Magnitude[ImagerTransformation.TransformVec[m, [context.state.np.strokeWidth, 0.0] ] ];
curSeg.color ← context.state.color;
SetSegColor[context, curSeg];
lp ← p1;
};
Curve: PROC [p1, p2, p3: VEC] ~ {
IF curSeg # NIL THEN [] ← GGTraj.AddSegment[curTraj, hi, curSeg, lo];
curSeg ← GGSegment.MakeBezier[[lp.x, lp.y], [p1.x, p1.y], [p2.x, p2.y], [p3.x, p3.y], NIL];
curSeg.strokeWidth ← GGVector.Magnitude[ImagerTransformation.TransformVec[m, [context.state.np.strokeWidth, 0.0] ] ];
curSeg.color ← context.state.color;
SetSegColor[context, curSeg];
lp ← p3;
};
Conic: PROC [p1, p2: VEC, r: REAL] ~ {
IF curSeg # NIL THEN [] ← GGTraj.AddSegment[curTraj, hi, curSeg, lo];
curSeg ← GGSegment.MakeConic[[lp.x, lp.y], [p1.x, p1.y], [p2.x, p2.y], r, NIL];
curSeg.strokeWidth ← GGVector.Magnitude[ImagerTransformation.TransformVec[m, [context.state.np.strokeWidth, 0.0] ] ];
curSeg.color ← context.state.color;
SetSegColor[context, curSeg];
lp ← p2;
};
Arc: PROC [p1, p2: VEC] ~ {
IF curSeg # NIL THEN [] ← GGTraj.AddSegment[curTraj, hi, curSeg, lo];
curSeg ← GGSegment.MakeArc[[lp.x, lp.y], [p1.x, p1.y], [p2.x, p2.y], NIL];
curSeg.strokeWidth ← GGVector.Magnitude[ImagerTransformation.TransformVec[m, [context.state.np.strokeWidth, 0.0] ] ];
curSeg.color ← context.state.color;
SetSegColor[context, curSeg];
lp ← p2;
};
ImagerPath.Transform[path, m, Move, Line, Curve, Conic, Arc];
Finish[];
RETURN [curOutline];
};
MyShow: PROC[context: Context, string: XStringProc, xrel: BOOL] ~ {
OPEN ImagerTransformation;
textSlice: GGModelTypes.Slice;
data: Data ← NARROW[context.data];
font: ImagerFont.Font ← context.class.GetFont[context];
rope: ROPE ← RopeFromXStringProc[string];
escapement: VEC ← ImagerFont.RopeWidth[font, rope];
IF context.state.np.noImage=0 THEN {
color: Imager.Color ← context.class.GetColor[context];
currentT: Transformation ← context.class.GetT[context];
currentPoint: Point ← context.class.GetCP[context, FALSE];
charToClientScale: VEC ← Factor[font.charToClient].s;
totalTransform: Transformation;
fontSize: REAL ← 1.0;
amplifySpace: REAL;
correctMeasureX: REAL;
prefix, family, face, fontName, problem: Rope.ROPE;
IF charToClientScale.y < 0 THEN
totalTransform ← Concat[Scale2[[1, -1]], Concat[Translate[currentPoint], currentT]]
ELSE totalTransform ← Concat[Translate[currentPoint], currentT];
amplifySpace ← ImagerBackdoor.GetReal[context, $amplifySpace];
correctMeasureX ← ImagerBackdoor.GetReal[context, $correctMX];
[prefix, family, face, fontSize] ← UnpackComplexFontName[font.name];
totalTransform ← Cat[Scale[fontSize], font.charToClient, Translate[currentPoint], currentT];
[fontName, ----, ----, problem] ← GGUtility.FontDataFromUserData[prefix, family, face, 1.0, fontSize];
IF problem#NIL THEN ERROR;
textSlice ← GGSlice.MakeTextSlice[rope, color, amplifySpace];
[] ← GGSlice.SetTextFont[slice: textSlice, prefix: prefix, family: family, face: face, fontName: fontName, scale: 1.0, fontScale: fontSize, transform: totalTransform, feedback: NIL];
GGObjects.AddSlice[data.scene, textSlice, -1];
};
ImagerState.StateSetXYRel[context, escapement];
};
MyMaskFill: PROC[context: Context, path: PathProc, oddWrap: BOOL] ~ {
data: Data ~ NARROW[context.data];
state: State ~ context.state;
IF state.changed#ImagerState.notChanged THEN ProcessStateChanges[context];
IF oddWrap THEN SIGNAL Warning[context, $ParityFill, "NotImplemented: ParityFill"];
IF context.state.np.noImage=0 THEN --CHECKED-- {
outline: GGModelTypes.Outline ← OutlineFromPath[context, path, state.T, TRUE];
outline.class.setFillColor[outline, state.color];
GGObjects.AddOutline[data.scene, outline, -1];
};
};
MyMaskStroke: PROC[context: Context, path: PathProc, closed: BOOL] ~ {
outline: GGModelTypes.Outline;
data: Data ~ NARROW[context.data];
state: State ~ context.state;
IF state.changed#ImagerState.notChanged THEN ProcessStateChanges[context];
IF context.state.np.noImage=0 THEN {
outline ← OutlineFromPath[context, path, state.T, closed];
GGObjects.SetLineEnds[outline, VAL[CARDINAL[state.np.strokeEnd]]];
outline.class.setFillColor[outline, NIL]; -- no fill color
GGObjects.AddOutline[data.scene, outline, -1];
};
};
MyMaskDashedStroke: PROC[context: Context, path: PathProc, patternLen: NAT, pattern: PROC [NAT] RETURNS [REAL], offset, length: REAL] ~ {
Can't do dashed stokes in gargoyle yet.
MyMaskStroke[context, path, FALSE];
};
MyMaskRectangle: PROC[context: Context, r: Rectangle] ~ {
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]]
};
MyMaskFill[context, path, FALSE];
};
MyMaskRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ~ {
MyMaskRectangle[context, [x, y, w, h]];
};
MyMaskVector: PROC[context: Context, p1, p2: VEC] ~ {
path: PathProc ~ {moveTo[p1]; lineTo[p2]};
MyMaskStroke[context, path, FALSE];
};
MyMaskPixel: PROC[context: Context, pa: PixelArray] ~ {
DoMyMaskPixel: PROC [dc: Imager.Context] = {
Imager.MaskPixel[dc, pa];
};
data: Data ← NARROW[context.data];
ipSlice: Slice;
currentColor: Color;
currentT: ImagerTransformation.Transformation;
currentColor ← context.state.color;
currentT ← ImagerTransformation.Copy[context.state.T];
ipSlice ← GGSlice.MakeIPSliceFromMaskPixel[pa, currentColor, NIL, currentT];
GGObjects.AddSlice[data.scene, ipSlice, -1];
};
MyMaskBits: PROC[context: Context, base: LONG POINTER, wordsPerLine: NAT,
sMin, fMin, sSize, fSize: NAT, tx, ty: INTEGER] ~ {
DoMyMaskBits: PROC [dc: Imager.Context] = {
Imager.MaskBits[dc, base, wordsPerLine, sMin, fMin, sSize, fSize, tx, ty];
};
masterStream, outStream: IO.STREAM;
masterRope: Rope.ROPE;
data: Data ← NARROW[context.data];
ipRef: ImagerInterpress.Ref;
ipMaster: Interpress.Master;
ipSlice: Slice;
SIGNAL Warning[context, $MaskBits, "NotImplemented: MaskBits"];
outStream ← IO.ROS[];
ipRef ← ImagerInterpress.CreateFromStream[outStream, "Interpress/Xerox/3.0 "];
ImagerInterpress.DoPage[ipRef, DoMyMaskBits];
ImagerInterpress.Finish[ipRef];
masterRope ← IO.RopeFromROS[outStream];
masterStream ← IO.RIS[masterRope];
ipMaster ← Interpress.FromStream[masterStream, NIL];
ipSlice ← GGSlice.MakeIPSliceFromMaster[ipMaster, NIL, NIL, NIL, TRUE];
GGObjects.AddSlice[data.scene, ipSlice, -1];
};
MyDrawBits: PROC[context: Context, base: LONG POINTER, wordsPerLine: NAT,
sMin, fMin, sSize, fSize: NAT, tx, ty: INTEGER] ~ {
DoMyDrawBits: PROC [dc: Imager.Context] = {
Imager.MaskBits[dc, base, wordsPerLine, sMin, fMin, sSize, fSize, tx, ty];
};
masterStream, outStream: IO.STREAM;
masterRope: Rope.ROPE;
data: Data ← NARROW[context.data];
ipRef: ImagerInterpress.Ref;
ipMaster: Interpress.Master;
ipSlice: Slice;
SIGNAL Warning[context, $DrawBits, "NotImplemented: DrawBits"];
outStream ← IO.ROS[];
ipRef ← ImagerInterpress.CreateFromStream[outStream, "Interpress/Xerox/3.0 "];
ImagerInterpress.DoPage[ipRef, DoMyDrawBits];
ImagerInterpress.Finish[ipRef];
masterRope ← IO.RopeFromROS[outStream];
masterStream ← IO.RIS[masterRope];
ipMaster ← Interpress.FromStream[masterStream, NIL];
ipSlice ← GGSlice.MakeIPSliceFromMaster[ipMaster, NIL, NIL, NIL, TRUE];
GGObjects.AddSlice[data.scene, ipSlice, -1];
};
MyGetBounds: PROC[context: Context] RETURNS[Rectangle] ~ {
ERROR Imager.Error[[$NotImplemented, "NotImplemented: GetBounds"]]
};
gargoyleClass: Class ~ NEW[ClassRep ← [
type: $Gargoyle,
DoSave: ImagerState.StateDoSave,
SetInt: ImagerState.StateSetInt,
SetReal: ImagerState.StateSetReal,
SetT: ImagerState.StateSetT,
SetFont: ImagerState.StateSetFont,
SetColor: ImagerState.StateSetColor,
SetClipper: ImagerState.StateSetClipper,
GetInt: ImagerState.StateGetInt,
GetReal: ImagerState.StateGetReal,
GetT: ImagerState.StateGetT,
GetFont: ImagerState.StateGetFont,
GetColor: ImagerState.StateGetColor,
GetClipper: ImagerState.StateGetClipper,
ConcatT: ImagerState.StateConcatT,
Scale2T: ImagerState.StateScale2T,
RotateT: ImagerState.StateRotateT,
TranslateT: ImagerState.StateTranslateT,
Move: ImagerState.StateMove,
SetXY: ImagerState.StateSetXY,
SetXYRel: ImagerState.StateSetXYRel,
Show: MyShow,
ShowText: ImagerRasterPrivate.RasterShowText,
StartUnderline: ImagerState.StateStartUnderline,
MaskUnderline: ImagerState.StateMaskUnderline,
CorrectMask: ImagerState.StateCorrectMask,
CorrectSpace: ImagerState.StateCorrectSpace,
Space: ImagerState.StateSpace,
SetCorrectMeasure: ImagerState.StateSetCorrectMeasure,
SetCorrectTolerance: ImagerState.StateSetCorrectTolerance,
Correct: ImagerState.StateCorrect,
DontCorrect: ImagerState.StateDontCorrect,
SetGray: ImagerState.StateSetGray,
SetSampledColor: ImagerState.StateSetSampledColor,
SetSampledBlack: ImagerState.StateSetSampledBlack,
MaskFill: MyMaskFill,
MaskStroke: MyMaskStroke,
MaskDashedStroke: MyMaskDashedStroke,
MaskRectangle: MyMaskRectangle,
MaskRectangleI: MyMaskRectangleI,
MaskVector: MyMaskVector,
MaskPixel: MyMaskPixel,
MaskBits: MyMaskBits,
DrawBits: MyDrawBits,
Clip: ImagerState.StateClip,
ClipRectangle: ImagerState.StateClipRectangle,
ClipRectangleI: ImagerState.StateClipRectangleI,
GetCP: ImagerState.StateGetCP,
GetBoundingRectangle: MyGetBounds,
propList: NIL
]];
END.