ImagerFastShowImpl.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Michael Plass, November 19, 1985 3:17:29 pm PST
Doug Wyatt, November 11, 1985 5:29:23 pm PST
DIRECTORY
Basics USING [BITAND, bitsPerWord, LongMult],
FunctionCache USING [Cache, CompareProc, Create, Insert, Lookup],
Imager USING [ClassRep, Context, SetXYRel, StateRep],
ImagerBitmapDevicePrivate USING [Data],
ImagerCache USING [Fetch, GetNamedCache, Ref],
ImagerDevice USING [CharMaskRep, Device],
ImagerFastShow USING [],
ImagerFont USING [Font, XChar, XStringProc],
ImagerFontPrivate USING [FontAtom],
ImagerPixelMap USING [DeviceRectangle, PixelMap],
ImagerPrivate USING [ClassRep],
ImagerRaster USING [Create, CreateClass, FontTuner, NewBitmapDevice],
ImagerRasterPrivate USING [AndFlags, Data, Flags, NoteStateChanges, RasterShow, ValidateIfNeeded],
ImagerState USING [notChanged, State, StateRep],
ImagerTransformation USING [InverseTransform, Transform, Transformation],
PrincOps USING [BBTableSpace, BitBltFlags, BitBltTablePtr],
PrincOpsUtils USING [AlignedBBTable, BITBLT],
Real,
Scaled USING [Float, FromReal, half, MINUS, PLUS, Value, zero],
Vector2 USING [Mul, VEC];
ImagerFastShowImpl: CEDAR PROGRAM
IMPORTS Basics, FunctionCache, Imager, ImagerCache, ImagerRaster, ImagerRasterPrivate, ImagerTransformation, PrincOpsUtils, Real, Scaled, Vector2
EXPORTS Imager, ImagerFastShow
~ BEGIN OPEN ImagerRasterPrivate;
bitsPerWord: NAT ~ Basics.bitsPerWord;
ClassRep: PUBLIC TYPE ~ ImagerPrivate.ClassRep; -- export to Imager.ClassRep
Context: TYPE ~ Imager.Context;
Device: TYPE ~ ImagerDevice.Device;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
Font: TYPE ~ ImagerFont.Font;
FontAtom: TYPE ~ ImagerFontPrivate.FontAtom;
RasterMask: TYPE ~ REF ImagerDevice.CharMaskRep.raster;
State: TYPE ~ ImagerState.State;
StateRep: PUBLIC TYPE ~ ImagerState.StateRep; -- export to Imager.StateRep
Transformation: TYPE ~ ImagerTransformation.Transformation;
VEC: TYPE ~ Vector2.VEC;
XChar: TYPE ~ ImagerFont.XChar;
XStringProc: TYPE ~ ImagerFont.XStringProc;
fastShowClass: REF Imager.ClassRep ~ FastShowClass[];
FastShowClass: PROC RETURNS [c: REF ImagerPrivate.ClassRep] ~ {
c ← ImagerRaster.CreateClass[$FastShowBitmap];
IF c.Show # ImagerRasterPrivate.RasterShow THEN ERROR;
c.Show ← FastShow;
};
rastWeight: REAL ← 2.0;
Create: PUBLIC PROC [pm: ImagerPixelMap.PixelMap, pixelsPerInch: REAL ← 72, pixelUnits: BOOL, fontTuner: ImagerRaster.FontTuner] RETURNS [Context] ~ {
device: ImagerDevice.Device ~ ImagerRaster.NewBitmapDevice[
frame: pm, pixelsPerInch: pixelsPerInch];
bitmapFontCache: ImagerCache.Ref ~ ImagerCache.GetNamedCache[
atom: $Bitmap, createSize: 4000];
RETURN[ImagerRaster.Create[device: device, pixelUnits: pixelUnits, fontCache: bitmapFontCache, rastWeight: rastWeight, fontTuner: fontTuner, class: fastShowClass]];
};
Validate: PROC [data: ImagerRasterPrivate.Data, state: State, needs: ImagerRasterPrivate.Flags] RETURNS [BOOL] ~ INLINE {
IF state.changed#ImagerState.notChanged THEN ImagerRasterPrivate.NoteStateChanges[data, state];
IF ImagerRasterPrivate.AndFlags[data.valid, needs]#needs THEN ImagerRasterPrivate.ValidateIfNeeded[data, state, needs];
RETURN [TRUE]
};
showNeeds: ImagerRasterPrivate.Flags ~ [clientClipper: TRUE, deviceColor: TRUE, devicePriority: TRUE, clientToDevice: TRUE, fontInfo: TRUE];
worryNat: NAT ~ NAT.LAST/2-1;
worryReal: REAL ← worryNat;
space: XChar ~ [0, ORD[' ]];
Trust: UNSAFE PROC [INTEGER] RETURNS [NAT] ~ UNCHECKED MACHINE CODE {};
NatBox: TYPE ~ RECORD [smin, fmin, smax, fmax: NAT];
SSizeOf: PROC [b: NatBox] RETURNS [NAT] ~ INLINE {
RETURN [b.smax - b.smin]
};
ContainingBox: PROC [s, f: INTEGER, boxes: LIST OF DeviceRectangle] RETURNS [b: NatBox] ~ {
FOR p: LIST OF DeviceRectangle ← boxes, p.rest UNTIL p=NIL DO
d: DeviceRectangle ~ p.first;
IF s IN [d.sMin..d.sMin+d.sSize) AND f IN [d.fMin..d.fMin+d.fSize)
THEN RETURN [[
smin: MAX[d.sMin, 0],
fmin: MAX[d.fMin, 0],
smax: MAX[d.sMin+d.sSize, 0],
fmax: MAX[d.fMin+d.fSize, 0]
]]
ENDLOOP;
RETURN [[0,0,0,0]]
};
sSizeBoxMin: NAT ← 4;
CommonChar: TYPE ~ [32..127];
charArrayCache: FunctionCache.Cache ← FunctionCache.Create[maxEntries: 24];
GetCharArray: 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]];
};
};
Ord: PROC [char: XChar] RETURNS [CARDINAL] ~ INLINE {RETURN [LOOPHOLE[char]]};
FastShow: PROC [context: Context, string: XStringProc, xrel: BOOL] ~ {
state: State ~ context.state;
rasterData: Data ~ NARROW[context.data];
device: Device ~ rasterData.device;
bitmapData: ImagerBitmapDevicePrivate.Data ~ NARROW[device.data];
cache: ImagerCache.Ref ~ rasterData.fontCache;
font: Font ~ state.font;
valid: BOOL ← Validate[rasterData, state, showNeeds];
scaledCPValid: BOOLFALSE;
sCP: Scaled.Value; -- device coordinates, offset by 1/2 pixel
fCP: Scaled.Value; -- ditto
box: NatBox;
UpdateCP: PROC ~ {
IF scaledCPValid
THEN state.p.cp ← rasterData.viewToDevice.InverseTransform[
[sCP.MINUS[Scaled.half].Float, fCP.MINUS[Scaled.half].Float]
];
};
TryScaledCP: PROC RETURNS [BOOL]~ {
cp: VEC ← rasterData.viewToDevice.Transform[state.p.cp];
IF ABS[cp.x] < worryReal AND ABS[cp.y] < worryReal THEN {
sCP ← Scaled.FromReal[cp.x].PLUS[Scaled.half];
fCP ← Scaled.FromReal[cp.y].PLUS[Scaled.half];
scaledCPValid ← TRUE;
}
ELSE scaledCPValid ← FALSE;
IF scaledCPValid THEN box ← ContainingBox[s: sCP.integerPart, f: fCP.integerPart, boxes: rasterData.clientClipMask];
RETURN [scaledCPValid]
};
charArray: REF ARRAY CommonChar OF RasterMask ← GetCharArray[rasterData.fontAtom];
Lookup: PROC [char: XChar] RETURNS [m: RasterMask ← NIL] ~ {
WITH ImagerCache.Fetch[cache, rasterData.fontAtom, char] SELECT FROM
r: RasterMask => {
IF MAX[r.sSizeBB, r.fSizeBB, ABS[r.sEscapement.integerPart], ABS[r.fEscapement.integerPart]] < worryNat 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;
};
lastAmplified: RasterMask ← NIL;
sCPAmp: Scaled.Value ← Scaled.zero;
fCPAmp: Scaled.Value ← Scaled.zero;
Amplify: PROC [m: RasterMask] ~ {
IF m # lastAmplified THEN {
IF state.np.amplifySpace = 1.0 THEN {
sCPAmp ← m.sEscapement;
fCPAmp ← m.fEscapement;
}
ELSE {
escapement: VEC ~ Vector2.Mul[[m.sEscapement.Float, m.fEscapement.Float], state.np.amplifySpace];
IF MAX[ABS[escapement.x], ABS[escapement.y]] < worryReal THEN {
sCPAmp ← Scaled.FromReal[escapement.x];
fCPAmp ← Scaled.FromReal[escapement.y];
}
ELSE {
UpdateCP[];
Imager.SetXYRel[context, escapement];
[] ← TryScaledCP[];
RETURN;
};
};
lastAmplified ← m;
};
sCP ← sCP.PLUS[sCPAmp];
fCP ← fCP.PLUS[fCPAmp];
};
IF NOT xrel
AND bitmapData.case = constant
AND (state.np.correctPass = 0 OR (state.np.correctPass = 2 AND state.p.correctMask.x=0.0 AND state.p.correctMask.y=0.0 AND state.p.correctSpace.x=0.0 AND state.p.correctSpace.y=0.0))
AND state.np.noImage = 0
AND cache # NIL
AND TryScaledCP[]
AND SSizeOf[box] > sSizeBoxMin
THEN TRUSTED {
dstBase: LONG POINTER ~ bitmapData.frame.pointer;
dstWpl: NAT ~ bitmapData.frame.rast;
bbspace: PrincOps.BBTableSpace;
bbPtr: PrincOps.BitBltTablePtr ~ InitBITBLT[];
InitBITBLT: PROC RETURNS [PrincOps.BitBltTablePtr] ~ TRUSTED {
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
flags: PrincOps.BitBltFlags ← bitmapData.maskBitsFlags;
flags.gray ← FALSE; flags.disjoint ← TRUE;
bb.dst ← [word: NIL, bit: 0];
bb.dstBpl ← dstWpl*bitsPerWord;
bb.src ← [word: NIL, bit: 0];
bb.flags ← flags;
RETURN [bb];
};
FastCharAction: PROC [char: XChar] ~ TRUSTED {
bb: PrincOps.BitBltTablePtr ~ bbPtr;
m: RasterMask ← NIL;
QuickLook: PROC RETURNS [ok: BOOL] ~ CHECKED INLINE {
IF Ord[char] IN CommonChar THEN {
m ← charArray[Ord[char]];
IF m # NIL THEN RETURN [TRUE];
};
m ← Lookup[char];
RETURN [m#NIL]
};
s0, f0: INTEGER;
sSize, fSize: NAT;
fast: BOOL ~ (
scaledCPValid
AND QuickLook[]
AND (s0 ← sCP.integerPart + m.sMinBB) >= box.smin
AND (f0 ← fCP.integerPart + m.fMinBB) >= box.fmin
AND (s0 + (sSize ← LOOPHOLE[m.sSizeBB])) <= box.smax
AND (f0 + (fSize ← LOOPHOLE[m.fSizeBB])) <= box.fmax
);
IF fast THEN {
IF sSize # 0 THEN {
bplMask: CARDINAL ~ LAST[CARDINAL]-(bitsPerWord-1);
bb.dst.word ← dstBase + Basics.LongMult[Trust[s0], dstWpl] + Trust[f0]/bitsPerWord;
bb.dst.bit ← Trust[f0] MOD bitsPerWord;
bb.height ← sSize;
bb.width ← fSize;
bb.src.word ← @m[0];
bb.srcDesc ← [srcBpl[LOOPHOLE[Basics.BITAND[fSize+(bitsPerWord-1), bplMask]]]];
PrincOpsUtils.BITBLT[bb];
};
IF NOT m.amplified THEN {
fCP ← fCP.PLUS[m.fEscapement];
sCP ← sCP.PLUS[m.sEscapement];
}
ELSE IF m = lastAmplified THEN {
sCP ← sCP.PLUS[sCPAmp];
fCP ← fCP.PLUS[fCPAmp];
}
ELSE Amplify[m];
}
ELSE {
oneChar: XStringProc ~ CHECKED {charAction[char]};
UpdateCP[];
ImagerRasterPrivate.RasterShow[context, oneChar, FALSE];
[] ← TryScaledCP[];
};
};
string[FastCharAction];
UpdateCP[];
}
ELSE ImagerRasterPrivate.RasterShow[context, string, xrel];
};
END.