PDFileWriterImpl:
CEDAR
PROGRAM
IMPORTS FileIO, IO
EXPORTS PDFileWriter
= BEGIN
bytesPerWord: CARDINAL = Environment.bytesPerWord;
bitsPerWord: CARDINAL = Environment.bitsPerWord;
ROPE: TYPE = Rope.ROPE;
LoadReference: TYPE = LONG CARDINAL;
DeliverRunGroupProc: TYPE = PDFileWriter.DeliverRunGroupProc;
CaptureRunProc: TYPE = PDFileWriter.CaptureRunProc;
DeliverSampleArrayProc: TYPE = PDFileWriter.DeliverSampleArrayProc;
CaptureScanLineProc: TYPE = PDFileWriter.CaptureScanLineProc;
TFlag: TYPE = PDFileWriter.TFlag;
Toner: TYPE = PDFileFormat.Toner;
maxLoadSize: CARDINAL = 16000;
LoadRec: TYPE = ARRAY [0..maxLoadSize) OF WORD;
Bands: TYPE = REF BandsRec;
BandsRec:
TYPE =
RECORD [
bands: SEQUENCE maxBands: NAT OF Band
];
Band:
TYPE =
RECORD [
colorId: INT,
bandBuffers: BandBuffer
];
bandBufferSize: NAT = 1000;
BandBuffer: TYPE = REF BandBufferRec;
BandBufferRec:
TYPE =
RECORD [
link: BandBuffer,
length: NAT ← 0,
word: ARRAY [0..bandBufferSize) OF WORD
];
ColorDescriptor:
TYPE =
MACHINE
DEPENDENT
RECORD [
colorId: INT ← 0, -- bumped whenever the color changes.
length: CARDINAL ← 1,
command: PDFileFormat.Command.control ← [control[setColorInk]],
setColorTile: PDFileFormat.SetColorTile
];
PDState: PUBLIC TYPE = REF PDStateRec;
PDStateRec:
PUBLIC
TYPE =
RECORD [
fileName: ROPE,
herald: PDFileFormat.Herald,
colorDescriptor: ARRAY Toner OF ColorDescriptor,
stream: IO.STREAM,
firstToner: Toner,
lastToner: Toner,
bands: ARRAY Toner OF Bands,
selectedBands: Bands ← NIL,
selectedBandNum: NAT ← 0,
sMinPage: CARDINAL,
sMaxPage: CARDINAL,
fMinPage: CARDINAL,
fMaxPage: CARDINAL,
currentLoadLocation: LONG CARDINAL ← 0,
loadWrittenLength: LONG CARDINAL ← 0,
load: REF LoadRec ← NIL,
leftOverMode: BOOLEAN,
priorityImportant: BOOLEAN
];
Create:
PUBLIC
PROC [fileName:
ROPE, deviceCode: PDFileFormat.DeviceCode, sResolution, fResolution, imageSSize, imageFSize:
CARDINAL, nColors:
NAT ← 1, bandSSize:
CARDINAL ← 16, copies:
CARDINAL ← 1, leftOverMode:
BOOLEAN ←
TRUE, priorityImportant:
BOOLEAN ←
TRUE]
RETURNS [pdState: PDState] = {
nBands: NAT;
pdState ← NEW [PDStateRec];
pdState.fileName ← fileName;
pdState.herald.deviceCode ← deviceCode;
pdState.herald.sResolution ← sResolution;
pdState.herald.fResolution ← fResolution;
pdState.herald.imageSSize ← pdState.sMinPage ← imageSSize;
pdState.herald.imageFSize ← pdState.fMinPage ← imageFSize;
pdState.herald.bandSSize ← bandSSize;
pdState.herald.maxLoadWord ← 0;
pdState.herald.copies ← copies;
pdState.leftOverMode ← leftOverMode;
pdState.priorityImportant ← priorityImportant;
pdState.sMaxPage ← pdState.fMaxPage ← 0;
pdState.firstToner ←
SELECT nColors
FROM
1, 4 => black,
3 => cyan,
ENDCASE => ERROR;
pdState.lastToner ←
SELECT nColors
FROM
1 => black,
3, 4 => yellow,
ENDCASE => ERROR;
nBands ← (pdState.herald.imageSSize+pdState.herald.bandSSize-1)/pdState.herald.bandSSize;
FOR t: Toner
IN [pdState.firstToner..pdState.lastToner]
DO
pdState.bands[t] ← NEW [BandsRec[nBands]];
ENDLOOP;
pdState.stream ← FileIO.Open[fileName, overwrite];
WriteHerald[pdState];
We will come back and overwrite this when the file is closed.
};
SetColorInk:
PUBLIC
PROC [pdState: PDState, toner: Toner] = {
pdState.colorDescriptor[toner].colorId ← pdState.colorDescriptor[toner].colorId + 1;
pdState.colorDescriptor[toner].length ← SIZE[PDFileFormat.Command];
pdState.colorDescriptor[toner].command ← [control[setColorInk]];
};
SetColorClear:
PUBLIC
PROC [pdState: PDState, toner: Toner] = {
pdState.colorDescriptor[toner].colorId ← pdState.colorDescriptor[toner].colorId + 1;
pdState.colorDescriptor[toner].length ← SIZE[PDFileFormat.Command];
pdState.colorDescriptor[toner].command ← [control[setColorClear]];
};
SetColorTile:
PUBLIC
PROC [pdState: PDState, toner: Toner, tileRef: LoadReference, tFlag: TFlag] =
TRUSTED {
colorId: INT ← pdState.colorDescriptor[toner].colorId + 1;
tBit: [0..1] = IF tFlag = opaque THEN PDFileFormat.opaqueFlag ELSE PDFileFormat.transparentFlag;
pdState.colorDescriptor[toner] ← [
colorId: colorId,
length: SIZE[PDFileFormat.Command] + SIZE[PDFileFormat.SetColorTile],
command: [control[setColorTile, tBit]],
setColorTile: [addr: tileRef]
];
};
DoForEachToner:
PUBLIC
PROC [pdState: PDState, proc:
PROC[Toner]] = {
FOR toner: Toner
IN [pdState.firstToner..pdState.lastToner]
DO
proc[toner];
ENDLOOP;
};
GetBounds:
PUBLIC
PROC [pdState: PDState]
RETURNS [sMax, fMax:
CARDINAL] = {
sMax ← pdState.herald.imageSSize;
fMax ← pdState.herald.imageFSize;
};
MaskRectangle:
PUBLIC
PROC [pdState: PDState, sMin, fMin:
CARDINAL, sSize, fSize:
CARDINAL] =
TRUSTED {
sEnd: CARDINAL ← IF pdState.leftOverMode THEN sMin+1 ELSE sMin + sSize;
bandSSize: CARDINAL ← pdState.herald.bandSSize;
command: PDFileFormat.Command ← [imaging[maskRectangle, 0]];
maskArgs: PDFileFormat.MaskRectangle ← [sMin:sMin, sSize:sSize, fMin:fMin, fSize:fSize];
ExtendBB[pdState, sMin, fMin];
ExtendBB[pdState, sMin + sSize, fMin + fSize];
FOR toner: Toner
IN [pdState.firstToner..pdState.lastToner]
DO
nextBandStart: CARDINAL ← sMin + (bandSSize - (sMin MOD bandSSize));
SelectBand[pdState, sMin, toner];
EnterBandData[pdState, @command, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @maskArgs, SIZE[PDFileFormat.MaskRectangle]];
FOR s:
CARDINAL ← nextBandStart, s + bandSSize
WHILE s<sEnd
DO
SelectBand[pdState, s, toner];
EnterBandData[pdState, @command, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @maskArgs, SIZE[PDFileFormat.MaskRectangle]];
ENDLOOP;
ENDLOOP;
};
MaskTrapezoid:
PUBLIC
PROC [pdState: PDState, sMin, sSize:
CARDINAL, fMin, fSize:
CARDINAL, fMinLast, fSizeLast:
CARDINAL] =
TRUSTED {
sEnd: CARDINAL ← IF pdState.leftOverMode THEN sMin+1 ELSE sMin + sSize;
bandSSize: CARDINAL ← pdState.herald.bandSSize;
command: PDFileFormat.Command ← [imaging[maskTrapezoid, 0]];
maskArgs: PDFileFormat.MaskTrapezoid ← [sMin:sMin, sSize:sSize, fMin:fMin, fSize:fSize, fMinLast:fMinLast, fSizeLast:fSizeLast];
ExtendBB[pdState, sMin, MIN[fMin, fMinLast]];
ExtendBB[pdState, sMin + sSize, MAX[fMin + fSize, fMinLast + fSizeLast]];
FOR toner: Toner
IN [pdState.firstToner..pdState.lastToner]
DO
nextBandStart: CARDINAL ← sMin + (bandSSize - (sMin MOD bandSSize));
SelectBand[pdState, sMin, toner];
EnterBandData[pdState, @command, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @maskArgs, SIZE[PDFileFormat.MaskTrapezoid]];
FOR s:
CARDINAL ← nextBandStart, s + bandSSize
WHILE s<sEnd
DO
SelectBand[pdState, s, toner];
EnterBandData[pdState, @command, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @maskArgs, SIZE[PDFileFormat.MaskTrapezoid]];
ENDLOOP;
ENDLOOP;
};
MaskSamplesRef:
PUBLIC
PROC [pdState: PDState, samplesRef: LoadReference, sMin:
CARDINAL, fMin:
CARDINAL] =
TRUSTED {
longNumber: Environment.LongNumber ← [lc[samplesRef]];
command: PDFileFormat.Command ← [imaging[maskSamplesRef, longNumber.highbits]];
args: PDFileFormat.MaskSamplesRef ← [
addrLowBits: longNumber.lowbits,
sMin: sMin,
fMin: fMin
];
ptr: LONG POINTER ← @(pdState.load[samplesRef]);
sampleArrayPtr: LONG POINTER TO PDFileFormat.SampleArray ← ptr;
sEnd: CARDINAL ← IF pdState.leftOverMode THEN sMin+1 ELSE sMin + sampleArrayPtr^.sSize;
bandSSize: CARDINAL ← pdState.herald.bandSSize;
ExtendBB[pdState, sMin, fMin];
ExtendBB[pdState, sMin + sampleArrayPtr^.sSize, fMin + sampleArrayPtr^.fSize];
FOR toner: Toner
IN [pdState.firstToner..pdState.lastToner]
DO
nextBandStart: CARDINAL ← sMin + (bandSSize - (sMin MOD bandSSize));
SelectBand[pdState, sMin, toner];
EnterBandData[pdState, @command, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @args, SIZE[PDFileFormat.MaskSamplesRef]];
FOR s:
CARDINAL ← nextBandStart, s + bandSSize
WHILE s<sEnd
DO
SelectBand[pdState, s, toner];
EnterBandData[pdState, @command, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @args, SIZE[PDFileFormat.MaskSamplesRef]];
ENDLOOP;
ENDLOOP;
};
MaskSamples:
PUBLIC
PROC [pdState: PDState, sMin:
CARDINAL, fMin:
CARDINAL, sSize:
CARDINAL, fSize:
CARDINAL, deliverProc: DeliverSampleArrayProc] =
TRUSTED {
command: PDFileFormat.Command ← [imaging[maskSamples, 0]];
bandSSize: CARDINAL = pdState.herald.bandSSize;
wordsPerLine: NAT ← (fSize+(bitsPerWord-1))/bitsPerWord;
ExtendBB[pdState, sMin, fMin];
ExtendBB[pdState, sMin + sSize, fMin + fSize];
FOR toner: Toner
IN [pdState.firstToner..pdState.lastToner]
DO
s: CARDINAL ← sMin;
sEnd: CARDINAL ← sMin + sSize;
residualThisBand: NAT ← 0;
scanLineProc:
PROC [scanLineDataPointer:
LONG
POINTER] =
TRUSTED {
IF residualThisBand = 0
THEN {
args: PDFileFormat.MaskSamples ← [
sMin: s,
fMin: fMin
];
truncatedEnd: CARDINAL ← MIN[sEnd, s + (bandSSize - (s MOD bandSSize))];
sampleArray: PDFileFormat.SampleArray ← [
sSize: (residualThisBand ← truncatedEnd - s),
fSize: fSize
];
SelectBand[pdState, s, toner];
EnterBandData[pdState, @command, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @args, SIZE[PDFileFormat.MaskSamples]];
EnterBandData[pdState, @sampleArray, SIZE[PDFileFormat.SampleArray]];
};
EnterBandData[pdState, scanLineDataPointer, wordsPerLine];
residualThisBand ← residualThisBand - 1;
s ← s + 1;
};
deliverProc[scanLineProc];
IF residualThisBand # 0 THEN ERROR;
IF s # sEnd THEN ERROR;
ENDLOOP;
};
MaskRunGroupRef:
PUBLIC
PROC [pdState: PDState, runGroupRef: LoadReference, sMin:
CARDINAL, fMin:
CARDINAL] =
TRUSTED {
longNumber: Environment.LongNumber ← [lc[runGroupRef]];
command: PDFileFormat.Command ← [imaging[maskRunGroupRef, longNumber.highbits]];
args: PDFileFormat.MaskRunGroupRef ← [
addrLowBits: longNumber.lowbits,
sMin: sMin,
fMin: fMin
];
sSize: CARDINAL ← pdState.load[runGroupRef];
fSize: CARDINAL ← pdState.load[runGroupRef-1];
sEnd: CARDINAL ← IF pdState.leftOverMode THEN sMin+1 ELSE sMin + sSize;
bandSSize: CARDINAL ← pdState.herald.bandSSize;
ExtendBB[pdState, sMin, fMin];
ExtendBB[pdState, sMin + sSize, fMin + fSize];
FOR toner: Toner
IN [pdState.firstToner..pdState.lastToner]
DO
nextBandStart: CARDINAL ← sMin + (bandSSize - (sMin MOD bandSSize));
SelectBand[pdState, sMin, toner];
EnterBandData[pdState, @command, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @args, SIZE[PDFileFormat.MaskRunGroupRef]];
FOR s:
CARDINAL ← nextBandStart, s + bandSSize
WHILE s<sEnd
DO
SelectBand[pdState, s, toner];
EnterBandData[pdState, @command, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @args, SIZE[PDFileFormat.MaskRunGroupRef]];
ENDLOOP;
ENDLOOP;
};
MaskRunGroup:
PUBLIC
PROC [pdState: PDState, deliverProc: DeliverRunGroupProc] = {
maxRuns: NAT = bandBufferSize/2 - 3;
bandSSize: CARDINAL = pdState.herald.bandSSize;
buffer:
MACHINE
DEPENDENT
RECORD [
command: PDFileFormat.Command ← [imaging[maskRunGroup]],
sMin: CARDINAL,
sSize: CARDINAL,
run: ARRAY [0..maxRuns) OF PDFileFormat.Run
];
nRuns: NAT ← 0;
scanLineNumber: CARDINAL;
bandEnd: CARDINAL;
currentToner: Toner;
PutBuffer:
PROC =
TRUSTED {
IF nRuns > 0
THEN {
IF
NOT buffer.run[nRuns - 1].lastRun
THEN {
buffer.sSize ← buffer.sSize + 1;
buffer.run[nRuns - 1].lastRun ← TRUE;
};
SelectBand[pdState, buffer.sMin, currentToner];
EnterBandData[pdState, @buffer, SIZE[PDFileFormat.Command] + SIZE[CARDINAL] + SIZE[CARDINAL] + nRuns * SIZE[PDFileFormat.Run]];
nRuns ← 0;
buffer.sMin ← scanLineNumber;
buffer.sSize ← 0;
};
};
InitBuffer:
PROC [sMin:
CARDINAL] = {
buffer.sMin ← scanLineNumber ← sMin;
buffer.sSize ← 0;
bandEnd ← sMin - sMin MOD bandSSize + bandSSize;
};
BufferRun:
PROC [fMin, fSize:
CARDINAL] = {
IF nRuns = maxRuns THEN PutBuffer[];
buffer.run[nRuns] ← [fMin: fMin, fSize: fSize, lastRun: FALSE];
nRuns ← nRuns + 1;
};
NextLine:
PROC = {
buffer.sSize ← buffer.sSize + 1;
buffer.run[nRuns - 1].lastRun ← TRUE;
scanLineNumber ← scanLineNumber + 1;
};
CaptureRun:
PROC [sMin, fMin, fSize:
CARDINAL] = {
IF nRuns = 0 THEN InitBuffer[sMin]
ELSE IF sMin >= bandEnd OR NOT (sMin IN [scanLineNumber..scanLineNumber+1]) OR nRuns = maxRuns THEN {PutBuffer[]; InitBuffer[sMin]};
IF sMin > scanLineNumber THEN NextLine[];
IF sMin # scanLineNumber THEN ERROR;
IF INT[fMin] + INT[fSize] > INT[LAST[CARDINAL]] THEN {fSize ← LAST[CARDINAL] - fMin};
ExtendBB[pdState, sMin, fMin];
IF fSize >
LAST[
NAT]
THEN {
BufferRun[fMin, LAST[NAT]];
fMin ← fMin + LAST[NAT]; fSize ← fSize - LAST[NAT];
};
BufferRun[fMin, fSize];
ExtendBB[pdState, sMin + 1, fMin + fSize];
};
FOR toner: Toner
IN [pdState.firstToner..pdState.lastToner]
DO
currentToner ← toner;
deliverProc[CaptureRun];
PutBuffer[];
ENDLOOP;
};
ColorSamples:
PUBLIC
PROC [pdState: PDState, toner: Toner, sMin
, fMin:
CARDINAL, sSize, fSize:
CARDINAL, deliverProc: DeliverSampleArrayProc, tFlag: TFlag] =
TRUSTED {
tBit: [0..1] = IF tFlag = opaque THEN PDFileFormat.opaqueFlag ELSE PDFileFormat.transparentFlag;
colorCommand: PDFileFormat.Command ← [imaging[colorSamples, tBit]];
bandSSize: CARDINAL = pdState.herald.bandSSize;
wordsPerLine: NAT ← (fSize+(bitsPerWord-1))/bitsPerWord;
s: CARDINAL ← sMin;
sEnd: CARDINAL ← sMin + sSize;
residualThisBand: NAT ← 0;
CaptureScanLine:
PROC [scanLineDataPointer:
LONG
POINTER] =
TRUSTED {
IF residualThisBand = 0
THEN {
args: PDFileFormat.MaskSamples ← [
sMin: s,
fMin: fMin
];
truncatedEnd: CARDINAL ← MIN[sEnd, s + bandSSize - (s MOD bandSSize)];
sampleArray: PDFileFormat.SampleArray ← [
sSize: (residualThisBand ← truncatedEnd - s),
fSize: fSize
];
SelectBand[pdState, s, toner];
EnterBandData[pdState, @colorCommand, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @args, SIZE[PDFileFormat.MaskSamples]];
EnterBandData[pdState, @sampleArray, SIZE[PDFileFormat.SampleArray]];
};
EnterBandData[pdState, scanLineDataPointer, wordsPerLine];
residualThisBand ← residualThisBand - 1;
s ← s + 1;
};
ExtendBB[pdState, sMin, fMin];
ExtendBB[pdState, sMin + sSize, fMin + fSize];
deliverProc[CaptureScanLine];
IF residualThisBand # 0 THEN ERROR;
IF s # sEnd THEN ERROR;
};
RemainingLoadSize:
PUBLIC
PROC [pdState: PDState]
RETURNS [words:
INT] = {
words ← INT[maxLoadSize] - pdState.currentLoadLocation;
};
SetLoadLocation:
PUBLIC
PROC [pdState: PDState, loadReference: LoadReference] = {
WriteLoadAdditions[pdState];
pdState.currentLoadLocation ← pdState.loadWrittenLength ← loadReference;
};
LoadRunGroup:
PUBLIC
PROC [pdState: PDState, deliverProc: DeliverRunGroupProc]
RETURNS [loadReference: LoadReference] =
TRUSTED {
highBit: CARDINAL = CARDINAL[LAST[NAT]] + 1;
scanLineNumber: CARDINAL ← 0;
loc: CARDINAL ← pdState.currentLoadLocation;
load: REF LoadRec ← pdState.load;
fMax: CARDINAL ← 0;
scanLineEmpty: BOOLEAN ← TRUE;
CaptureRun:
PROC [sMin, fMin, fSize:
CARDINAL] =
TRUSTED {
IF sMin<scanLineNumber THEN ERROR; -- scan lines must come in increasing s order.
WHILE sMin#scanLineNumber
DO
IF scanLineEmpty THEN {load[loc] ← 0; load[loc+1] ← highBit; loc ← loc+2}
ELSE {load[loc-1] ← load[loc-1] + highBit};
scanLineNumber ← scanLineNumber+1;
scanLineEmpty ← TRUE;
ENDLOOP;
scanLineEmpty ← FALSE;
IF INT[fMin] + INT[fSize] > INT[LAST[CARDINAL]] THEN {fSize ← LAST[CARDINAL] - fMin};
IF fSize >
LAST[
NAT]
THEN {
load[loc] ← fMin; load[loc+1] ← LAST[NAT]; loc ← loc+2;
fMin ← fMin + LAST[NAT]; fSize ← fSize - LAST[NAT];
};
load[loc] ← fMin; load[loc+1] ← fSize; loc ← loc+2;
fMax ← MAX[fMax, fMin+fSize];
};
IF load = NIL THEN pdState.load ← load ← NEW[LoadRec];
loadReference ← loc+1;
Reserve a word in the load for fMax.
loc ← loc + 2;
Will come back to fill in sSize.
deliverProc[CaptureRun];
IF NOT scanLineEmpty THEN {load[loc-1] ← load[loc-1] + highBit; scanLineNumber ← scanLineNumber+1};
load[loadReference-1] ← fMax;
load[loadReference] ← scanLineNumber;
pdState.currentLoadLocation ← loc;
pdState.herald.maxLoadWord ← MAX[pdState.herald.maxLoadWord, loc];
};
LoadSampleArray:
PUBLIC
PROC [pdState: PDState, sSize, fSize:
CARDINAL, deliverProc: DeliverSampleArrayProc]
RETURNS [loadReference: LoadReference] =
TRUSTED {
CaptureScanLine:
PROC [scanLineDataPointer:
LONG
POINTER] =
TRUSTED {
source: LONG POINTER TO WORD ← scanLineDataPointer;
startLoc: CARDINAL ← loc;
FOR i:
NAT
IN [0..wordsPerLine)
DO
load[startLoc+i] ← (source+i)^;
ENDLOOP;
loc ← loc + wordsPerLine;
};
load: REF LoadRec ← pdState.load;
wordsPerLine: NAT ← (fSize+(bitsPerWord-1))/bitsPerWord;
loc: LONG CARDINAL ← pdState.currentLoadLocation;
numberOfWordsOfData: LONG CARDINAL ← LONG[sSize]*wordsPerLine;
IF load = NIL THEN pdState.load ← load ← NEW[LoadRec];
loadReference ← loc;
load[loc] ← sSize; loc ← loc+1;
load[loc] ← fSize; loc ← loc+1;
deliverProc[CaptureScanLine];
IF loc # loadReference + SIZE[PDFileFormat.SampleArray] + numberOfWordsOfData THEN ERROR;
pdState.currentLoadLocation ← loc;
pdState.herald.maxLoadWord ← MAX[pdState.herald.maxLoadWord, loc];
};
LoadContiguousSampleArray:
PUBLIC
PROC [pdState: PDState, sSize, fSize:
CARDINAL, bitsPtr:
LONG
POINTER]
RETURNS [loadReference: LoadReference] =
TRUSTED {
source: LONG POINTER TO WORD ← bitsPtr;
load: REF LoadRec ← pdState.load;
wordsPerLine: INT ← (fSize+(bitsPerWord-1))/bitsPerWord;
loc: LONG CARDINAL ← pdState.currentLoadLocation;
IF load = NIL THEN pdState.load ← load ← NEW[LoadRec];
loadReference ← loc;
load[loc] ← sSize; loc ← loc+1;
load[loc] ← fSize; loc ← loc+1;
FOR i:
INT
IN [0..sSize*wordsPerLine)
DO
load[loc] ← source^;
loc ← loc+1;
source ← source+1;
ENDLOOP;
pdState.currentLoadLocation ← loc;
pdState.herald.maxLoadWord ← MAX[pdState.herald.maxLoadWord, loc];
};
LoadColorTile:
PUBLIC
PROC [pdState: PDState, phase:
CARDINAL, sMin, fMin:
CARDINAL, sSize, fSize:
CARDINAL, deliverProc: DeliverSampleArrayProc]
RETURNS [loadReference: LoadReference] =
TRUSTED {
CaptureScanLine:
PROC [scanLineDataPointer:
LONG
POINTER] =
TRUSTED {
source: LONG POINTER TO WORD ← scanLineDataPointer;
startLoc: CARDINAL ← loc;
FOR i:
NAT
IN [0..wordsPerLine)
DO
load[startLoc+i] ← (source+i)^;
ENDLOOP;
loc ← loc + wordsPerLine;
};
load: REF LoadRec ← pdState.load;
wordsPerLine: NAT ← (fSize+(bitsPerWord-1))/bitsPerWord;
loc: LONG CARDINAL ← pdState.currentLoadLocation;
numberOfWordsOfData: LONG CARDINAL ← LONG[sSize]*wordsPerLine;
IF load = NIL THEN pdState.load ← load ← NEW[LoadRec];
loadReference ← loc;
load[loc] ← phase; loc ← loc+1;
load[loc] ← sMin; loc ← loc+1;
load[loc] ← fMin; loc ← loc+1;
load[loc] ← sSize; loc ← loc+1;
load[loc] ← fSize; loc ← loc+1;
deliverProc[CaptureScanLine];
IF loc # loadReference + SIZE[PDFileFormat.Tile] + numberOfWordsOfData THEN ERROR;
pdState.currentLoadLocation ← loc;
pdState.herald.maxLoadWord ← MAX[pdState.herald.maxLoadWord, loc];
};
LoadContiguousColorTile:
PUBLIC
PROC [pdState: PDState, phase:
CARDINAL, sMin, fMin:
CARDINAL, sSize, fSize:
CARDINAL, bitsPtr:
LONG
POINTER]
RETURNS [loadReference: LoadReference] =
TRUSTED {
source: LONG POINTER TO WORD ← bitsPtr;
load: REF LoadRec ← pdState.load;
wordsPerLine: INT ← (fSize+(bitsPerWord-1))/bitsPerWord;
loc: LONG CARDINAL ← pdState.currentLoadLocation;
IF load = NIL THEN pdState.load ← load ← NEW[LoadRec];
loadReference ← loc;
load[loc] ← phase; loc ← loc+1;
load[loc] ← sMin; loc ← loc+1;
load[loc] ← fMin; loc ← loc+1;
load[loc] ← sSize; loc ← loc+1;
load[loc] ← fSize; loc ← loc+1;
FOR i:
INT
IN [0..sSize*wordsPerLine)
DO
load[loc] ← source^;
loc ← loc+1;
source ← source+1;
ENDLOOP;
pdState.currentLoadLocation ← loc;
pdState.herald.maxLoadWord ← MAX[pdState.herald.maxLoadWord, loc];
};
EndPage:
PUBLIC
PROC [pdState: PDState] = {
startBand: NAT ← pdState.sMinPage/pdState.herald.bandSSize;
endBand: NAT ← (pdState.sMaxPage+pdState.herald.bandSSize-1)/pdState.herald.bandSSize;
nBands: NAT ← MAX[0, INTEGER[endBand]-startBand];
fSizePage: CARDINAL ← MAX[INT[pdState.fMaxPage]-pdState.fMinPage, 0];
IF nBands = 0 THEN startBand ← 0;
IF fSizePage = 0 THEN pdState.fMinPage ← 0;
WriteLoadAdditions[pdState];
FOR t: Toner
IN [pdState.firstToner..pdState.lastToner]
DO
bands: Bands ← pdState.bands[t];
WriteStartImage[
pdState: pdState,
feed: t = pdState.firstToner,
strip: t = pdState.lastToner,
toner: t,
passBands: startBand,
nBands: nBands,
fMinPage: pdState.fMinPage,
fSizePage: fSizePage
];
WriteBands[pdState, bands, startBand, nBands];
ENDLOOP;
pdState.sMinPage ← pdState.herald.imageSSize;
pdState.fMinPage ← pdState.herald.imageFSize;
pdState.sMaxPage ← pdState.fMaxPage ← 0;
};
FlushPage:
PUBLIC
PROC [pdState: PDState] = {
In case the client decides it didn't really want this page after all.
startBand: NAT ← pdState.sMinPage/pdState.herald.bandSSize;
endBand: NAT ← (pdState.sMaxPage+pdState.herald.bandSSize-1)/pdState.herald.bandSSize;
nBands: NAT ← MAX[0, INTEGER[endBand]-startBand];
fSizePage: CARDINAL ← MAX[INT[pdState.fMaxPage]-pdState.fMinPage, 0];
FOR t: Toner
IN [pdState.firstToner..pdState.lastToner]
DO
bands: Bands ← pdState.bands[t];
FOR i:
NAT
IN [startBand..startBand+nBands)
DO
bands[i] ← [colorId: 0, bandBuffers: NIL];
ENDLOOP
ENDLOOP;
pdState.sMinPage ← pdState.herald.imageSSize;
pdState.fMinPage ← pdState.herald.imageFSize;
pdState.sMaxPage ← pdState.fMaxPage ← 0;
};
Close:
PUBLIC
PROC [pdState: PDState] = {
WriteControlCommand[pdState, endDocument];
pdState.stream.SetIndex[0];
WriteHerald[pdState];
pdState.stream.Close[];
};
ExtendBB:
PROC [pdState: PDState, s:
CARDINAL, f:
CARDINAL] = {
pdState.sMinPage ← MIN[s, pdState.sMinPage];
pdState.sMaxPage ← MAX[s, pdState.sMaxPage];
pdState.fMinPage ← MIN[f, pdState.fMinPage];
pdState.fMaxPage ← MAX[f, pdState.fMaxPage];
};
SelectBandNoColor:
PROC [pdState: PDState, sMin:
CARDINAL, toner: Toner] =
TRUSTED {
bandNum: NAT ← sMin/pdState.herald.bandSSize;
bands: Bands ← pdState.bands[toner];
IF bands[bandNum].bandBuffers = NIL THEN bands[bandNum].bandBuffers ← NEW[BandBufferRec];
pdState.selectedBands ← bands;
pdState.selectedBandNum ← bandNum;
};
SelectBand:
PROC [pdState: PDState, sMin:
CARDINAL, toner: Toner] =
TRUSTED {
colorId: INT ← pdState.colorDescriptor[toner].colorId;
longPriority: Environment.LongNumber ← [lc[colorId]];
priorityHighbits: [0..256) ← longPriority.highbits;
priorityLowbits: CARDINAL ← longPriority.lowbits;
priorityCommand: PDFileFormat.Command ← [control[setPriority, priorityHighbits]];
bandNum: NAT ← sMin/pdState.herald.bandSSize;
bands: Bands ← pdState.bands[toner];
IF bands[bandNum].bandBuffers = NIL THEN bands[bandNum].bandBuffers ← NEW[BandBufferRec];
pdState.selectedBands ← bands;
pdState.selectedBandNum ← bandNum;
IF colorId # bands[bandNum].colorId
THEN {
bands[bandNum].colorId ← colorId;
IF pdState.priorityImportant
THEN {
EnterBandData[pdState, @priorityCommand, SIZE[PDFileFormat.Command]];
EnterBandData[pdState, @priorityLowbits, SIZE[CARDINAL]];
};
EnterBandData[pdState, @(pdState.colorDescriptor[toner].command), pdState.colorDescriptor[toner].length];
};
};
EnterBandData:
PROC [pdState: PDState, startPtr:
LONG
POINTER, wordCount:
NAT] =
TRUSTED {
source: LONG POINTER TO WORD ← startPtr;
bandBuffers: BandBuffer ← pdState.selectedBands[pdState.selectedBandNum].bandBuffers;
length: NAT ← bandBuffers.length;
WHILE wordCount > 0
DO
IF length = bandBufferSize
THEN {
new: BandBuffer ← NEW[BandBufferRec];
bandBuffers.length ← length;
new.link ← bandBuffers;
bandBuffers ← new;
length ← 0;
};
bandBuffers.word[length] ← source^;
length ← length + 1;
wordCount ← wordCount - 1;
source ← source + 1;
ENDLOOP;
bandBuffers.length ← length;
pdState.selectedBands[pdState.selectedBandNum].bandBuffers ← bandBuffers;
};
WriteLoadAdditions:
PROC [pdState: PDState] =
TRUSTED {
Writes out any additions to the font load
WHILE pdState.loadWrittenLength < pdState.currentLoadLocation
DO
lengthOfAdditions: INT ← pdState.currentLoadLocation-pdState.loadWrittenLength;
lengthOfChunk: INT ← MIN[lengthOfAdditions, LAST[NAT]];
unsafeBlock: IO.UnsafeBlock = [base: @(pdState.load[pdState.loadWrittenLength]), startIndex: 0, stopIndexPlusOne: lengthOfChunk*bytesPerWord];
WriteControlCommand[pdState, storeLoad];
WriteLongCardinal[pdState, pdState.loadWrittenLength];
WriteCardinal[pdState, lengthOfChunk];
pdState.stream.UnsafePutBlock[unsafeBlock];
pdState.loadWrittenLength ← pdState.loadWrittenLength + lengthOfChunk;
ENDLOOP;
};
WriteLongCardinal:
PROC [pdState: PDState, lc:
LONG
CARDINAL] =
TRUSTED {
unsafeBlock: IO.UnsafeBlock = [base: @lc, startIndex: 0, stopIndexPlusOne: SIZE[LONG CARDINAL]*bytesPerWord];
pdState.stream.UnsafePutBlock[unsafeBlock];
};
WriteCardinal:
PROC [pdState: PDState, c:
CARDINAL] =
TRUSTED {
unsafeBlock: IO.UnsafeBlock = [base: @c, startIndex: 0, stopIndexPlusOne: SIZE[CARDINAL]*bytesPerWord];
pdState.stream.UnsafePutBlock[unsafeBlock];
};
WriteHerald:
PROC [pdState: PDState] =
TRUSTED {
unsafeBlock: IO.UnsafeBlock = [base: @pdState.herald, startIndex: 0, stopIndexPlusOne: SIZE[PDFileFormat.Herald]*bytesPerWord];
pdState.stream.UnsafePutBlock[unsafeBlock];
};
WriteControlCommand:
PROC [pdState: PDState, controlCom: PDFileFormat.ControlCom] =
TRUSTED {
command: PDFileFormat.Command ← [control[controlCom]];
unsafeBlock: IO.UnsafeBlock = [base: @command, startIndex: 0, stopIndexPlusOne: SIZE[PDFileFormat.Command]*bytesPerWord];
pdState.stream.UnsafePutBlock[unsafeBlock];
};
WriteStartImage:
PROC [
pdState: PDState,
feed: BOOLEAN,
strip: BOOLEAN,
toner: Toner,
passBands: NAT,
nBands: NAT,
fMinPage: CARDINAL,
fSizePage: CARDINAL
] = TRUSTED {
StartImageBuf:
TYPE =
MACHINE
DEPENDENT
RECORD [
command: PDFileFormat.Command,
args: PDFileFormat.StartImage
];
startImageBuf: StartImageBuf ← [
command: [control[com: startImage]],
args: [leftOverMode: pdState.leftOverMode, feed: feed, strip: strip, toner: toner, passBands: passBands, nBands: nBands, fMinPage: fMinPage, fSizePage: fSizePage]
];
unsafeBlock: IO.UnsafeBlock = [base: @startImageBuf, startIndex: 0, stopIndexPlusOne: SIZE[StartImageBuf]*bytesPerWord];
pdState.stream.UnsafePutBlock[unsafeBlock];
};
WriteBands:
PROC [pdState: PDState, bands: Bands, startBand, nBands:
NAT] =
TRUSTED {
Writes out the bands, resetting them along the way.
FOR bandNum:
NAT
IN [startBand..startBand+nBands)
DO
bandBuffers: BandBuffer ← bands[bandNum].bandBuffers;
bufList: BandBuffer ← NIL;
bands[bandNum] ← [0, NIL];
Reverse the list of buffers.
WHILE bandBuffers #
NIL
DO
t: BandBuffer ← bandBuffers;
bandBuffers ← bandBuffers.link;
t.link ← bufList;
bufList ← t;
ENDLOOP;
WHILE bufList #
NIL
DO
unsafeBlock: IO.UnsafeBlock = [base: @(bufList.word[0]), startIndex: 0, stopIndexPlusOne: INT[bufList.length]*bytesPerWord];
t: BandBuffer ← bufList;
pdState.stream.UnsafePutBlock[unsafeBlock];
bufList ← bufList.link;
t ← NIL; -- Free goes here
ENDLOOP;
WriteControlCommand[pdState, endBand];
ENDLOOP;
};
END.