ImagerRasterShowImpl.mesa
Copyright Ó 1986 by Xerox Corporation. All rights reserved.
Michael Plass, November 26, 1986 4:22:52 pm PST
DIRECTORY
Basics USING [BITAND, bitsPerWord],
FunctionCache USING [Cache, CompareProc, Create, Insert, Lookup],
II,
IIBackdoor,
IIBox,
IIFont,
IIMaskCache USING [CharMask, CharMaskRep, Fetch, MaskCache, ScaledVec, Store],
IIMaskCapture USING [CaptureChar],
IIRaster USING [GetContainingBox],
IIRasterShow USING [CommonChar, GetShowData, MaskCharMask, ShowData, zeroScaledVec],
IISample,
IIState USING [State, StateRep],
IITransformation,
IITypeface,
Real,
Scaled USING [Float, FromReal, half, MINUS, PLUS, Value],
SF,
Vector2 USING [Mul, VEC];
IIRasterShowImpl: CEDAR PROGRAM
IMPORTS Basics, FunctionCache, II, IIBackdoor, IIFont, IIMaskCache, IIMaskCapture, IIRaster, IIRasterShow, IITransformation, IITypeface, Real, Scaled, SF, Vector2
EXPORTS II, IIRasterShow
~ BEGIN
State: TYPE ~ IIState.State;
StateRep: PUBLIC TYPE ~ IIState.StateRep; -- export to II.StateRep
CharMask: TYPE ~ IIMaskCache.CharMask;
CharMaskRep: TYPE ~ IIMaskCache.CharMaskRep;
Context: TYPE ~ II.Context;
CorrectionType: TYPE ~ IIFont.CorrectionType;
Extents: TYPE ~ IIBox.Extents;
Font: TYPE ~ IIFont.Font;
RawArray: TYPE ~ IISample.RawArray;
RawDescriptor: TYPE ~ IISample.RawDescriptor;
ScaledVec: TYPE ~ IIMaskCache.ScaledVec;
ShowData: TYPE ~ IIRasterShow.ShowData;
Transformation: TYPE ~ IITransformation.Transformation;
Typeface: TYPE ~ IITypeface.Typeface;
VEC: TYPE ~ Vector2.VEC;
XChar: TYPE ~ IIFont.XChar;
bitsPerWord: NAT ~ Basics.bitsPerWord;
nullXChar: XChar ~ IIFont.nullXChar;
rawArraySize: NAT ~ IISample.rawArraySize;
worryNat: NAT ~ LAST[NAT]/2-1;
worryReal: REAL ← worryNat;
zeroScaledVec: ScaledVec ~ IIRasterShow.zeroScaledVec;
BitFont
bitFont: II.Font ~ IITypeface.MakeFont[MakeBitTypeface[], IITransformation.Scale[1]];
MakeBitTypeface: PROC RETURNS [IITypeface.Typeface] ~ {
class: IITypeface.TypefaceClass ← NEW[IITypeface.TypefaceClassRep ← [type: $BitTypeface, Contains: BitContains, NextChar: BitNextChar, Escapement: BitEscapement, Amplified: BitAmplified, Correction: BitCorrection, BoundingBox: BitBoundingBox, FontBoundingBox: BitFontBoundingBox, Ligature: BitLigature, NextLigature: BitNextLigature, Kern: BitKern, NextKern: BitNextKern, Mask: BitMask]];
typeface: IITypeface.Typeface ← NEW[IITypeface.TypefaceRep ← [class: class, data: NIL]];
RETURN [typeface]
};
BitContains: PROC [self: Typeface, char: XChar] RETURNS [BOOL] ~ {RETURN [char.set = 0]};
BitNextChar: PROC [self: Typeface, char: XChar] RETURNS [next: XChar] ~ {RETURN [IF char = nullXChar THEN [0, 0] ELSE IF char.set # 0 OR char.code = 255 THEN nullXChar ELSE [0, char.code+1]]};
BitEscapement: PROC [self: Typeface, char: XChar] RETURNS [VEC] ~ {RETURN [[0, 8]]};
BitAmplified: PROC [self: Typeface, char: XChar] RETURNS [BOOL] ~ {RETURN [FALSE]};
BitCorrection: PROC [self: Typeface, char: XChar] RETURNS [CorrectionType] ~ {RETURN [none]};
BitBoundingBox: PROC [self: Typeface, char: XChar] RETURNS [Extents] ~ {
RETURN [[leftExtent: 0, rightExtent: 1, descent: 0, ascent: 8]];
};
BitFontBoundingBox: PROC [self: Typeface] RETURNS [Extents] ~ {
RETURN [[leftExtent: 0, rightExtent: 1, descent: 0, ascent: 8]];
};
BitLigature: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ {
RETURN [nullXChar];
};
BitNextLigature: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ {
RETURN [nullXChar];
};
BitKern: PROC [self: Typeface, char, successor: XChar] RETURNS [VEC] ~ {
RETURN [[0,0]];
};
BitNextKern: PROC [self: Typeface, char, successor: XChar] RETURNS [XChar] ~ {
RETURN [[0,0]];
};
BitMask: PROC [self: Typeface, char: XChar, context: II.Context] ~ {
k: CARDINAL ← char.code;
bloat: REAL ← 0.499/IITransformation.SingularValues[IIBackdoor.GetT[context]].x;
II.SetStrokeEnd[context, round];
II.SetStrokeJoint[context, round];
II.SetStrokeWidth[context, 0];
FOR i: NAT IN [0..8) DO
IF k >= 128 THEN {
k ← k - 128;
II.MaskRectangle[context, [x: -bloat, y: i-bloat, w: 1+2*bloat, h: 1+2*bloat]];
};
k ← 2*k;
ENDLOOP;
};
BitFont: PUBLIC PROC RETURNS [IIFont.Font] ~ {RETURN [bitFont]};
Show
BasicShowChar: PUBLIC PROC [context: Context, char: XChar] ~ {
state: State ~ context.state;
amplifySpace: REAL ~ state.np.amplifySpace;
proc: PROC ~ {
font: Font ~ state.font;
escapement: VEC ← IIFont.Escapement[font, char];
IF amplifySpace#1.0 AND IIFont.Amplified[font, char] THEN {
escapement ← Vector2.Mul[escapement, amplifySpace];
};
II.Trans[context];
IF state.np.noImage = 0 THEN {
IITypeface.MaskChar[font, char, context]
};
II.SetXYRel[context, escapement];
SELECT IIFont.Correction[font, char] FROM
none => NULL;
space => II.CorrectSpace[context, escapement];
mask => II.CorrectMask[context];
ENDCASE => ERROR;
};
II.DoSave[context, proc];
};
RasterShow: PUBLIC PROC [context: Context, string: IIFont.XStringProc, xrel: BOOL] ~ {
state: State ~ context.state;
showData: IIRasterShow.ShowData ~ IIRasterShow.GetShowData[context];
basic: BOOL ~ showData.fontCache = NIL;
BasicCharAction: PROC [char: XChar] ~ { BasicShowChar[context, char] };
CachedCharAction: PROC [char: XChar] ~ { CachedShowChar[context, char] };
oddCharIndex: BOOLFALSE;
XRelAction: PROC [char: XChar] ~ {
IF oddCharIndex THEN II.SetXRel[context, char.code-128] ELSE (IF basic THEN BasicCharAction ELSE CachedCharAction)[char];
};
IF xrel THEN string[XRelAction] ELSE string[IF basic THEN BasicCharAction ELSE CachedCharAction];
};
CachedShowChar: PUBLIC PROC [context: Context, char: XChar] ~ {
state: State ~ context.state;
showData: IIRasterShow.ShowData ~ IIRasterShow.GetShowData[context];
fontCache: IIMaskCache.MaskCache ~ showData.fontCache;
charMask: CharMask ← NIL;
visible: BOOL ← state.np.noImage = 0;
amplifying: BOOL ~ state.np.amplifySpace # 1.0;
correcting: BOOL ~ state.np.correctPass # 0;
escapement: VEC ← [0, 0];
charMask ← IIMaskCache.Fetch[fontCache, showData.fontAtom, char];
IF charMask = NIL THEN {
cp: VEC ~ IITransformation.Transform[showData.viewToDevice, state.p.cp];
bb: IIBox.Box ~ showData.fontBB;
compositeBox: SF.Box ~ showData.clipBounds;
clippedBox: IIBox.Box ~ [
xmin: MAX[REAL[compositeBox.min.s], bb.xmin+cp.x],
ymin: MAX[REAL[compositeBox.min.f], bb.ymin+cp.y],
xmax: MIN[REAL[compositeBox.max.s], bb.xmax+cp.x],
ymax: MIN[REAL[compositeBox.max.f], bb.ymax+cp.y]
];
IF clippedBox.xmin >= clippedBox.xmax OR clippedBox.ymin >= clippedBox.ymax
THEN { visible ← FALSE }
ELSE {
charMask ← IIMaskCapture.CaptureChar[font: showData.fontAtom, char: char, ratio: showData.deviceParm.rastWeight, fontTuner: showData.deviceParm.fontTuner, metricsOnly: FALSE];
IF charMask # NIL THEN [] ← IIMaskCache.Store[fontCache, charMask];
};
IF charMask = NIL THEN {
save: INT ~ state.np.noImage;
IF NOT visible THEN state.np.noImage ← 1; -- Save some work if we know it's invisible
BasicShowChar[context, char];
state.np.noImage ← save;
RETURN
};
};
IF visible THEN {
ok: BOOL ~ IIRasterShow.MaskCharMask[context, charMask];
IF NOT ok THEN {BasicShowChar[context, char]; RETURN};
};
escapement ← IIBackdoor.TransformVec[
context: context,
v: [x: Scaled.Float[charMask.escapement.s], y: Scaled.Float[charMask.escapement.f]],
from: device, to: client];
IF amplifying AND charMask.amplified THEN {
escapement ← Vector2.Mul[escapement, state.np.amplifySpace];
};
II.SetXYRel[context, escapement];
IF correcting THEN SELECT charMask.correction FROM
none => NULL;
space => II.CorrectSpace[context, escapement];
mask => II.CorrectMask[context];
ENDCASE => ERROR;
};
Fast Show
VECFromSV: PROC [sv: ScaledVec] RETURNS [VEC] ~ INLINE {
RETURN [[x: Scaled.Float[sv.s], y: Scaled.Float[sv.f]]]
};
SVFromVEC: PROC [v: VEC] RETURNS [ScaledVec] ~ INLINE {
RETURN [[s: Scaled.FromReal[v.x], f: Scaled.FromReal[v.y]]]
};
SVAdd: PROC [a, b: ScaledVec] RETURNS [ScaledVec] ~ INLINE {
RETURN [[s: Scaled.PLUS[a.s, b.s], f: Scaled.PLUS[a.f, b.f]]]
};
SVSub: PROC [a, b: ScaledVec] RETURNS [ScaledVec] ~ INLINE {
RETURN [[s: Scaled.MINUS[a.s, b.s], f: Scaled.MINUS[a.f, b.f]]]
};
cpOffset: ScaledVec ~ [Scaled.half, Scaled.half];
FlushState: PUBLIC PROC [state: State, showData: ShowData] ~ {
IF showData.valid THEN {
state.p.cp ← IITransformation.InverseTransform[showData.viewToDevice, VECFromSV[SVSub[showData.cp, cpOffset]]];
SELECT showData.correctPass FROM
1 => state.p.correctSum ← IITransformation.InverseTransformVec[showData.viewToDevice, VECFromSV[showData.correctSum]];
ENDCASE => NULL;
showData.valid ← FALSE;
};
};
TryFastState: PUBLIC PROC [state: State, showData: ShowData] ~ {
cp: VEC ~ IITransformation.Transform[showData.viewToDevice, state.p.cp];
showData.correctPass ← SELECT state.np.correctPass FROM 1 => 1, 2 => 2 ENDCASE => 0;
showData.valid ← (
ABS[cp.x] < worryReal AND
ABS[cp.y] < worryReal AND
ABS[state.np.amplifySpace] < 4.0
);
IF showData.valid AND showData.correctPass = 1 THEN {
s: VEC ~ IITransformation.TransformVec[showData.viewToDevice, state.p.correctSum];
showData.valid ← (ABS[s.x] < worryReal AND ABS[s.y] < worryReal);
IF showData.valid THEN showData.correctSum ← SVFromVEC[s];
};
IF showData.valid AND showData.correctPass = 2 THEN {
s: VEC ~ IITransformation.TransformVec[showData.viewToDevice, state.p.correctMask];
showData.valid ← (ABS[s.x] < worryReal AND ABS[s.y] < worryReal);
IF showData.valid THEN {
showData.correctMask ← SVFromVEC[s];
showData.lastUnCorrectedSpace ← zeroScaledVec;
showData.lastCorrectedSpace ← zeroScaledVec;
};
};
IF showData.valid THEN {
showData.cp ← SVAdd[SVFromVEC[cp], cpOffset];
};
};
DoCharMetrics: PUBLIC PROC [state: State, showData: ShowData, m: IIMaskCache.CharMask] ~ {
esc: ScaledVec ← m.escapement;
IF NOT showData.valid THEN ERROR;
IF m.amplified THEN {
IF m # showData.lastAmpMask THEN {
IF state.np.amplifySpace = 1.0
THEN { showData.lastAmp ← esc }
ELSE {
e: VEC ~ VECFromSV[esc];
es: VEC ~ Vector2.Mul[e, state.np.amplifySpace];
showData.lastAmp ← SVFromVEC[e];
};
showData.lastAmpMask ← m;
};
esc ← showData.lastAmp;
};
SELECT showData.correctPass FROM
1 => {
SELECT m.correction FROM
mask => state.p.correctMaskCount ← state.p.correctMaskCount+1;
space => { showData.correctSum ← SVAdd[showData.correctSum, esc] };
ENDCASE => NULL;
};
2 => {
SELECT m.correction FROM
mask => {
IF state.p.correctMaskCount#0 THEN {
esc ← SVAdd[esc, showData.correctMask];
state.p.correctMaskCount ← state.p.correctMaskCount-1;
};
};
space => {
IF esc # showData.lastUnCorrectedSpace THEN {
cs: VEC ~ state.p.correctSpace;
e1: VEC ~ VECFromSV[esc];
e2: VEC ~ IITransformation.InverseTransformVec[showData.viewToDevice, e1];
e3: VEC ~ [x: (cs.x+1.0)*e2.x, y: (cs.y+1.0)*e2.y];
e4: VEC ~ IITransformation.TransformVec[showData.viewToDevice, e3];
showData.lastCorrectedSpace ← SVFromVEC[e4];
};
esc ← showData.lastCorrectedSpace
};
ENDCASE => NULL;
};
ENDCASE => NULL;
showData.cp.s ← showData.cp.s.PLUS[esc.s];
showData.cp.f ← showData.cp.f.PLUS[esc.f];
IF ABS[showData.cp.s.integerPart] >= worryNat OR ABS[showData.cp.f.integerPart] >= worryNat THEN FlushState[state, showData];
};
RasterMask: TYPE ~ REF IIMaskCache.CharMaskRep.raster;
CommonChar: TYPE ~ IIRasterShow.CommonChar;
charArrayCache: FunctionCache.Cache ← FunctionCache.Create[maxEntries: 24];
Ord: PROC [char: XChar] RETURNS [CARDINAL] ~ INLINE {RETURN [LOOPHOLE[char]]};
GetCharArray: PUBLIC PROC [fontAtom: REF] RETURNS [r: REF ARRAY CommonChar OF RasterMask] ~ {
compare: FunctionCache.CompareProc ~ {RETURN [argument = fontAtom]};
r ← NARROW[FunctionCache.Lookup[charArrayCache, compare].value];
IF r = NIL THEN {
r ← NEW[ARRAY CommonChar OF RasterMask ← ALL[NIL]];
[] ← FunctionCache.Insert[charArrayCache, fontAtom, r, SIZE[ARRAY CommonChar OF RasterMask]];
};
};
CommonCharLookup: PUBLIC PROC [showData: ShowData, charArray: REF ARRAY CommonChar OF RasterMask, char: XChar] RETURNS [m: RasterMask ← NIL] ~ {
WITH IIMaskCache.Fetch[showData.fontCache, showData.fontAtom, char] SELECT FROM
r: RasterMask => {
IF MAX[SF.SizeS[r.box], SF.SizeF[r.box], ABS[r.escapement.s.integerPart], ABS[r.escapement.f.integerPart]] < worryNat/8 THEN {
m ← r;
IF Ord[char] IN CommonChar THEN {
charArray[Ord[char]] ← m;
N.B. Uses the fact that ref assignment is atomic to avoid the need for a monitor.
};
};
};
ENDCASE => NULL;
};
FastShow: PUBLIC PROC [context: Context, string: IIFont.XStringProc, xrel: BOOL] ~ {
state: State ~ context.state;
showData: IIRasterShow.ShowData ~ IIRasterShow.GetShowData[context];
noImage: BOOL ~ (state.np.noImage#0);
easyMetrics: BOOL ~ (state.np.amplifySpace = 1.0 AND state.np.correctPass = 0);
box: SF.Box;
TryScaled: PROC RETURNS [BOOL] ~ INLINE {
TryFastState[state, showData];
IF showData.valid THEN { box ← IIRaster.GetContainingBox[context, [s: showData.cp.s.integerPart, f: showData.cp.f.integerPart]] };
RETURN [showData.valid];
};
IF NOT xrel AND showData.allow.rawBitmaps AND showData.fontCache # NIL AND TryScaled[] AND SF.SizeS[box] > 4 THEN {
charArray: REF ARRAY CommonChar OF RasterMask ← GetCharArray[showData.fontAtom];
a: RawArray;
p: POINTER TO RawDescriptor ← NIL;
n: [0..rawArraySize] ← 0;
Flush: PROC ~ TRUSTED INLINE
{ showData.deviceClass.MaskRawBitmaps[context, n, @a]; n ← 0; p ← @(a[0]) };
FastCharAction: PROC [char: XChar] ~ {
m: RasterMask ← NIL;
charBox: SF.Box;
QuickLook: PROC RETURNS [ok: BOOL] ~ INLINE {
IF Ord[char] IN CommonChar THEN {
m ← charArray[Ord[char]];
IF m = NIL THEN { m ← CommonCharLookup[showData, charArray, char]; IF m = NIL THEN RETURN [FALSE] }
};
charBox ← SF.Displace[m.box, [showData.cp.s.integerPart, showData.cp.f.integerPart]];
RETURN [TRUE]
};
IF showData.valid AND QuickLook[] THEN {
SELECT TRUE FROM
noImage => NULL;
SF.Inside[charBox, box] => {
fSize: INTEGER ~ charBox.max.f-charBox.min.f;
IF n = rawArraySize THEN Flush[];
IF fSize > 0 THEN TRUSTED {
bplMask: CARDINAL ~ LAST[CARDINAL]-(bitsPerWord-1);
pp: POINTER TO RawDescriptor ~ p;
pp.box.min ← charBox.min;
pp.box.max ← charBox.max;
pp.bitsPerLine ← Basics.BITAND[LOOPHOLE[fSize+(bitsPerWord-1)], bplMask];
pp.basePointer ← @(m[0]);
n ← n + 1;
p ← pp + SIZE[RawDescriptor];
};
IF easyMetrics THEN {
Can't overflow here because we were not clipped.
showData.cp.s ← showData.cp.s.PLUS[m.escapement.s];
showData.cp.f ← showData.cp.f.PLUS[m.escapement.f];
RETURN
};
};
SF.Empty[SF.Intersect[charBox, showData.clipBounds]] => { NULL };
ENDCASE => {
IF n # 0 THEN Flush[];
FlushState[state, showData];
IF NOT IIRasterShow.MaskCharMask[context, m] THEN ERROR; -- should never fail
showData.valid ← TRUE; -- Everything is really still valid
};
DoCharMetrics[state, showData, m];
RETURN;
};
IF n # 0 THEN Flush[];
FlushState[state, showData];
CachedShowChar[context, char];
TryFastState[state, showData];
};
TRUSTED {n ← 0; p ← @(a[0])};
string[FastCharAction];
FlushState[state, showData];
IF n # 0 THEN Flush[];
}
ELSE RasterShow[context, string, xrel];
};
END.