ImagerBitmapDeviceImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Michael Plass, September 16, 1985 3:37:29 pm PDT
Doug Wyatt, June 25, 1985 4:37:42 pm PDT
Tim Diebert: April 14, 1986 10:08:54 am PST
DIRECTORY
Basics USING [BITSHIFT, bitsPerWord, LongMult],
FunctionCache USING [Cache, CompareProc, GlobalCache, Insert, Lookup],
ImagerBitmapDevicePrivate USING [grayHeight, GrayArray, Case, Data, DataRep],
ImagerBrick USING [Brick, BrickRep, ThresholdsFromBrick],
ImagerColorDefs USING [Color, ColorOperator, ConstantColor, ConstantColorImplRep, PixelArray, SampledColor],
ImagerColorOperator USING [GetColorOperatorClass, Mapper, MapPixels, NewMapper],
ImagerColorPrivate USING [ConstantColorImpl, ConstantColorImplRep, StippleFunction],
ImagerDevice USING [BoxProc, Class, ClassRep, Device, DeviceBox, DeviceRep, HalftoneParameters, RunProc],
ImagerMask USING [RunsFromBits, RunsFromBox],
ImagerPixelArray USING [GetPixels, MaxSampleValue, PixelArray, UnsafeGetBits],
ImagerPixelMap,
ImagerRaster USING [],
ImagerSample,
ImagerTransformation USING [ApplyCat, ApplyPreRotate, Scale, Transformation, Translate],
PrincOps USING [BBTableSpace, BitBltFlags, BitBltTable, BitBltTablePtr, GrayParm, op, zBNDCK, zINC],
PrincOpsUtils USING [AlignedBBTable, BITBLT, LongCopy],
Real,
Vector2 USING [VEC];
ImagerBitmapDeviceImpl: CEDAR PROGRAM
IMPORTS Basics, FunctionCache, ImagerBrick, ImagerColorOperator, ImagerMask, ImagerPixelArray, ImagerPixelMap, ImagerSample, ImagerTransformation, PrincOpsUtils, Real
EXPORTS ImagerColorDefs, ImagerRaster, ImagerBitmapDevicePrivate
~ BEGIN OPEN ImagerDevice;
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 ~ ImagerPixelArray.PixelArray;
Sample: TYPE ~ ImagerSample.Sample;
SampleBuffer: TYPE ~ ImagerSample.SampleBuffer;
UnsafeSamples: TYPE ~ ImagerSample.UnsafeSamples;
grayHeight: NAT ~ ImagerBitmapDevicePrivate.grayHeight;
GrayArray: TYPE ~ ImagerBitmapDevicePrivate.GrayArray;
Case: TYPE ~ ImagerBitmapDevicePrivate.Case;
Data: TYPE ~ ImagerBitmapDevicePrivate.Data;
DataRep: TYPE ~ ImagerBitmapDevicePrivate.DataRep;
grayParm: PrincOps.GrayParm ~ [yOffset: 0, widthMinusOne: 0, heightMinusOne: grayHeight-1];
class: ImagerDevice.Class ~ NEW[ImagerDevice.ClassRep ← [
type: $Bitmap,
SetColor: BitmapSetColor,
SetPriority: BitmapSetPriority,
SetHalftone: BitmapSetHalftone,
MaskRuns: BitmapMaskRuns,
MaskBoxes: BitmapMaskBoxes,
MaskBits: BitmapMaskBits,
DrawBits: BitmapDrawBits,
MoveBoxes: BitmapMoveBoxes
]];
NewBitmapDevice: PUBLIC PROC[frame: ImagerPixelMap.PixelMap, pixelsPerInch: REAL]
RETURNS
[Device] ~ {
clipped: ImagerPixelMap.PixelMap ~ frame.Clip[frame.BoundedWindow];
data: Data ~ NEW[DataRep ← [sSizeFrame: clipped.sMin+clipped.sSize, fSizeFrame: clipped.fMin+clipped.fSize, frame: clipped.refRep, pixelsPerInch: pixelsPerInch, paToDevice: ImagerTransformation.Scale[0]]];
surfaceToDevice: Transformation ~ ImagerTransformation.Translate[[clipped.sSize-clipped.sOrigin, -clipped.fOrigin]];
surfaceToDevice.ApplyPreRotate[90];
RETURN[NEW[ImagerDevice.DeviceRep ← [class: class,
box: [smin: clipped.sMin, fmin: clipped.fMin, smax: clipped.sMin+clipped.sSize, fmax: clipped.sMin+clipped.fSize],
surfaceToDevice: surfaceToDevice,
surfaceUnitsPerInch: [pixelsPerInch, pixelsPerInch],
surfaceUnitsPerPixel: 1,
data: data
]]];
};
nullBitBltTable: PrincOps.BitBltTable ~ [
dst: [word: NIL, bit: 0], dstBpl: 0,
src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]],
width: 0, height: 0, flags: []
];
bitsPerWord: NAT ~ Basics.bitsPerWord;
StippleFunction: TYPE ~ ImagerColorPrivate.StippleFunction;
ConstantColorImpl: TYPE ~ ImagerColorPrivate.ConstantColorImpl;
ConstantColorImplRep: PUBLIC TYPE ~ ImagerColorPrivate.ConstantColorImplRep;
desktopStipple: WORD ~ 01144H;
defaultBrick: ImagerBrick.Brick ← ImagerBrick.NewSquareBrick[4, 1, 0, 1, 1];
SetBrick: PUBLIC PROC [brick: ImagerBrick.Brick] ~ {defaultBrick ← brick};
defaultBrick: ImagerBrick.Brick ← InitDefaultBrick[];
InitDefaultBrick: PROC RETURNS [ImagerBrick.Brick] ~ {
brick: ImagerBrick.Brick ~ NEW[ImagerBrick.BrickRep[16] ← [
sSize: 4, fSize: 4, phase: 0, u: 1, v: 1, samples: ]];
Val: PROC[n: [1..16]] RETURNS [REAL] ~ { RETURN[(n-0.5)/16.0] };
brick[00] ← Val[01]; brick[01] ← Val[09]; brick[02] ← Val[03]; brick[03] ← Val[11];
brick[04] ← Val[15]; brick[05] ← Val[05]; brick[06] ← Val[13]; brick[07] ← Val[07];
brick[08] ← Val[04]; brick[09] ← Val[12]; brick[10] ← Val[02]; brick[11] ← Val[10];
brick[12] ← Val[14]; brick[13] ← Val[08]; brick[14] ← Val[16]; brick[15] ← Val[06];
RETURN[brick];
};
TileFromFraction: PROC [f: REAL, scratch: REF ImagerPixelMap.PixelMapRep ← NIL] RETURNS [tile: ImagerPixelMap.Tile] ~ {
sSize: NAT ~ defaultBrick.sSize;
fSize: NAT ~ defaultBrick.fSize;
pm: ImagerPixelMap.PixelMap ← scratch.Reshape[0, [0, 0, sSize, fSize]];
max: CARDINAL ~ 255;
samp: CARDINAL ← Real.Round[(1.0-f)*max];
br: SampleBuffer ~ ImagerBrick.ThresholdsFromBrick[defaultBrick, max];
ImagerPixelMap.Clear[pm];
FOR s: NAT IN [0..sSize) DO
FOR f: NAT IN [0..fSize) DO
br.PutSample[s, f, samp-br.GetSample[s, f]];
ENDLOOP;
ENDLOOP;
FOR s: NAT IN [0..sSize) DO
TRUSTED {
samples: UnsafeSamples ~ br.GetPointer[s, 0, fSize];
ImagerSample.UnsafePutFSign[samples: samples, count: fSize, s: s, f: 0, base: pm.refRep.pointer, wordsPerLine: pm.refRep.rast];
};
ENDLOOP;
tile ← ImagerPixelMap.CreateTile[pm, defaultBrick.phase];
};
stippleTableMax: NAT ~ 16;
stippleTable: ARRAY [0..stippleTableMax] OF WORD ← [0FFFFH,
07FFFH, 07FDFH, 05FDFH, 05F5FH, 05B5FH, 05B5EH, 05A5EH, 05A5AH,
01A5AH, 01A4AH, 00A4AH, 00A0AH, 0080AH, 00802H, 00002H, 00000H
];
StippleFromIntensity: PROC [Y: REAL] RETURNS [WORD] ~ {
IF Y<=0 THEN RETURN[WORD.LAST]; -- black
IF Y>=1 THEN RETURN[0]; -- white
RETURN[stippleTable[Real.RoundC[Y*stippleTableMax]]];
};
grayTable: ARRAY[0..16) OF WORD ← [
00000H, 01111H, 02222H, 03333H, 04444H, 05555H, 06666H, 07777H,
08888H, 09999H, 0AAAAH, 0BBBBH, 0CCCCH, 0DDDDH, 0EEEEH, 0FFFFH
];
GrayArrayFromStipple: PROC [stipple: WORD] RETURNS [GrayArray] ~ {
SELECT stipple FROM
WORD.LAST => RETURN[ALL[WORD.LAST]];
0 => RETURN[ALL[0]];
ENDCASE => {
nibbles: PACKED ARRAY [0..4) OF [0..16) ~ LOOPHOLE[stipple];
grayArray: GrayArray;
FOR i: NAT IN[0..4) DO grayArray[i] ← grayTable[nibbles[i]] ENDLOOP;
RETURN[grayArray];
};
};
sourceLgBitsPerSample: NAT ~ 3; -- for sampled color source
oneFlags: PrincOps.BitBltFlags ~ [srcFunc: null, dstFunc: or];
zeroFlags: PrincOps.BitBltFlags ~ [srcFunc: complement, dstFunc: and];
xorFlags: PrincOps.BitBltFlags ~ [srcFunc: null, dstFunc: xor];
BitmapSetColor: PROC[device: Device, color: Color, viewToDevice: Transformation] ~ {
data: Data ~ NARROW[device.data];
data.source.refRep ← NIL;
WITH color SELECT FROM
color: ConstantColor => {
impl: ConstantColorImpl ~ color.impl;
data.case ← constant;
data.source.refRep ← NIL;
data.flags ← [disjoint: TRUE, gray: TRUE];
data.sampledBlack ← data.sampledBlackClear ← FALSE;
WITH impl: impl SELECT FROM
stipple => {
function: StippleFunction ← replace;
stipple: WORD ~ impl.word;
function ← impl.function;
SELECT function FROM
replace => NULL;
paint => { data.flags.dstFunc ← or };
invert => { data.flags.dstFunc ← xor };
erase => { data.flags.srcFunc ← complement; data.flags.dstFunc ← and };
ENDCASE => ERROR;
IF stipple=WORD.LAST THEN SELECT function FROM
replace, paint => data.maskBitsFlags ← oneFlags;
invert => data.maskBitsFlags ← xorFlags;
erase => data.maskBitsFlags ← zeroFlags;
ENDCASE => ERROR
ELSE IF stipple=0 THEN SELECT function FROM
replace => data.maskBitsFlags ← zeroFlags;
paint, invert, erase => data.case ← noop;
ENDCASE => ERROR
ELSE data.case ← stipple;
data.grayArray ← GrayArrayFromStipple[stipple];
};
ENDCASE => {
SELECT impl.Y FROM
< 0.0001 => {data.grayArray ← ALL[LAST[WORD]]}; -- black --
> 0.9999 => {data.grayArray ← ALL[0]}; -- white --
ENDCASE => {
data.tile ← TileFromFraction[1-impl.Y];
data.case ← tile;
};
};
};
color: SampledColor => {
maxSample: CARDINAL ← SetUpSampledColorData[data, color, viewToDevice];
IF data.sampledBlack AND data.paToDevice.form = 3 AND data.paToDevice.integerTrans THEN {
IF data.source.fSize >= 32 AND data.source.sMin=0 AND data.source.fMin = 0 THEN {
data.tile ← [sOrigin: data.source.sOrigin+data.paToDevice.tx, fOrigin: data.source.fOrigin+data.paToDevice.ty, sSize: data.source.sSize, fSize: data.source.fSize, phase: 0, refRep: data.source.refRep]
}
ELSE {
data.tile ← ImagerPixelMap.CreateTile[pixelMap: ImagerPixelMap.ShiftMap[data.source, data.paToDevice.tx, data.paToDevice.ty], phase: 0, fSizeHint: 32, scratch: data.tile.refRep];
};
data.case ← tile;
};
IF data.buffer=NIL OR data.buffer.jSize < data.fSizeFrame THEN data.buffer ← ImagerSample.NewBuffer[1, data.fSizeFrame];
IF NOT data.sampledBlack THEN {
br: SampleBuffer ~ ImagerBrick.ThresholdsFromBrick[defaultBrick, maxSample];
brick: SampleBuffer ~ ImagerSample.NewBuffer[br.iSize, data.fSizeFrame];
FOR i: NAT IN[0..br.iSize) DO
from: UnsafeSamples ~ br.GetPointer[i, 0, br.jSize];
to: UnsafeSamples ~ brick.GetPointer[i, 0, brick.jSize];
TRUSTED {
PrincOpsUtils.LongCopy[from: from, nwords: br.jSize, to: to];
PrincOpsUtils.LongCopy[from: to, nwords: brick.jSize-br.jSize, to: to+br.jSize];
};
ENDLOOP;
data.brick ← brick;
};
};
ENDCASE => ERROR; -- unknown color variant
};
me: REF TEXT ~ "BitDev"; -- a globally unique REF for use as a clientID in the global cache.
SetUpSampledColorData: PROC [data: Data, color: SampledColor, viewToDevice: Transformation] RETURNS [max: Sample] ~ {
pa: PixelArray ~ color.pa;
um: Transformation ~ color.um;
colorOperator: ColorOperator ~ color.colorOperator;
samplesPerPixel: NAT ~ pa.samplesPerPixel;
sSize: NAT ~ pa.sSize;
fSize: NAT ~ pa.fSize;
maxIn: Sample ~ ImagerPixelArray.MaxSampleValue[pa, 0];
lgBitsPerSample: NAT ~ IF maxIn = 1 AND samplesPerPixel = 1 THEN 0 ELSE sourceLgBitsPerSample;
bitsPerSample: NAT ~ Basics.BITSHIFT[1, lgBitsPerSample];
maxSample: Sample ~ Basics.BITSHIFT[1, bitsPerSample]-1;
cache: FunctionCache.Cache ← FunctionCache.GlobalCache[];
compare: FunctionCache.CompareProc ~ {RETURN [argument=pa]};
source: REF ImagerPixelMap.PixelMap ← NARROW[FunctionCache.Lookup[cache, compare, me].value];
data.sampledColor ← color;
ImagerTransformation.ApplyCat[data.paToDevice, pa.m, um, viewToDevice];
data.case ← sampled;
SELECT ImagerColorOperator.GetColorOperatorClass[colorOperator] FROM
$SampledBlack => {data.sampledBlack ← TRUE; data.sampledBlackClear ← FALSE};
$SampledBlackClear => {data.sampledBlack ← data.sampledBlackClear ← TRUE};
ENDCASE => data.sampledBlack ← data.sampledBlackClear ← FALSE;
IF source = NIL THEN {
source ← NEW[ImagerPixelMap.PixelMap ← ImagerPixelMap.Create[lgBitsPerSample, [sMin: 0, fMin: 0, sSize: sSize, fSize: fSize]]];
IF data.sampledBlack THEN TRUSTED {
ImagerPixelArray.UnsafeGetBits[pa: pa, i: 0, s: 0, f: 0, dst: [word: source.refRep.pointer, bit: 0], dstBpl: source.refRep.rast*bitsPerWord, width: source.fSize, height: source.sSize];
}
ELSE {
pixels: SampleBuffer ~ ImagerSample.NewBuffer[samplesPerPixel, fSize];
buffer: SampleBuffer ~ ImagerSample.NewBuffer[1, fSize];
mapper: ImagerColorOperator.Mapper ~ ImagerColorOperator.NewMapper[
op: colorOperator, component: $Intensity, maxIn: maxIn, maxOut: maxSample];
samples: UnsafeSamples ~ buffer.GetPointer[0, 0, fSize];
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, count: fSize];
TRUSTED { ImagerSample.UnsafePutF[samples: samples, count: fSize,
base: source.refRep.pointer, wordsPerLine: source.refRep.rast,
bitsPerSample: bitsPerSample, s: s, f: 0] };
ENDLOOP;
};
FunctionCache.Insert[cache, pa, source, source.refRep.words, me];
};
data.source ← source^;
IF data.sampler=NIL THEN data.sampler ← NEW[ImagerSample.SamplerRep ← []];
data.sampler.base ← source^.refRep.pointer;
data.sampler.wordsPerLine ← source.refRep.rast;
data.sampler.bitsPerSample ← bitsPerSample;
data.sampler.sMin ← source.sMin;
data.sampler.fMin ← source.fMin;
data.sampler.sSize ← source.sSize;
data.sampler.fSize ← source.fSize;
ImagerSample.SetSamplerIncrements[data.sampler, data.paToDevice];
RETURN [maxSample]
};
BitmapSetPriority: PROC[device: Device, priorityImportant: BOOL] ~ {
};
BitmapSetHalftone: PROC[device: Device, halftone: HalftoneParameters] ~ {
data: Data ~ NARROW[device.data];
data.halftone ← halftone;
};
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
BitmapMaskRunsInternal: PROC[data: Data, bounds: DeviceBox, runs: PROC[RunProc]] ~ {
sSizeFrame: NAT ~ data.sSizeFrame;
fSizeFrame: NAT ~ data.fSizeFrame;
frame: REF ImagerPixelMap.PixelMapRep ~ data.frame;
base: LONG POINTER ~ frame.pointer;
wordsPerLine: NAT ~ frame.rast;
SELECT data.case FROM
nil => ERROR; -- color not initialized
noop => NULL;
constant, stipple => TRUSTED {
grayBase: LONG POINTER ~ LOOPHOLE[@data.grayArray];
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
constantRun: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED {
f: NAT ~ Check[fMin, fSizeFrame];
s: NAT ~ Check[sMin, sSizeFrame];
bb.dst.word ← base+Basics.LongMult[s, wordsPerLine]+f/bitsPerWord;
bb.src.word ← grayBase+(bb.srcDesc.gray.yOffset ← s MOD grayHeight);
bb.dst.bit ← bb.src.bit ← f MOD bitsPerWord;
bb.width ← Check[fSize, fSizeFrame-f];
bb.height ← Check[1, sSizeFrame-s];
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← wordsPerLine*bitsPerWord;
bb.srcDesc.gray ← grayParm;
bb.flags ← data.flags;
runs[constantRun];
};
tile => {
tile: ImagerPixelMap.Tile ~ data.tile;
function: ImagerPixelMap.Function ~ IF data.sampledBlackClear THEN [or, null] ELSE [null, null];
tileRun: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ TRUSTED {
ImagerPixelMap.TransferTile[
[sOrigin: 0, fOrigin: 0, sMin: sMin, fMin: fMin, sSize: 1, fSize: fSize, refRep: frame],
tile,
function
];
};
runs[tileRun];
};
sampled => {
sampler: ImagerSample.Sampler ~ data.sampler;
buffer: SampleBuffer ~ data.buffer;
brick: SampleBuffer ~ data.brick;
bitmapSampledRun: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ CHECKED {
s: NAT ~ Check[sMin, sSizeFrame];
f: NAT ~ Check[fMin, fSizeFrame];
count: NAT ~ Check[fSize, fSizeFrame-f];
ImagerSample.GetPointSamples[sampler: sampler, s: s, f: f,
buffer: buffer, bi: 0, bj: f, count: count];
IF data.sampledBlack THEN TRUSTED {
ImagerSample.UnsafePutF[samples: buffer.GetPointer[0, f, count], count: count,
s: s, f: f, base: base, wordsPerLine: wordsPerLine, bitsPerSample: 1, srcFunc: null, dstFunc: IF data.sampledBlackClear THEN or ELSE null];
}
ELSE {
ImagerSample.SubSamples[samples: brick, si: s MOD brick.iSize, sj: f,
buffer: buffer, bi: 0, bj: f, count: count];
TRUSTED {
samples: UnsafeSamples ~ buffer.GetPointer[0, f, count];
ImagerSample.UnsafePutFSign[samples: samples, count: count,
s: s, f: f, base: base, wordsPerLine: wordsPerLine];
};
};
};
ImagerSample.SetSamplerPosition[sampler: sampler,
m: data.paToDevice, s: bounds.smin, f: bounds.fmin];
runs[bitmapSampledRun];
};
ENDCASE => ERROR; -- illegal case
};
BitmapMaskRuns: PROC[device: Device, bounds: DeviceBox, runs: PROC[RunProc]] ~ {
data: Data ~ NARROW[device.data];
BitmapMaskRunsInternal[data, bounds, runs];
};
BitmapMaskBoxes: PROC[device: Device, bounds: DeviceBox, boxes: PROC[BoxProc]] ~ {
data: Data ~ NARROW[device.data];
sSizeFrame: NAT ~ data.sSizeFrame;
fSizeFrame: NAT ~ data.fSizeFrame;
frame: REF ImagerPixelMap.PixelMapRep ~ data.frame;
SELECT data.case FROM
constant, stipple => TRUSTED {
base: LONG POINTER ~ frame.pointer;
wordsPerLine: NAT ~ frame.rast;
grayBase: LONG POINTER ~ LOOPHOLE[@data.grayArray];
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
bitmapConstantBox: SAFE PROC[box: DeviceBox] ~ TRUSTED {
f: NAT ~ Check[box.fmin, fSizeFrame];
s: NAT ~ Check[box.smin, sSizeFrame];
bb.dst.word ← base+Basics.LongMult[s, wordsPerLine]+f/bitsPerWord;
bb.src.word ← grayBase+(bb.srcDesc.gray.yOffset ← s MOD grayHeight);
bb.dst.bit ← bb.src.bit ← f MOD bitsPerWord;
bb.width ← Check[box.fmax, fSizeFrame]-f;
bb.height ← Check[box.smax, sSizeFrame]-s;
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← wordsPerLine*bitsPerWord;
bb.srcDesc.gray ← grayParm;
bb.flags ← data.flags;
boxes[bitmapConstantBox];
};
tile => {
tile: ImagerPixelMap.Tile ~ data.tile;
function: ImagerPixelMap.Function ~ IF data.sampledBlackClear THEN [or, null] ELSE [null, null];
tileBox: PROC[box: DeviceBox] ~ TRUSTED {
ImagerPixelMap.TransferTile[
dest: [
sOrigin: 0, fOrigin: 0,
sMin: box.smin, fMin: box.fmin,
sSize: box.smax-box.smin, fSize: box.fmax-box.fmin,
refRep: frame
],
tile: tile,
function: function
];
};
boxes[tileBox];
};
ENDCASE => {
bitmapNonConstantBox: PROC[box: DeviceBox] ~ {
runs: PROC[run: RunProc] ~ { ImagerMask.RunsFromBox[box: box, run: run] };
BitmapMaskRunsInternal[data: data, bounds: box, runs: runs];
};
boxes[bitmapNonConstantBox];
};
};
BitmapMaskBits: PROC [device: Device, srcBase: LONG POINTER, srcWordsPerLine: NAT,
ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ {
data: Data ~ NARROW[device.data];
IF data.case=constant THEN TRUSTED {
sSizeFrame: NAT ~ data.sSizeFrame;
fSizeFrame: NAT ~ data.fSizeFrame;
frame: REF ImagerPixelMap.PixelMapRep ~ data.frame;
dstBase: LONG POINTER ~ frame.pointer;
dstWordsPerLine: NAT ~ frame.rast;
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
fastBox: PROC[box: DeviceBox] ~ TRUSTED {
df: NAT ~ Check[box.fmin, fSizeFrame];
ds: NAT ~ Check[box.smin, sSizeFrame];
sf: NAT ~ df-tf;
ss: NAT ~ ds-ts;
bb.dst.word ← dstBase+Basics.LongMult[ds, dstWordsPerLine]+df/bitsPerWord;
bb.dst.bit ← df MOD bitsPerWord;
bb.src.word ← srcBase+Basics.LongMult[ss, srcWordsPerLine]+sf/bitsPerWord;
bb.src.bit ← sf MOD bitsPerWord;
bb.width ← Check[box.fmax, fSizeFrame]-df;
bb.height ← Check[box.smax, sSizeFrame]-ds;
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← dstWordsPerLine*bitsPerWord;
bb.srcDesc.srcBpl ← srcWordsPerLine*bitsPerWord;
bb.flags ← data.maskBitsFlags;
bb.flags.gray ← FALSE; bb.flags.disjoint ← TRUE;
boxes[fastBox];
}
ELSE {
bitmapMaskBitsBox: PROC[box: DeviceBox] ~ {
runs: PROC[run: RunProc] ~ { ImagerMask.RunsFromBits[
base: srcBase, wordsPerLine: srcWordsPerLine,
sBits: box.smin-ts, fBits: box.fmin-tf, sRuns: box.smin, fRuns: box.fmin,
sSize: box.smax-box.smin, fSize: box.fmax-box.fmin, run: run];
};
BitmapMaskRunsInternal[data: data, bounds: box, runs: runs];
};
boxes[bitmapMaskBitsBox];
};
};
BitmapDrawBits: PROC [device: Device, srcBase: LONG POINTER, srcWordsPerLine: NAT,
ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ TRUSTED {
data: Data ~ NARROW[device.data];
sSizeFrame: NAT ~ data.sSizeFrame;
fSizeFrame: NAT ~ data.fSizeFrame;
frame: REF ImagerPixelMap.PixelMapRep ~ data.frame;
dstBase: LONG POINTER ~ frame.pointer;
dstWordsPerLine: NAT ~ frame.rast;
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
fastBox: PROC[box: DeviceBox] ~ TRUSTED {
df: NAT ~ Check[box.fmin, fSizeFrame];
ds: NAT ~ Check[box.smin, sSizeFrame];
sf: NAT ~ df-tf;
ss: NAT ~ ds-ts;
bb.dst.word ← dstBase+Basics.LongMult[ds, dstWordsPerLine]+df/bitsPerWord;
bb.dst.bit ← df MOD bitsPerWord;
bb.src.word ← srcBase+Basics.LongMult[ss, srcWordsPerLine]+sf/bitsPerWord;
bb.src.bit ← sf MOD bitsPerWord;
bb.width ← Check[box.fmax, fSizeFrame]-df;
bb.height ← Check[box.smax, sSizeFrame]-ds;
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← dstWordsPerLine*bitsPerWord;
bb.srcDesc.srcBpl ← srcWordsPerLine*bitsPerWord;
bb.flags ← [direction: forward, disjoint: TRUE, disjointItems: FALSE, gray: FALSE, srcFunc: null, dstFunc: null];
boxes[fastBox];
};
BitmapMoveBoxes: PROC [device: Device, ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ TRUSTED {
data: Data ~ NARROW[device.data];
sSizeFrame: NAT ~ data.sSizeFrame;
fSizeFrame: NAT ~ data.fSizeFrame;
frame: REF ImagerPixelMap.PixelMapRep ~ data.frame;
base: LONG POINTER ~ frame.pointer;
wordsPerLine: NAT ~ frame.rast;
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
moveBox: PROC[box: DeviceBox] ~ TRUSTED {
dfmin: NAT ~ Check[box.fmin, fSizeFrame];
dsmin: NAT ~ Check[box.smin, sSizeFrame];
dfmax: NAT ~ Check[box.fmax, fSizeFrame];
dsmax: NAT ~ Check[box.smax, sSizeFrame];
sfmin: NAT ~ dfmin-tf;
ssmin: NAT ~ dsmin-ts;
sfmax: NAT ~ dfmax-tf;
ssmax: NAT ~ dsmax-ts;
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]+dfmin/bitsPerWord;
bb.dst.bit ← dfmin MOD bitsPerWord;
bb.dstBpl ← bpl;
bb.src.word ← base+Basics.LongMult[ss, wordsPerLine]+sfmin/bitsPerWord;
bb.src.bit ← sfmin MOD bitsPerWord;
bb.srcDesc.srcBpl ← bpl;
bb.width ← dfmax-dfmin;
bb.height ← dsmax-dsmin;
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
boxes[moveBox];
};
END.