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];
~
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]]
};
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: BOOL ← FALSE;
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];
};