ImagerGrayDeviceImpl.mesa
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Michael Plass, June 12, 1985 11:53:55 am PDT
Doug Wyatt, May 30, 1985 11:24:15 pm PDT
DIRECTORY
Basics USING [BITSHIFT, bitsPerWord, BYTE, LongMult],
ImagerColorDefs USING [Color, ColorOperator, ConstantColor, ConstantColorImplRep, SampledColor],
ImagerColorOperator USING [GetColorOperatorClass, Mapper, MapPixels, NewMapper],
ImagerColorPrivate USING [ConstantColorImpl, ConstantColorImplRep],
ImagerDevice USING [BoxProc, Class, ClassRep, Device, DeviceBox, DeviceRep, HalftoneParameters, RunProc],
ImagerMask USING [RunsFromBits, RunsFromBox],
ImagerPixelArray USING [GetPixels, MaxSampleValue],
ImagerPixelArrayDefs USING [PixelArray],
ImagerPixelMap USING [PixelMap, Reshape],
ImagerRaster USING [],
ImagerSample USING [BitsPerSample, GetPointer, GetPointSamples, NewBuffer, Sample, SampleBuffer, Sampler, SamplerRep, SetSamplerIncrements, SetSamplerPosition, UnsafePutF, UnsafeSamples],
ImagerTransformation USING [ApplyPreRotate, Cat, Transformation, Translate],
PrincOps USING [BBTableSpace, BitAddress, BitBltFlags, BitBltTable, BitBltTablePtr, GrayParm, op, zBNDCK, zINC],
PrincOpsUtils USING [AlignedBBTable, BITBLT],
Real USING [RoundC],
Terminal USING [FrameBuffer, GetColorFrameBufferA, ModifyColorFrame, Virtual],
Vector2 USING [VEC];
ImagerGrayDeviceImpl: CEDAR PROGRAM
IMPORTS Basics, ImagerColorOperator, ImagerMask, ImagerPixelArray, ImagerPixelMap, ImagerSample, ImagerTransformation, PrincOpsUtils, Real, Terminal
EXPORTS ImagerColorDefs, ImagerRaster
~ BEGIN OPEN ImagerDevice;
BYTE: TYPE ~ Basics.BYTE;
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;
Sample: TYPE ~ ImagerSample.Sample;
SampleBuffer: TYPE ~ ImagerSample.SampleBuffer;
UnsafeSamples: TYPE ~ ImagerSample.UnsafeSamples;
ConstantColorImpl: TYPE ~ ImagerColorPrivate.ConstantColorImpl;
ConstantColorImplRep: PUBLIC TYPE ~ ImagerColorPrivate.ConstantColorImplRep;
Case: TYPE ~ {nil, constant, stipple, sampled};
StippleArray: TYPE ~ PACKED ARRAY [0..16) OF BYTE;
Data: TYPE ~ REF DataRep;
DataRep: TYPE ~ RECORD[
terminal: Terminal.Virtual,
frame: Terminal.FrameBuffer, -- the frame buffer
case: Case ← nil, -- what type of color
sampledBlack: BOOLFALSE,
sampledBlackClear: BOOLFALSE,
bitsPerPixel: ImagerSample.BitsPerSample ← 0,
flags: PrincOps.BitBltFlags ← [], -- bitblt flags
grayWord: WORD ← 0, -- constant gray word (two pixels)
stipple: StippleArray ← ALL[0], -- stipple pattern
sampledColor: SampledColor ← NIL, -- sampled color
paToDevice: Transformation ← NIL, -- transformation from pa coords to display
source: ImagerPixelMap.PixelMap ← [0, 0, 0, 0, 0, 0, NIL], -- source values from pixel array
sampler: ImagerSample.Sampler ← NIL, -- sampler information
buffer: ImagerSample.SampleBuffer ← NIL -- scan line buffer for samples
];
class: ImagerDevice.Class ~ NEW[ImagerDevice.ClassRep ← [
type: $GrayDisplay,
SetColor: GraySetColor,
SetPriority: GraySetPriority,
SetHalftone: GraySetHalftone,
MaskRuns: GrayMaskRuns,
MaskBoxes: GrayMaskBoxes,
MaskBits: GrayMaskBits,
MoveBoxes: GrayMoveBoxes
]];
defaultDot: ImagerPixelMap.PixelMap ~ ImagerSampler.DotScreen[
r: 0.5, sSize: 16, fSize: 16, maxPixelValue: 255];
NewGrayDevice: PUBLIC PROC[terminal: Terminal.Virtual] RETURNS[Device] ~ {
frame: Terminal.FrameBuffer ~ Terminal.GetColorFrameBufferA[terminal];
IF frame=NIL OR frame.bitsPerPixel#8 THEN RETURN[NIL]
ELSE {
data: Data ~ NEW[DataRep ← [terminal: terminal, frame: frame]];
pixelsPerInch: REAL ~ terminal.colorPixelsPerInch;
surfaceToDevice: Transformation ~ ImagerTransformation.Translate[[frame.height, 0]];
surfaceToDevice.ApplyPreRotate[90];
RETURN[NEW[ImagerDevice.DeviceRep ← [class: class,
box: [smin: 0, fmin: 0, smax: frame.height, fmax: frame.width],
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: []
];
bitsPerPixel: NAT ~ 8;
bitsPerWord: NAT ~ Basics.bitsPerWord;
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] ← BYTE.LAST ENDLOOP;
};
PixelFromIntensity: PROC[Y: REAL] RETURNS[BYTE] ~ {
IF Y<=0 THEN RETURN[0]; -- black
IF Y>=1 THEN RETURN[BYTE.LAST]; -- white
RETURN[Real.RoundC[Y*BYTE.LAST]]; -- gray
};
sourceLgBitsPerSample: NAT ~ 3; -- for array of samples from sampled color
sourceBitsPerSample: NAT ~ Basics.BITSHIFT[1, sourceLgBitsPerSample];
maxSourceSample: Sample ~ Basics.BITSHIFT[1, sourceBitsPerSample]-1;
GraySetColor: PROC[device: Device, color: Color, viewToDevice: Transformation] ~ {
data: Data ~ NARROW[device.data];
WITH color SELECT FROM
color: ConstantColor => {
impl: ConstantColorImpl ~ color.impl;
data.case ← constant;
data.source.refRep ← NIL;
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.grayWord ← word
ELSE { data.stipple ← StippleArrayFromWord[word]; data.case ← stipple };
};
ENDCASE => {
pixel: BYTE ~ PixelFromIntensity[impl.Y];
data.grayWord ← pixel*400B+pixel;
};
};
color: SampledColor => {
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];
source: ImagerPixelMap.PixelMap ~ data.source.refRep.Reshape[
lgBitsPerPixel: sourceLgBitsPerSample,
bounds: [sMin: 0, fMin: 0, sSize: sSize, fSize: fSize]];
sourceBase: LONG POINTER ~ source.refRep.pointer;
sourceWordsPerLine: NAT ~ source.refRep.rast;
pixels: SampleBuffer ~ ImagerSample.NewBuffer[samplesPerPixel, fSize];
buffer: SampleBuffer ~ ImagerSample.NewBuffer[1, fSize];
mapper: ImagerColorOperator.Mapper ~ ImagerColorOperator.NewMapper[
op: colorOperator, component: $Intensity, maxIn: maxIn, maxOut: maxSourceSample];
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: sourceBase, wordsPerLine: sourceWordsPerLine,
bitsPerSample: sourceBitsPerSample, s: s, f: 0] };
ENDLOOP;
data.sampledColor ← color;
data.paToDevice ← ImagerTransformation.Cat[pa.m, color.um, viewToDevice];
data.source ← source;
IF data.sampler=NIL THEN data.sampler ← NEW[ImagerSample.SamplerRep ← []];
data.sampler.base ← sourceBase;
data.sampler.wordsPerLine ← sourceWordsPerLine;
data.sampler.bitsPerSample ← sourceBitsPerSample;
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];
IF data.buffer=NIL THEN data.buffer ← ImagerSample.NewBuffer[1, data.frame.width];
SELECT ImagerColorOperator.GetColorOperatorClass[colorOperator] FROM
$SampledBlack => {data.sampledBlack ← TRUE; data.sampledBlackClear ← FALSE};
$SampledBlackClear => {data.sampledBlack ← data.sampledBlackClear ← TRUE};
ENDCASE => data.sampledBlack ← data.sampledBlackClear ← FALSE;
data.case ← sampled;
};
ENDCASE => ERROR; -- unknown color variant
};
GraySetPriority: PROC[device: Device, priorityImportant: BOOL] ~ {
};
GraySetHalftone: 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
GrayMaskRunsInternal: PROC[data: Data, bounds: DeviceBox, runs: PROC[RunProc]] ~ {
frame: Terminal.FrameBuffer ~ data.frame;
base: LONG POINTER ~ frame.base;
wordsPerLine: NAT ~ frame.wordsPerLine;
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, frame.width];
s: NAT ~ Check[sMin, frame.height];
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, frame.width-f]*bitsPerPixel;
bb.height ← Check[1, frame.height-s];
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← wordsPerLine*bitsPerWord;
bb.src.word ← LOOPHOLE[@data.grayWord];
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, frame.width];
fmax: NAT ~ Check[fmin+fSize, frame.width];
smin: NAT ~ Check[sMin, frame.height];
smax: NAT ~ Check[smin+1, frame.height];
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 => {
sampler: ImagerSample.Sampler ~ data.sampler;
buffer: SampleBuffer ~ data.buffer;
graySampledRun: PROC[sMin, fMin: INTEGER, fSize: NAT] ~ CHECKED {
s: NAT ~ Check[sMin, frame.height];
f: NAT ~ Check[fMin, frame.width];
count: NAT ~ Check[fSize, frame.width-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: IF data.sampledBlackClear THEN and ELSE null]};
};
ImagerSample.SetSamplerPosition[sampler: sampler,
m: data.paToDevice, s: bounds.smin, f: bounds.fmin];
runs[graySampledRun];
};
ENDCASE => ERROR; -- illegal case
};
GrayMaskBoxesInternal: PROC[data: Data, bounds: DeviceBox, boxes: PROC[BoxProc]] ~ {
IF data.case=constant THEN TRUSTED {
frame: Terminal.FrameBuffer ~ data.frame;
base: LONG POINTER ~ frame.base;
wordsPerLine: NAT ~ frame.wordsPerLine;
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
grayConstantBox: PROC[box: DeviceBox] ~ TRUSTED {
fmin: NAT ~ Check[box.fmin, frame.width];
fmax: NAT ~ Check[box.fmax, frame.width];
smin: NAT ~ Check[box.smin, frame.height];
smax: NAT ~ Check[box.smax, frame.height];
line: LONG POINTER ~ base+Basics.LongMult[smin, wordsPerLine];
bit: NAT ~ fmin*bitsPerPixel;
bb.dst.word ← line+bit/bitsPerWord;
bb.dst.bit ← bit MOD bitsPerWord;
bb.width ← (fmax-fmin)*bitsPerPixel;
bb.height ← smax-smin;
PrincOpsUtils.BITBLT[bb];
};
bb^ ← nullBitBltTable;
bb.dstBpl ← wordsPerLine*bitsPerWord;
bb.src.word ← LOOPHOLE[@data.grayWord];
bb.srcDesc.gray ← [yOffset: 0, widthMinusOne: 0, heightMinusOne: 0];
bb.flags ← data.flags;
boxes[grayConstantBox];
}
ELSE {
grayNonConstantBox: PROC[box: DeviceBox] ~ {
runs: PROC[run: RunProc] ~ { ImagerMask.RunsFromBox[box: box, run: run] };
GrayMaskRunsInternal[data: data, bounds: box, runs: runs];
};
boxes[grayNonConstantBox];
};
};
ModifyColorFrame: PROC [vt: Terminal.Virtual, action: PROC, xmin: NAT, ymin: NAT, xmax: NAT, ymax: NAT] ~ INLINE {
IF vt = NIL THEN action[]
ELSE Terminal.ModifyColorFrame[vt: vt, action: action, xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax];
};
GrayMaskRuns: PROC[device: Device, bounds: DeviceBox, runs: PROC[RunProc]] ~ {
data: Data ~ NARROW[device.data];
grayMaskRunsAction: PROC ~ { GrayMaskRunsInternal[data, bounds, runs] };
ModifyColorFrame[vt: data.terminal, action: grayMaskRunsAction,
xmin: bounds.fmin, ymin: bounds.smin, xmax: bounds.fmax, ymax: bounds.smax];
};
GrayMaskBoxes: PROC[device: Device, bounds: DeviceBox, boxes: PROC[BoxProc]] ~ {
data: Data ~ NARROW[device.data];
grayMaskBoxesAction: PROC ~ { GrayMaskBoxesInternal[data, bounds, boxes] };
ModifyColorFrame[vt: data.terminal, action: grayMaskBoxesAction,
xmin: bounds.fmin, ymin: bounds.smin, xmax: bounds.fmax, ymax: bounds.smax];
};
GrayMaskBits: PROC[device: Device, srcBase: LONG POINTER, srcWordsPerLine: NAT,
ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ {
data: Data ~ NARROW[device.data];
grayMaskBitsBox: PROC[box: DeviceBox] ~ {
grayMaskBitsBoxAction: PROC ~ {
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];
};
GrayMaskRunsInternal[data: data, bounds: box, runs: runs];
};
ModifyColorFrame[vt: data.terminal, action: grayMaskBitsBoxAction,
xmin: box.fmin, ymin: box.smin, xmax: box.fmax, ymax: box.smax];
};
boxes[grayMaskBitsBox];
};
GrayMoveBoxes: PROC [device: Device, ts, tf: INTEGER, boxes: PROC[BoxProc]] ~ TRUSTED {
data: Data ~ NARROW[device.data];
frame: Terminal.FrameBuffer ~ data.frame;
base: LONG POINTER ~ frame.base;
wordsPerLine: NAT ~ frame.wordsPerLine;
bbspace: PrincOps.BBTableSpace;
bb: PrincOps.BitBltTablePtr ~ PrincOpsUtils.AlignedBBTable[@bbspace];
action: SAFE PROC ~ TRUSTED { PrincOpsUtils.BITBLT[bb] };
moveBox: PROC[box: DeviceBox] ~ TRUSTED {
dfmin: NAT ~ Check[box.fmin, frame.width];
dsmin: NAT ~ Check[box.smin, frame.height];
dfmax: NAT ~ Check[box.fmax, frame.width];
dsmax: NAT ~ Check[box.smax, frame.height];
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;
ModifyColorFrame[vt: data.terminal, action: action,
xmin: MIN[dfmin, sfmin], ymin: MIN[dsmin, ssmin],
xmax: MAX[dfmax, sfmax], ymax: MAX[dsmax, ssmax]];
};
bb^ ← nullBitBltTable;
boxes[moveBox];
};
END.