DIRECTORY
Basics USING [BITSHIFT, bitsPerWord, CARD, LongDivMod, LongMult, LongNumber, RawWords],
FunctionCache USING [Cache, CompareProc, GlobalCache, Insert, Lookup],
Imager USING [ClassRep, Context, DoSaveAll, Error, ScaleT],
ImagerCache USING [GetNamedCache, Ref],
ImagerColorDefs USING [Color, ColorOperator, ConstantColor, ConstantColorImplRep, SampledColor],
ImagerColorOperator USING [GetColorOperatorClass, Mapper, MapPixels, NewMapper],
ImagerColorPrivate USING [ConstantColorClass, ConstantColorClassRep, ConstantColorImpl, ConstantColorImplRep],
ImagerDevice USING [BoxProc, Class, ClassRep, Device, DeviceBox, DeviceRep, HalftoneParameters, RunProc],
ImagerGray USING [],
ImagerOps USING [PixelArrayFromPixelMaps],
ImagerPixelArray USING [GetPixels, MaxSampleValue],
ImagerPixelArrayDefs USING [PixelArray],
ImagerPixelMap USING [BoundedWindow, Clear, Clip, Copy, Create, DeviceRectangle, Fill, PixelMap, PixelMapRep, ShiftMap],
ImagerRaster USING [Create],
ImagerRasterPrivate USING [Data, DeviceRectangle],
ImagerSample USING [GetPointer, GetPointSamples, NewBuffer, Sample, SampleBuffer, Sampler, SamplerRep, SetSamplerIncrements, SetSamplerPosition, UnsafePutF, UnsafeSamples],
ImagerTransformation USING [ApplyPreRotate, Cat, Concat, Invert, Rectangle, Transformation, TransformRectangle, Translate],
PixelMapOps USING [],
PrincOps USING [BBTableSpace, BitBltFlags, BitBltTable, BitBltTablePtr, op, zBNDCK, zINC],
PrincOpsUtils USING [AlignedBBTable, BITBLT, LongZero],
Real USING [RoundC],
Vector2 USING [VEC];
~
BEGIN
VEC: TYPE ~ Vector2.VEC;
Transformation: TYPE ~ ImagerTransformation.Transformation;
Color: TYPE ~ ImagerColorDefs.Color;
ConstantColor: TYPE ~ ImagerColorDefs.ConstantColor;
SampledColor: TYPE ~ ImagerColorDefs.SampledColor;
ColorOperator: TYPE ~ ImagerColorDefs.ColorOperator;
PixelArray: TYPE ~ ImagerPixelArrayDefs.PixelArray;
PixelMap: TYPE ~ ImagerPixelMap.PixelMap;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
Sample: TYPE ~ ImagerSample.Sample;
Sampler: TYPE ~ ImagerSample.Sampler;
SampleBuffer: TYPE ~ ImagerSample.SampleBuffer;
UnsafeSamples: TYPE ~ ImagerSample.UnsafeSamples;
DeviceBox: TYPE ~ ImagerDevice.DeviceBox;
Rectangle: TYPE ~ ImagerTransformation.Rectangle;
Context: TYPE ~ Imager.Context;
Device: TYPE ~ ImagerDevice.Device;
RunProc: TYPE ~ ImagerDevice.RunProc;
BoxProc: TYPE ~ ImagerDevice.BoxProc;
ConstantColorImpl: TYPE ~ ImagerColorPrivate.ConstantColorImpl;
ConstantColorImplRep: PUBLIC TYPE ~ ImagerColorPrivate.ConstantColorImplRep;
ConstantColorClass: TYPE ~ ImagerColorPrivate.ConstantColorClass;
ConstantColorClassRep:
PUBLIC
TYPE ~ ImagerColorPrivate.ConstantColorClassRep;
bitsPerWord:
NAT ~ Basics.bitsPerWord;
Must use a version of ImagerRasterImpl that allows MaskBoxes and MaskBits to be NIL.
class: ImagerDevice.Class ~
NEW[ImagerDevice.ClassRep ← [
type: $Gray,
SetColor: GraySetColor,
SetPriority: GraySetPriority,
SetHalftone: GraySetHalftone,
MaskRuns: GrayMaskRuns,
MaskBoxes: NIL,
MaskBits: NIL,
MoveBoxes: GrayMoveBoxes
]];
Lg:
PROC [n:
NAT]
RETURNS [
NAT] ~ {
RETURN[SELECT n FROM 1 => 0, 2 => 1, 4 => 2, 8 => 3, 16 => 4, ENDCASE => ERROR]
};
fontCacheID: ATOM ~ $Gray;
fontCacheSize: NAT ← 4000;
fontRastWeight:
REAL ← 0.0;
Case:
TYPE ~ {nil, constant, stipple, sampled};
StippleArray:
TYPE ~
PACKED
ARRAY [0..16)
OF
WORD;
Data: TYPE ~ REF DataRep;
DataRep:
TYPE ~
RECORD[
component: ATOM,
pixelMap: ImagerPixelMap.PixelMap,
maxValue: Sample,
sOrigin, fOrigin: INTEGER, -- used for providing d to change proc.
deviceToPixel: Transformation,
change: PROC[changeData: REF, d: DeviceRectangle, action: PROC],
changeData: REF,
case: Case ← nil, -- what type of color
zerosAreClear: BOOL ← FALSE, -- special case for sampled black clear.
flags: PrincOps.BitBltFlags ← [], -- bitblt flags
grayWord: WORD ← 0, -- bitblt gray word
constant: Sample ← 0, -- for case = constant
stipple: StippleArray ← ALL[0], -- stipple pattern
fTileOrg: NAT ← 0,
sTileOrg: NAT ← 0,
sampledColor: ImagerColorDefs.SampledColor ← NIL, -- sampled color
sampledColorData: SampledColorData ← NIL, -- cached data associated with sampledColor
paToPixel: Transformation ← NIL, -- transformation from pa coords to pixelMap coords
sampBuffer: ImagerSample.SampleBuffer ←, -- scan line buffer for samples from sampledColor
lineBuffer: ImagerSample.SampleBuffer ←, -- for ops that cannot go directly to frame
sampler: ImagerSample.Sampler ← -- sampler information
];
SampledColorData: TYPE ~ REF SampledColorDataRep;
SampledColorDataRep:
TYPE ~
RECORD [
source: ImagerPixelMap.PixelMap,
key: SampledColorKey
];
MakePixelArray:
PUBLIC
PROC [action:
PROC [Context], sSize, fSize:
NAT, components:
LIST
OF
ATOM, viewToPixel: Transformation ←
NIL, initialScale:
REAL ← 1.0, lgBitsPerSample:
NAT ← 3, cacheFonts:
BOOL ←
TRUE, blackBackground:
BOOL ←
FALSE]
RETURNS [PixelArray] ~ {
pixelMap: PixelMap ~ ImagerPixelMap.Create[lgBitsPerSample, [0, 0, sSize, fSize]];
c: Context ~ Create[pixelMap: pixelMap, component: $Intensity, viewToPixel: viewToPixel, initialScale: initialScale, change: NIL, changeData: NIL, cacheFonts: cacheFonts];
proc: PROC ~ {action[c]};
list: LIST OF PixelMap ← NIL;
last: LIST OF PixelMap ← NIL;
FOR a:
LIST
OF
ATOM ← components, a.rest
UNTIL a=
NIL
DO
pm: PixelMap;
IF blackBackground THEN ImagerPixelMap.Clear[pixelMap] ELSE ImagerPixelMap.Fill[pixelMap, [0, 0, sSize, fSize], CARDINAL.LAST];
SetComponent[c, a.first];
Imager.DoSaveAll[c, proc];
IF a.rest = NIL THEN pm ← pixelMap ELSE pm ← ImagerPixelMap.Copy[pixelMap];
IF last = NIL THEN {list ← last ← LIST[pm]}
ELSE {last.rest ← LIST[pm]; last ← last.rest};
ENDLOOP;
RETURN [ImagerOps.PixelArrayFromPixelMaps[list, ImagerTransformation.Invert[viewToPixel]]]
};
SetComponent:
PUBLIC
PROC [context: Context, component:
ATOM] ~ {
WITH context.data
SELECT
FROM
rasterData: ImagerRasterPrivate.Data => {
WITH rasterData.device.data
SELECT
FROM
data: Data => {
data.component ← component;
};
ENDCASE => NULL;
};
ENDCASE => NULL;
};
LikeScreen:
PUBLIC
PROC [sSize:
NAT]
RETURNS [Transformation] ~ {
m: Transformation ~ ImagerTransformation.Translate[[sSize, 0]];
m.ApplyPreRotate[90];
RETURN [m];
};
Create:
PUBLIC
PROC [pixelMap: PixelMap, component:
ATOM, viewToPixel: Transformation ←
NIL, initialScale:
REAL ← 1.0, change:
PROC[changeData:
REF, d: DeviceRectangle, action:
PROC] ←
NIL, changeData:
REF ←
NIL, cacheFonts:
BOOL ←
TRUE]
RETURNS [context: Context] ~ {
device: ImagerDevice.Device ~ DeviceFromPixelMap[pixelMap, component, viewToPixel, change, changeData];
fontCache: ImagerCache.Ref ~ IF cacheFonts THEN ImagerCache.GetNamedCache[atom: fontCacheID, createSize: fontCacheSize] ELSE NIL;
context ← ImagerRaster.Create[device: device, pixelUnits: TRUE, fontCache: fontCache, rastWeight: fontRastWeight];
Imager.ScaleT[context, initialScale];
};
DeviceBoxFromRectangle:
PROC [r: Rectangle]
RETURNS [DeviceBox] ~ {
smin: CARDINAL ← Real.RoundC[r.x];
fmin: CARDINAL ← Real.RoundC[r.y];
smax: CARDINAL ← Real.RoundC[r.x+r.w];
fmax: CARDINAL ← Real.RoundC[r.y+r.h];
IF smin > smax THEN {t: CARDINAL ← smin; smin ← smax; smax ← t};
IF fmin > fmax THEN {t: CARDINAL ← fmin; fmin ← fmax; fmax ← t};
RETURN [[smin: smin, fmin: fmin, smax: smax, fmax: fmax]]
};
DBFromDR:
PROC [r: DeviceRectangle]
RETURNS [DeviceBox] ~ {
RETURN [[smin: r.sMin, fmin: r.fMin, smax: r.sMin+r.sSize, fmax: r.fMin+r.fSize]]
};
DeviceFromPixelMap:
PROC [pixelMap: PixelMap, component:
ATOM, viewToPixel: Transformation, change:
PROC[changeData:
REF, d: DeviceRectangle, action:
PROC], changeData:
REF]
RETURNS [ImagerDevice.Device] ~ {
w: ImagerPixelMap.DeviceRectangle ~ ImagerPixelMap.BoundedWindow[pixelMap];
pm: ImagerPixelMap.PixelMap ~ pixelMap.Clip[w].ShiftMap[-w.sMin, -w.fMin];
maxValue: CARDINAL ~ Basics.BITSHIFT[1, Basics.BITSHIFT[1, pm.refRep.lgBitsPerPixel]]-1;
sampBuffer: SampleBuffer ~ ImagerSample.NewBuffer[1, pm.fSize];
lineBuffer: SampleBuffer ~ ImagerSample.NewBuffer[1, pm.fSize];
sampler: ImagerSample.Sampler ~ NEW[ImagerSample.SamplerRep ← []];
pixelToDevice: Transformation ~ ImagerTransformation.Translate[[w.sMin, w.fMin]];
surfaceToDevice: Transformation ~ viewToPixel.Concat[pixelToDevice];
surfaceRectangle: Rectangle ~ ImagerTransformation.TransformRectangle[pixelToDevice, [pm.sMin, pm.fMin, pm.sSize, pm.fSize]];
surface: DeviceBox ~ DeviceBoxFromRectangle[surfaceRectangle];
data: Data ~
NEW[DataRep ← [
component: component,
pixelMap: pm,
maxValue: maxValue,
sOrigin: w.sMin,
fOrigin: w.fMin,
deviceToPixel: ImagerTransformation.Invert[pixelToDevice],
change: change,
changeData: changeData,
sampBuffer: sampBuffer,
lineBuffer: lineBuffer,
sampler: sampler
]];
RETURN [
NEW[ImagerDevice.DeviceRep ← [class: class,
box: surface,
surfaceToDevice: surfaceToDevice,
surfaceUnitsPerInch: [72, 72],
surfaceUnitsPerPixel: 1,
data: data]]]
};
GraySetPriority:
PROC [device: Device, priorityImportant:
BOOL] ~ {
};
GraySetHalftone:
PROC [device: Device, halftone: ImagerDevice.HalftoneParameters] ~ {
};
PixelFromIntensity:
PROC[i:
REAL, maxValue:
CARDINAL]
RETURNS[
CARDINAL] ~ {
IF i<=0.0 THEN RETURN[0];
IF i>=1.0 THEN RETURN[maxValue];
RETURN[Real.RoundC[i*maxValue]];
};
GraySetColor:
PROC [device: Device, color: Color, viewToDevice: Transformation] ~ {
data: Data ~ NARROW[device.data];
data.case ← nil;
data.sampledColor ← NIL;
data.sampledColorData ← NIL;
IF data.component = $Alpha
THEN {
data.case ← constant;
data.constant ← data.maxValue;
RETURN;
};
WITH color
SELECT
FROM
color: ConstantColor => {
MakeSampleFromColor:
PROC [c:
REAL]
RETURNS [Sample] ~ {
RETURN [
SELECT data.maxValue
FROM
1 => PixelFromIntensity[c, 1] * 0FFFFH,
3 => PixelFromIntensity[c, 3] * 05555H,
15 => PixelFromIntensity[c, 15] * 01111H,
255 => PixelFromIntensity[c, 255] * 0101H,
ENDCASE => ERROR
];
};
impl: ConstantColorImpl ~ color.impl;
c: REAL;
data.case ← constant;
data.flags ← [disjoint: TRUE, gray: TRUE, srcFunc: null, dstFunc: null];
WITH impl: impl
SELECT
FROM
stipple => {
word: WORD ~ impl.word;
SELECT impl.function
FROM
replace => { data.flags.srcFunc ← complement };
paint => { data.flags.srcFunc ← complement; data.flags.dstFunc ← and };
invert => { data.flags.dstFunc ← xor };
erase => { data.flags.dstFunc ← or };
ENDCASE => ERROR;
IF word=WORD.LAST THEN data.constant ← word
ELSE { data.stipple ← StippleArrayFromWord[word]; data.case ← stipple };
};
rgb => {
SELECT data.component
FROM
$Intensity => data.constant ← MakeSampleFromColor[impl.Y];
$Red => data.constant ← MakeSampleFromColor[impl.val.R];
$Green => data.constant ← MakeSampleFromColor[impl.val.G];
$Blue => data.constant ← MakeSampleFromColor[impl.val.B];
ENDCASE => ERROR Imager.Error[[$unimplemented, "Unknown component name"]];
};
gray => data.constant ← MakeSampleFromColor[impl.Y]
ENDCASE => ERROR;
};
color: SampledColor => {
pa: PixelArray ~ color.pa;
um: Transformation ~ color.um;
colorOperator: ColorOperator ~ color.colorOperator;
data.sampledColor ← color;
data.case ← sampled;
data.zerosAreClear ← ImagerColorOperator.GetColorOperatorClass[colorOperator] = $SampledBlackClear;
data.paToPixel ← ImagerTransformation.Cat[pa.m, color.um, viewToDevice, data.deviceToPixel];
SetUpSampledColorData[data];
};
ENDCASE => ERROR; -- unknown color variant
};
StippleArrayFromWord:
PROC [t:
WORD]
RETURNS[array: StippleArray ←
ALL[0]] ~ {
bits: PACKED ARRAY [0..16) OF BOOL ~ LOOPHOLE[t];
FOR i: [0..16) IN [0..16) DO IF bits[i] THEN array[i] ← WORD.LAST ENDLOOP;
};
me:
REF
TEXT ~ "Gray";
-- a globally unique REF for use as a clientID in the global cache.
SampledColorKey:
TYPE ~
RECORD [pa: PixelArray, component:
ATOM];
SetUpSampledColorData:
PROC [data: Data] ~ {
cache: FunctionCache.Cache ← FunctionCache.GlobalCache[];
color: SampledColor ~ data.sampledColor;
pa: PixelArray ~ color.pa;
component: ATOM ~ data.component;
key: SampledColorKey ~ [data.sampledColor.pa, data.component];
compare: FunctionCache.CompareProc ~ {
RETURN [
WITH argument
SELECT
FROM
p: REF SampledColorKey => (p^=key),
ENDCASE => FALSE
]};
scd: SampledColorData ← NARROW[FunctionCache.Lookup[cache, compare, me].value];
IF color = NIL THEN ERROR;
IF scd =
NIL
THEN
TRUSTED {
colorOperator: ColorOperator ~ color.colorOperator;
samplesPerPixel: NAT ~ pa.samplesPerPixel;
sSize: NAT ~ pa.sSize;
fSize: NAT ~ pa.fSize;
maxIn: Sample ~ ImagerPixelArray.MaxSampleValue[pa, 0];
pixels: SampleBuffer ~ ImagerSample.NewBuffer[samplesPerPixel, fSize];
buffer: SampleBuffer ~ ImagerSample.NewBuffer[1, fSize];
bufferPointer: UnsafeSamples ~ buffer.GetPointer[0, 0, fSize];
mapper: ImagerColorOperator.Mapper ~ ImagerColorOperator.NewMapper[op: colorOperator, component: data.component, maxIn: maxIn, maxOut: data.maxValue];
t: ImagerPixelMap.PixelMap ~ ImagerPixelMap.Create[data.pixelMap.refRep.lgBitsPerPixel, [0, 0, sSize, fSize]];
line: LONG POINTER TO Basics.RawWords ← t.refRep.pointer;
rast: NAT ~ t.refRep.rast;
bps: NAT ~ Basics.BITSHIFT[1, t.refRep.lgBitsPerPixel];
sampledColorDataSize: INT ← t.refRep.words+SIZE[ImagerPixelMap.PixelMap]+SIZE[ImagerPixelMap.PixelMapRep];
scd ← NEW[SampledColorDataRep ← [t, key]];
FOR s:
NAT
IN[0..sSize)
DO
ImagerPixelArray.GetPixels[pa: pa, s: s, f: 0, buffer: pixels, count: fSize];
ImagerColorOperator.MapPixels[mapper: mapper, pixels: pixels, buffer: buffer, bi: 0, count: fSize];
ImagerSample.UnsafePutF[samples: bufferPointer, count: fSize, s: s, f: 0, base: t.refRep.pointer, wordsPerLine: rast, bitsPerSample: bps];
ENDLOOP;
FunctionCache.Insert[cache, NEW[SampledColorKey ← key], scd, sampledColorDataSize, me];
};
data.sampledColorData ← scd;
};
Mod:
PROC [n:
INTEGER, d:
NAT]
RETURNS [
NAT] ~ {
nn: Basics.LongNumber ← [li[n]];
IF nn.li < 0 THEN nn.highbits ← nn.highbits + d;
RETURN [Basics.LongDivMod[nn.lc, d].remainder];
};
ClearSampleBuffer:
PROC[buffer: SampleBuffer, i, j:
NAT ← 0, count:
NAT] ~
TRUSTED {
pointer: LONG POINTER ~ ImagerSample.GetPointer[buffer, i, j, count];
PrincOpsUtils.LongZero[where: pointer, nwords: count*SIZE[Sample]];
};
nullBitBltTable: PrincOps.BitBltTable ~ [
dst: [word: NIL, bit: 0], dstBpl: 0,
src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: []
];
Check:
PROC[x:
CARDINAL, max:
NAT]
RETURNS[
NAT] ~
TRUSTED MACHINE CODE { PrincOps.zINC; PrincOps.zBNDCK };
IF x IN[0..max] THEN RETURN[x] ELSE ERROR RuntimeError.BoundsFault
GrayMaskRunsInternal:
PROC[data: Data, bounds: DeviceBox, runs:
PROC[RunProc]] ~ {
bitsPerWord: NAT ~ Basics.bitsPerWord;
pixelMap: ImagerPixelMap.PixelMap ~ data.pixelMap;
lgBitsPerPixel: NAT ~ pixelMap.refRep.lgBitsPerPixel;
base: LONG POINTER ~ pixelMap.refRep.pointer;
wordsPerLine: NAT ~ pixelMap.refRep.rast;
bitsPerPixel: NAT ~ Basics.BITSHIFT[1, lgBitsPerPixel];
SELECT data.case
FROM
nil => ERROR; -- color not initialized
constant =>
TRUSTED {
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
grayConstantRun:
PROC[sMin, fMin:
INTEGER, fSize:
NAT] ~
TRUSTED {
f: NAT ~ Check[fMin, pixelMap.fSize];
s: NAT ~ Check[sMin, pixelMap.sSize];
line: LONG POINTER ~ base+Basics.LongMult[s, wordsPerLine];
bit: CARDINAL ~ f*bitsPerPixel;
bb.dst.word ← line+bit/bitsPerWord;
bb.dst.bit ← bit MOD bitsPerWord;
bb.width ← Check[fSize, pixelMap.fSize-f]*bitsPerPixel;
bb.height ← Check[1, pixelMap.sSize-s];
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← wordsPerLine*bitsPerWord;
bb.src.word ← LOOPHOLE[@data.constant];
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0];
bb.flags ← data.flags;
runs[grayConstantRun];
};
stipple =>
TRUSTED {
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
srcBase: LONG POINTER ~ LOOPHOLE[@data.stipple];
srcWordsPerLine: NAT ~ (4*bitsPerPixel)/bitsPerWord;
grayStippleRun:
PROC[sMin, fMin:
INTEGER, fSize:
NAT] ~
TRUSTED {
fmin: NAT ~ Check[fMin, pixelMap.fSize];
fmax: NAT ~ Check[fmin+fSize, pixelMap.fSize];
smin: NAT ~ Check[sMin, pixelMap.sSize];
smax: NAT ~ Check[smin+1, pixelMap.sSize];
dstLine: LONG POINTER ~ base+Basics.LongMult[smin, wordsPerLine];
srcLine: LONG POINTER ~ srcBase+(smin MOD 4)*srcWordsPerLine;
FOR f:
NAT
IN [fmin..
MIN[fmin+4, fmax])
DO
dstBit: NAT ~ f*bitsPerPixel;
srcBit: NAT ~ (f MOD 4)*bitsPerPixel;
bb.dst.word ← dstLine+dstBit/bitsPerWord;
bb.dst.bit ← dstBit MOD bitsPerWord;
bb.src.word ← srcLine+srcBit/bitsPerWord;
bb.src.bit ← srcBit MOD bitsPerWord;
bb.height ← (fmax-f+3)/4;
PrincOpsUtils.BITBLT[bb];
ENDLOOP;
};
bb^ ← nullBitBltTable;
bb.dstBpl ← 4*bitsPerPixel;
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0];
bb.width ← bitsPerPixel;
bb.flags ← data.flags;
runs[grayStippleRun];
};
sampled => {
graySampledRun:
PROC[sMin, fMin:
INTEGER, fSize:
NAT] ~
CHECKED {
s: NAT ~ Check[sMin, pixelMap.sSize];
f: NAT ~ Check[fMin, pixelMap.fSize];
count: NAT ~ Check[fSize, pixelMap.fSize-f];
samples: ImagerSample.UnsafeSamples ~ buffer.GetPointer[0, f, count];
ImagerSample.GetPointSamples[sampler: sampler, s: s, f: f,
buffer: buffer, bi: 0, bj: f, count: count];
TRUSTED { ImagerSample.UnsafePutF[samples: samples, count: count,
base: base, wordsPerLine: wordsPerLine, bitsPerSample: 8, s: s, f: f, dstFunc: null]};
};
t: PixelMap ← data.sampledColorData.source;
buffer: SampleBuffer ~ data.sampBuffer;
sampler: ImagerSample.Sampler ~ data.sampler;
sampler.base ← t.refRep.pointer;
sampler.wordsPerLine ← t.refRep.rast;
sampler.bitsPerSample ← Basics.BITSHIFT[1, t.refRep.lgBitsPerPixel];
sampler.sMin ← t.sMin;
sampler.fMin ← t.fMin;
sampler.sSize ← t.sSize;
sampler.fSize ← t.fSize;
ImagerSample.SetSamplerIncrements[sampler, data.paToPixel];
ImagerSample.SetSamplerPosition[sampler: sampler,
m: data.paToPixel, s: bounds.smin, f: bounds.fmin];
runs[graySampledRun];
};
ENDCASE => ERROR; -- illegal case
};
RectFromDeviceBox:
PROC[data: Data, bounds: DeviceBox]
RETURNS [rect: DeviceRectangle]~ {
bounds are in device coordinates.
rect is in pixel coordinates.
smin: CARDINAL ~ bounds.smin;
smax: CARDINAL ~ bounds.smax;
fmin: CARDINAL ~ bounds.fmin;
fmax: CARDINAL ~ bounds.fmax;
rect.sMin ← data.sOrigin + smin;
rect.fMin ← data.fOrigin + fmin;
rect.sSize ← smax - smin;
rect.fSize ← fmax - fmin;
};
GrayMaskRuns:
PROC[device: Device, bounds: DeviceBox, runs:
PROC[RunProc]] ~ {
data: Data ~ NARROW[device.data];
smoothMaskRunsAction: PROC ~ { GrayMaskRunsInternal[data, bounds, runs] };
IF data.change = NIL THEN GrayMaskRunsInternal[data, bounds, runs]
ELSE data.change[data.changeData, RectFromDeviceBox[data, bounds], smoothMaskRunsAction];
};
GrayMoveBoxes:
PROC [device: Device, ts, tf:
INTEGER, boxes:
PROC[BoxProc]] ~
TRUSTED {
data: Data ~ NARROW[device.data];
bitsPerWord: NAT ~ Basics.bitsPerWord;
pixelMap: ImagerPixelMap.PixelMap ~ data.pixelMap;
lgBitsPerPixel: NAT ~ pixelMap.refRep.lgBitsPerPixel;
base: LONG POINTER ~ pixelMap.refRep.pointer;
wordsPerLine: NAT ~ pixelMap.refRep.rast;
bitsPerPixel: NAT ~ Basics.BITSHIFT[1, lgBitsPerPixel];
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
moveBox:
PROC[box: DeviceBox] ~
TRUSTED {
dfmin: NAT ~ Check[box.fmin, pixelMap.fSize];
dsmin: NAT ~ Check[box.smin, pixelMap.sSize];
dfmax: NAT ~ Check[box.fmax, pixelMap.fSize];
dsmax: NAT ~ Check[box.smax, pixelMap.sSize];
sfmin: NAT ~ dfmin-tf;
ssmin: NAT ~ dsmin-ts;
sfmax: NAT ~ dfmax-tf;
ssmax: NAT ~ dsmax-ts;
dstBit: CARDINAL ~ dfmin*bitsPerPixel;
srcBit: CARDINAL ~ sfmin*bitsPerPixel;
bpl: INTEGER ← wordsPerLine*bitsPerWord;
ss: NAT ← ssmin;
ds: NAT ← dsmin;
bb.flags ← [disjoint: TRUE, disjointItems: TRUE, direction: forward, gray: FALSE];
IF dsmin<ssmax
AND dsmax>ssmin
THEN {
bb.flags.disjoint ← FALSE;
IF dsmin=ssmin AND dfmin<sfmax AND dfmax>sfmin THEN bb.flags.disjointItems ← FALSE;
IF dsmin>ssmin
OR (dsmin=ssmin
AND dfmin>sfmin)
THEN {
bb.flags.direction ← backward; bpl ← -bpl; ss ← ssmax-1; ds ← dsmax-1;
};
};
bb.dst.word ← base+Basics.LongMult[ds, wordsPerLine]+dstBit/bitsPerWord;
bb.dst.bit ← dstBit MOD bitsPerWord;
bb.dstBpl ← bpl;
bb.src.word ← base+Basics.LongMult[ss, wordsPerLine]+srcBit/bitsPerWord;
bb.src.bit ← srcBit MOD bitsPerWord;
bb.srcDesc.srcBpl ← bpl;
bb.width ← (dfmax-dfmin)*bitsPerPixel;
bb.height ← dsmax-dsmin;
PrincOpsUtils.BITBLT[bb]
};
bb^ ← nullBitBltTable;
boxes[moveBox];
};