ImagerRasterShowImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Michael Plass, July 20, 1985 10:37:13 am PDT
Doug Wyatt, November 11, 1985 5:28:04 pm PST
DIRECTORY
Basics USING [bitsPerWord],
Imager USING [Box, Color, ColorOperator, Context, CorrectMask, CorrectSpace, DoSave, Error, PixelArray, SetXRel, SetXYRel, StateRep, Trans],
ImagerBackdoor USING [Clipper, GetBounds, GetCP, GetReal],
ImagerBox USING [BoxFromExtents, BoxFromRect, IntersectBox],
ImagerCache USING [Fetch, Flush, Ref, Store],
ImagerDevice USING [CharMask, CharMaskRep, Class, Device, DeviceBox, RunProc],
ImagerFont USING [Amplified, BoundingBox, Correction, Escapement, Font, MapText, XChar, XStringProc],
ImagerFontPrivate USING [FontImpl, FontImplRep, MaskChar],
ImagerManhattan USING [CreateFromBox, Destroy, IsVisible, Polygon],
ImagerMask USING [RunsFromCharMask],
ImagerMaskCapture USING [Capture],
ImagerPath USING [PathProc],
ImagerPixelMap USING [DeviceRectangle],
ImagerPrivate USING [Class, ClassRep],
ImagerRaster USING [FontTuner],
ImagerRasterPrivate USING [AndFlags, CharArrayIndex, charArraySize, ClipBoxToMask, Data, Flags, NoteStateChanges, ValidateIfNeeded],
ImagerScanConverter USING [DevicePath],
ImagerState USING [notChanged, State, StateRep],
ImagerTransformation USING [InverseTransform, Rectangle, Transform, Transformation, TransformationRep, TranslateTo],
Real USING [],
Rope USING [ROPE],
Scaled USING [Float, FromReal, PLUS, Round, Value],
Vector2 USING [Mul, VEC];
ImagerRasterShowImpl: CEDAR PROGRAM
IMPORTS Basics, Imager, ImagerBackdoor, ImagerBox, ImagerCache, ImagerFont, ImagerFontPrivate, ImagerManhattan, ImagerMask, ImagerMaskCapture, ImagerRasterPrivate, ImagerTransformation, Real, Scaled, Vector2
EXPORTS Imager, ImagerFont, ImagerRasterPrivate
~ BEGIN OPEN ImagerState, ImagerRasterPrivate;
Class: TYPE ~ ImagerPrivate.Class;
ClassRep: PUBLIC TYPE ~ ImagerPrivate.ClassRep; -- export to Imager.ClassRep
State: TYPE ~ ImagerState.State;
StateRep: PUBLIC TYPE ~ ImagerState.StateRep; -- export to Imager.StateRep
CharMask: TYPE ~ ImagerDevice.CharMask;
Clipper: TYPE ~ ImagerBackdoor.Clipper;
Color: TYPE ~ Imager.Color;
ColorOperator: TYPE ~ Imager.ColorOperator;
Context: TYPE ~ Imager.Context;
Device: TYPE ~ ImagerDevice.Device;
DeviceBox: TYPE ~ ImagerDevice.DeviceBox;
RunProc: TYPE ~ ImagerDevice.RunProc;
DevicePath: TYPE ~ ImagerScanConverter.DevicePath;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
Font: TYPE ~ ImagerFont.Font;
ManhattanPolygon: TYPE ~ ImagerManhattan.Polygon;
PathProc: TYPE ~ ImagerPath.PathProc;
PixelArray: TYPE ~ Imager.PixelArray;
Rectangle: TYPE ~ ImagerTransformation.Rectangle;
Transformation: TYPE ~ ImagerTransformation.Transformation;
TransformationRep: TYPE ~ ImagerTransformation.TransformationRep;
VEC: TYPE ~ Vector2.VEC;
XChar: TYPE ~ ImagerFont.XChar;
XStringProc: TYPE ~ ImagerFont.XStringProc;
FontImpl: TYPE ~ ImagerFontPrivate.FontImpl;
FontImplRep: PUBLIC TYPE ~ ImagerFontPrivate.FontImplRep; -- export to to ImagerFont
FontTuner: TYPE ~ ImagerRaster.FontTuner;
bitsPerWord:
NAT ~ Basics.bitsPerWord;
DeviceBoxFromDeviceRectangle:
PROC [r: DeviceRectangle]
RETURNS [DeviceBox] ~ {
RETURN[[smin: r.sMin, smax: r.sMin+r.sSize, fmin: r.fMin, fmax: r.fMin+r.fSize]];
};
Validate:
PROC [data: Data, state: State, needs: Flags] ~
INLINE {
IF state.changed#ImagerState.notChanged THEN NoteStateChanges[data, state];
IF AndFlags[data.valid, needs]#needs THEN ValidateIfNeeded[data, state, needs];
};
showNeeds: Flags ~ [clientClipper:
TRUE, deviceColor:
TRUE, devicePriority:
TRUE, clientToDevice:
TRUE, fontInfo:
TRUE];
CharPartlyVisible:
PROC [context: Context, font: Font, char: XChar]
RETURNS [
BOOL] ~ {
bounds: Imager.Box ~ ImagerBox.BoxFromRect[ImagerBackdoor.GetBounds[context]];
bb: Imager.Box ~ ImagerBox.BoxFromExtents[ImagerFont.BoundingBox[font, char]];
IF bb.xmin=bb.xmax THEN RETURN[TRUE]
ELSE {
cp: VEC ~ ImagerBackdoor.GetCP[context];
cbb: Imager.Box ~ [xmin: bb.xmin+cp.x, ymin: bb.ymin+cp.y, xmax: bb.xmax+cp.x, ymax: bb.ymax+cp.y];
common: Imager.Box ~ ImagerBox.IntersectBox[bounds, cbb];
RETURN [((common.xmax > common.xmin) AND (common.ymax > common.ymin))]
};
};
BasicShowChar:
PUBLIC
PROC [context: Context, font: Font, char: XChar,
checkBB:
BOOL, imaging:
BOOL, fontTuner: FontTuner ←
NIL] ~ {
escapement: VEC ← font.Escapement[char];
IF font.Amplified[char]
THEN {
escapement ← escapement.Mul[ImagerBackdoor.GetReal[context, amplifySpace]];
};
Imager.Trans[context];
IF imaging
AND (
NOT checkBB
OR CharPartlyVisible[context, font, char])
THEN {
IF fontTuner =
NIL
THEN {
ImagerFontPrivate.MaskChar[font, char, context];
}
ELSE {
op: PROC [ctx: Context] ~ {ImagerFontPrivate.MaskChar[font, char, ctx]};
fontTuner.proc[fontTuner, op, context];
};
};
Imager.SetXYRel[context, escapement];
SELECT font.Correction[char]
FROM
none => NULL;
space => Imager.CorrectSpace[context, escapement];
mask => Imager.CorrectMask[context];
ENDCASE => ERROR;
};
worryNat: NAT ~ NAT.LAST/2-1;
worryReal:
REAL ← worryNat;
RasterShow:
PUBLIC
PROC [context: Context, string: XStringProc, xrel:
BOOL] ~ {
state: State ~ context.state;
data: Data ~ NARROW[context.data];
device: Device ~ data.device;
cache: ImagerCache.Ref ~ data.fontCache;
font: Font ~ state.font;
amplifySpace: REAL ~ state.np.amplifySpace;
testAmplified: BOOL ~ amplifySpace#1.0;
testCorrection: BOOL ~ state.np.correctPass#0;
imaging: BOOL ~ state.np.noImage=0;
basicCharAction:
PROC [char: XChar] ~ {
BasicShowChar[context, font, char, TRUE, imaging, data.fontTuner];
};
scaledCPValid: BOOL ← FALSE;
sCP: Scaled.Value;
fCP: Scaled.Value;
UpdateCP:
PROC ~ {
IF scaledCPValid THEN state.p.cp ← data.viewToDevice.InverseTransform[[sCP.Float, fCP.Float]];
};
TryScaledCP:
PROC ~ {
cp: VEC ← data.viewToDevice.Transform[state.p.cp];
IF
ABS[cp.x] < worryReal
AND
ABS[cp.y] < worryReal
THEN {
sCP ← Scaled.FromReal[cp.x];
fCP ← Scaled.FromReal[cp.y];
scaledCPValid ← TRUE;
}
ELSE scaledCPValid ← FALSE;
};
cachedCharAction:
PROC [char: XChar] ~ {
charIndex: CharArrayIndex ~ char.code MOD charArraySize;
prevMask: CharMask ~ data.charArray[charIndex];
charMask: CharMask ← prevMask;
Validate[data, state, showNeeds];
IF charMask#NIL AND charMask.font=data.fontAtom AND charMask.char=char THEN NULL
ELSE charMask ← ImagerCache.Fetch[cache, data.fontAtom, char];
IF charMask=
NIL
AND imaging
AND CharPartlyVisible[context, font, char]
THEN {
operator: PROC [c: Context] ~ {BasicShowChar[c, font, char, FALSE, TRUE, data.fontTuner]};
m: Transformation ← data.clientToDevice.TranslateTo[[0, 0]];
charMask ← ImagerMaskCapture.Capture[operator, m, data.rastWeight];
IF charMask#
NIL
THEN {
charMask.font ← data.fontAtom;
charMask.char ← char;
UNTIL ImagerCache.Store[cache, charMask].ok DO ImagerCache.Flush[cache] ENDLOOP;
};
};
IF charMask=
NIL
OR
NOT charMask.metricsValid
OR
NOT scaledCPValid
THEN {
UpdateCP[];
basicCharAction[char];
TryScaledCP[];
}
ELSE {
sCPOld: Scaled.Value ~ sCP;
fCPOld: Scaled.Value ~ fCP;
s: INTEGER ~ Scaled.Round[sCPOld];
f: INTEGER ~ Scaled.Round[fCPOld];
IF imaging
AND charMask.sSizeBB#0
THEN {
ShowCharacterMask[data: data, mask: charMask, s: s, f: f];
};
IF testCorrection
OR (testAmplified
AND charMask.amplified)
THEN {
escapement: VEC ← font.Escapement[char];
IF testAmplified
AND font.Amplified[char]
THEN {
escapement ← escapement.Mul[amplifySpace];
};
UpdateCP[];
Imager.SetXYRel[context, escapement];
IF testCorrection
THEN
SELECT font.Correction[char]
FROM
none => NULL;
space => Imager.CorrectSpace[context, escapement];
mask => Imager.CorrectMask[context];
ENDCASE => ERROR;
TryScaledCP[];
}
ELSE {
sCPNew: Scaled.Value ~ (sCP ← sCPOld.PLUS[charMask.sEscapement]);
fCPNew: Scaled.Value ~ (fCP ← fCPOld.PLUS[charMask.fEscapement]);
IF sCPNew.integerPart NOT IN [-worryNat..worryNat]
OR fCPNew.integerPart
NOT
IN [-worryNat..worryNat]
THEN {
UpdateCP[];
TryScaledCP[];
};
};
IF charMask#prevMask THEN data.charArray[charIndex] ← charMask;
};
};
oddCharIndex: BOOL ← FALSE;
xRelAction:
PROC [char: XChar] ~ {
IF oddCharIndex
THEN {
Imager.SetXRel[context, char.code-128];
}
ELSE IF cache=NIL THEN basicCharAction[char]
ELSE {
TryScaledCP[];
cachedCharAction[char];
UpdateCP[];
};
oddCharIndex ← NOT oddCharIndex;
};
saveAction:
PROC ~ {
Validate[data, state, showNeeds];
IF xrel THEN string[xRelAction]
ELSE IF cache=NIL THEN string[basicCharAction]
ELSE {
TryScaledCP[];
string[cachedCharAction];
UpdateCP[];
};
};
IF state.font=NIL THEN ERROR Imager.Error[[code: $noFont,
explanation: "Failed to set font before calling Show."]];
Imager.DoSave[context, saveAction];
};
ShowCharacterMask:
PUBLIC
PROC [data: Data, mask: CharMask, s:
INTEGER, f:
INTEGER] ~ {
sMin: INTEGER ~ s+mask.sMinBB;
fMin: INTEGER ~ f+mask.fMinBB;
device: Device ~ data.device;
allVisible: BOOL ← FALSE;
partlyVisible: BOOL ← TRUE;
partlyClipped: BOOL ← FALSE;
charBox: DeviceBox ← [
smin: LOOPHOLE[sMin],
fmin: LOOPHOLE[fMin],
smax: LOOPHOLE[sMin, CARDINAL]+mask.sSizeBB,
fmax: LOOPHOLE[fMin, CARDINAL]+mask.fSizeBB
];
IF AndFlags[data.valid, showNeeds]#showNeeds THEN oops ← oops + 1;
IF sMin < 0
OR fMin < 0
THEN {
charBox ← [
smin: MAX[sMin, 0],
fmin: MAX[fMin, 0],
smax: MAX[sMin+INTEGER[mask.sSizeBB], 0],
fmax: MAX[fMin+INTEGER[mask.fSizeBB], 0]
];
partlyClipped ← TRUE;
};
IF data.clientClipBoxOnly
THEN {
dBB: DeviceBox ~ data.clientClipBox;
IF
NOT partlyClipped
AND charBox.smin >= dBB.smin
AND charBox.fmin >= dBB.fmin
AND charBox.smax <= dBB.smax
AND charBox.fmax <= dBB.fmax
THEN {
allVisible ← TRUE;
}
ELSE
IF charBox.smax <= dBB.smin
OR charBox.fmax <= dBB.fmin
OR charBox.smin >= dBB.smax
OR charBox.fmin > dBB.fmax
THEN {
partlyVisible ← FALSE;
};
}
ELSE IF charBox.smax = 0 OR charBox.fmax = 0 THEN partlyVisible ← FALSE
ELSE
IF device.class.MaskChar #
NIL
THEN {
p: ManhattanPolygon ~ ImagerManhattan.CreateFromBox[[sMin, fMin, mask.sSizeBB, mask.fSizeBB]];
SELECT ImagerManhattan.IsVisible[p, data.clientClipMask]
FROM
invisible => partlyVisible ← FALSE;
visible => allVisible ← TRUE;
ENDCASE => NULL;
ImagerManhattan.Destroy[p];
};
IF allVisible AND (device.class.MaskChar # NIL) THEN device.class.MaskChar[device, s, f, mask]
ELSE
IF partlyVisible
THEN
WITH mask
SELECT
FROM
raster:
REF ImagerDevice.CharMaskRep.raster => {
boxes:
PROC[action:
PROC[DeviceBox]] ~ {
ClipBoxToMask[box: charBox, mask: data.clientClipMask, action: action];
};
TRUSTED {device.class.MaskBits[device: device,
srcBase: @raster[0],
srcWordsPerLine: (raster.fSizeBB+(bitsPerWord-1))/bitsPerWord,
ts: sMin,
tf: fMin,
boxes: boxes
]};
};
runs:
REF ImagerDevice.CharMaskRep.runs => {
FOR p: ManhattanPolygon ← data.clientClipMask, p.rest
UNTIL p=
NIL
DO
Runs:
PROC [run: ImagerDevice.RunProc] ~ {
ImagerMask.RunsFromCharMask[mask, run, s, f, p.first];
};
bounds: DeviceBox ~ DeviceBoxFromDeviceRectangle[p.first];
smin: CARDINAL ~ MAX[charBox.smin, bounds.smin];
smax: CARDINAL ~ MIN[charBox.smax, bounds.smax];
fmin: CARDINAL ~ MAX[charBox.fmin, bounds.fmin];
fmax: CARDINAL ~ MIN[charBox.fmax, bounds.fmax];
IF smin<smax
AND fmin<fmax
THEN {
device.class.MaskRuns[device: device, bounds: [smin: smin, fmin: fmin, smax: smax, fmax: fmax], runs: Runs];
};
ENDLOOP;
};
ENDCASE => ERROR;
};
RasterShowText:
PUBLIC PROC [context: Context,
text:
REF
READONLY
TEXT, start, len:
NAT, xrel:
BOOL] ~ {
class: Class ~ context.class;
string: XStringProc ~ { ImagerFont.MapText[text, start, len, charAction] };
class.Show[context, string, xrel];
};
END.