PDFileWriterImpl.mesa
Michael Plass, April 30, 1984 4:54:01 pm PDT
DIRECTORY
Basics,
CountedVM,
FS,
IO,
PDFileFormat,
PDFileWriter,
PrincOpsUtils,
Rope
;
PDFileWriterImpl: CEDAR PROGRAM
IMPORTS Basics, CountedVM, FS, IO, PrincOpsUtils
EXPORTS PDFileWriter
= BEGIN
BlockTransfer: UNSAFE PROC [source: LONG POINTER, count: CARDINAL, dest: LONG POINTER]
~ UNCHECKED INLINE {PrincOpsUtils.LongCopy[from: source, nwords: count, to: dest]};
LongBlockTransfer: UNSAFE PROC [source: LONG POINTER, count: INT, dest: LONG POINTER] ~ UNCHECKED {
WHILE count > LAST[CARDINAL] DO
BlockTransfer[source: source, count: LAST[CARDINAL], dest: dest];
source ← source + LAST[CARDINAL];
dest ← dest + LAST[CARDINAL];
count ← count - LAST[CARDINAL];
ENDLOOP;
IF count > 0 THEN BlockTransfer[source: source, count: count, dest: dest];
};
bytesPerWord: CARDINAL = Basics.bytesPerWord;
bitsPerWord: CARDINAL = Basics.bitsPerWord;
ROPE: TYPE = Rope.ROPE;
LoadReference: TYPE = NAT;
DeliverRunGroupProc: TYPE = PDFileWriter.DeliverRunGroupProc;
CaptureRunProc: TYPE = PDFileWriter.CaptureRunProc;
DeliverSampleArrayProc: TYPE = PDFileWriter.DeliverSampleArrayProc;
CaptureScanLineProc: TYPE = PDFileWriter.CaptureScanLineProc;
TFlag: TYPE = PDFileWriter.TFlag;
TonerSet: TYPE = PDFileWriter.TonerSet;
Toner: TYPE = PDFileFormat.Toner;
Bands: TYPE = REF BandsRec;
BandsRec: TYPE = RECORD [
bands: SEQUENCE maxBands: NAT OF Band
];
Band: TYPE = RECORD [
colorId: INT,
bandBuffer: BandBuffer
];
bandBufferSize: NAT = 200;
BandBuffer: TYPE = REF BandBufferRec;
BandBufferRec: TYPE = RECORD [
length: NAT ← 0,
overflowIndices: LIST OF INTNIL,
word: ARRAY [0..bandBufferSize) OF WORD
];
ColorDescriptor: TYPE = MACHINE DEPENDENT RECORD [
colorId: INT ← 0, -- bumped whenever the color changes.
enabled: BOOLEANTRUE,
length: NAT ← 1,
command: PDFileFormat.Command.control ← [control[setColorInk]],
setColorTile: PDFileFormat.SetColorTile
];
maxLoadItems: CARDINAL ← 2000;
LoadDescription: TYPE = REF LoadDescriptionRep;
LoadDescriptionRep: TYPE = RECORD [
storageRef: REF, -- to protect against garbage collection
pointer: LONG POINTER,
words: INT, -- at least as big as loadSizeInWords
count: NAT ← 0,
entries: SEQUENCE maxCount: NAT OF LoadEntryDescription
];
LoadEntryType: TYPE = {none, samples, runGroup, tile};
LoadEntryDescription: TYPE = RECORD [
loadEntryType: LoadEntryType,
offsetHighBits: [0..256),
offsetLowBits: CARDINAL,
pageOfMostRecentUse: CARDINAL,
numberOfPagesUsedIn: CARDINAL
];
PDState: PUBLIC TYPE = REF PDStateRec;
PDStateRec: PUBLIC TYPE = RECORD [
fileName: ROPE,
herald: PDFileFormat.Herald,
colorDescriptor: ARRAY Toner OF ColorDescriptor,
stream: IO.STREAM,
toners: TonerSet ← [black: TRUE],
firstToner, lastToner: Toner ← black,
feed: BOOLEANTRUE,
strip: BOOLEANTRUE,
bands: ARRAY Toner OF Bands,
selectedBands: Bands ← NIL,
selectedBandNum: NAT ← 0,
sMinPage: CARDINAL,
sMaxPage: CARDINAL,
fMinPage: CARDINAL,
fMaxPage: CARDINAL,
currentImage: CARDINAL ← 1,
currentLoadLocation: INT ← 0,
loadWrittenLength: INT ← 0,
loadSizeInWords: INT,
leftOverMode: BOOLEAN,
priorityImportant: BOOLEAN,
loadDescription: LoadDescription,
overflowStream: IO.STREAMNIL
];
Create: PUBLIC PROC [fileName: ROPE, deviceCode: PDFileFormat.DeviceCode, sResolution, fResolution, imageSSize, imageFSize: CARDINAL, bandSSize: CARDINAL, copies: CARDINAL, leftOverMode: BOOLEAN, maxLoadWords: INT] 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.loadSizeInWordsmaxLoadWords;
pdState.leftOverMode ← leftOverMode;
pdState.priorityImportant ← FALSE;
pdState.sMaxPage ← pdState.fMaxPage ← 0;
pdState.toners ← [black: TRUE];
pdState.feed ← pdState.strip ← TRUE;
nBands ← (pdState.herald.imageSSize+pdState.herald.bandSSize-1)/pdState.herald.bandSSize;
pdState.bands[black] ← NEW [BandsRec[nBands]];
pdState.stream ← FS.StreamOpen[fileName, $create];
WriteHerald[pdState];
We will come back and overwrite this when the file is closed.
};
SetPriorityImportant: PUBLIC PROC [pdState: PDState, priorityImportant: BOOLEAN] RETURNS [previousValue: BOOLEAN] = {
previousValue ← pdState.priorityImportant;
pdState.priorityImportant ← priorityImportant;
};
StartImage: PUBLIC PROC [pdState: PDState, toners: TonerSet ← [black: TRUE], feed, strip: BOOLEANTRUE] ~ {
pdState.feed ← feed;
pdState.strip ← strip;
pdState.toners ← toners;
pdState.firstToner ← Toner.LAST;
pdState.lastToner ← Toner.FIRST;
FOR t: Toner IN [Toner.FIRST..Toner.LAST] DO
IF toners[t] THEN {
IF pdState.bands[t] = NIL THEN {
pdState.bands[t] ← NEW [BandsRec[pdState.bands[black].maxBands]];
};
IF pdState.firstToner = Toner.LAST THEN pdState.firstToner ← t;
pdState.lastToner ← t;
};
pdState.colorDescriptor[t] ← [
colorId: 0,
length: 1,
command: [control[setColorInk]],
setColorTile: [addr: 0],
enabled: toners[t]
];
ENDLOOP;
};
SetColorInk: PUBLIC PROC [pdState: PDState, toner: Toner] = {
IF NOT pdState.toners[toner] THEN ERROR;
pdState.colorDescriptor[toner].colorId ← pdState.colorDescriptor[toner].colorId + 1;
pdState.colorDescriptor[toner].length ← SIZE[PDFileFormat.Command];
pdState.colorDescriptor[toner].command ← [control[setColorInk]];
pdState.colorDescriptor[toner].enabled ← TRUE;
};
SetColorClear: PUBLIC PROC [pdState: PDState, toner: Toner] = {
IF NOT pdState.toners[toner] THEN ERROR;
pdState.colorDescriptor[toner].colorId ← pdState.colorDescriptor[toner].colorId + 1;
pdState.colorDescriptor[toner].length ← SIZE[PDFileFormat.Command];
pdState.colorDescriptor[toner].command ← [control[setColorClear]];
pdState.colorDescriptor[toner].enabled ← TRUE;
};
SetColorOff: PUBLIC PROC [pdState: PDState, toner: Toner] = {
pdState.colorDescriptor[toner].enabled ← FALSE;
};
SetColorTile: PUBLIC PROC [pdState: PDState, toner: Toner, tileRef: LoadReference, tFlag: TFlag] = TRUSTED {
loadEntry: LoadEntryDescription ← pdState.loadDescription[tileRef];
reference: Basics.LongNumber ← [num[lowbits: loadEntry.offsetLowBits, highbits: loadEntry.offsetHighBits]];
colorId: INT ← pdState.colorDescriptor[toner].colorId + 1;
tBit: [0..1] = IF tFlag = opaque THEN PDFileFormat.opaqueFlag ELSE PDFileFormat.transparentFlag;
IF loadEntry.loadEntryType # tile THEN ERROR;
IF NOT pdState.toners[toner] THEN ERROR;
pdState.colorDescriptor[toner] ← [
colorId: colorId,
length: SIZE[PDFileFormat.Command] + SIZE[PDFileFormat.SetColorTile],
command: [control[setColorTile, tBit]],
setColorTile: [addr: reference.lc],
enabled: TRUE
];
};
DoForEachToner: PUBLIC PROC [pdState: PDState, proc: PROC[Toner]] = {
FOR toner: Toner IN [pdState.firstToner..pdState.lastToner] DO
IF pdState.toners[toner] THEN 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: CARDINALIF 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
IF pdState.colorDescriptor[toner].enabled THEN {
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: CARDINALIF 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
IF pdState.colorDescriptor[toner].enabled THEN {
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 {
loadEntry: LoadEntryDescription ← pdState.loadDescription[samplesRef];
reference: Basics.LongNumber ← [num[lowbits: loadEntry.offsetLowBits, highbits: loadEntry.offsetHighBits]];
command: PDFileFormat.Command ← [imaging[maskSamplesRef, loadEntry.offsetHighBits]];
args: PDFileFormat.MaskSamplesRef ← [
addrLowBits: loadEntry.offsetLowBits,
sMin: sMin,
fMin: fMin
];
sampleArrayPtr: LONG POINTER TO PDFileFormat.SampleArray ← pdState.loadDescription.pointer + reference.lc;
sEnd: CARDINALIF pdState.leftOverMode THEN sMin+1 ELSE sMin + sampleArrayPtr^.sSize;
bandSSize: CARDINAL ← pdState.herald.bandSSize;
IF loadEntry.loadEntryType # samples THEN ERROR;
ExtendBB[pdState, sMin, fMin];
ExtendBB[pdState, sMin + sampleArrayPtr^.sSize, fMin + sampleArrayPtr^.fSize];
FOR toner: Toner IN [pdState.firstToner..pdState.lastToner] DO
IF pdState.colorDescriptor[toner].enabled THEN {
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
IF pdState.colorDescriptor[toner].enabled THEN {
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: CARDINALMIN[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 {
loadEntry: LoadEntryDescription ← pdState.loadDescription[runGroupRef];
reference: Basics.LongNumber ← [num[lowbits: loadEntry.offsetLowBits, highbits: loadEntry.offsetHighBits]];
command: PDFileFormat.Command ← [imaging[maskRunGroupRef, loadEntry.offsetHighBits]];
args: PDFileFormat.MaskRunGroupRef ← [
addrLowBits: loadEntry.offsetLowBits,
sMin: sMin,
fMin: fMin
];
fSizePtr: LONG POINTER TO CARDINAL ← pdState.loadDescription.pointer + reference.lc - 1;
sSizePtr: LONG POINTER TO CARDINAL ← pdState.loadDescription.pointer + reference.lc;
sEnd: CARDINALIF pdState.leftOverMode THEN sMin+1 ELSE sMin + sSizePtr^;
bandSSize: CARDINAL ← pdState.herald.bandSSize;
IF loadEntry.loadEntryType # runGroup THEN ERROR;
ExtendBB[pdState, sMin, fMin];
ExtendBB[pdState, sMin + sSizePtr^, fMin + fSizePtr^];
FOR toner: Toner IN [pdState.firstToner..pdState.lastToner] DO
IF pdState.colorDescriptor[toner].enabled THEN {
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/SIZE[PDFileFormat.Run];
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] = INLINE {
IF nRuns = maxRuns THEN PutBuffer[];
buffer.run[nRuns] ← [fMin: fMin, fSize: fSize, lastRun: FALSE];
nRuns ← nRuns + 1;
};
NextLine: PROC = INLINE {
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
IF pdState.colorDescriptor[toner].enabled THEN {
currentToner ← toner;
deliverProc[CaptureRun];
PutBuffer[];
};
ENDLOOP;
};
ColorSamples: PUBLIC PROC [pdState: PDState, toner: Toner, sMin, fMin: CARDINAL, sSize, fSize: CARDINAL, deliverProc: DeliverSampleArrayProc, tFlag: TFlag] = TRUSTED {
colorCommand: PDFileFormat.Command ← [imaging[IF tFlag = opaque THEN colorSamples ELSE maskSamples]];
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: CARDINALMIN[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;
};
IF pdState.colorDescriptor[toner].enabled THEN {
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 ← pdState.loadSizeInWords - pdState.currentLoadLocation;
IF pdState.loadDescription # NIL AND pdState.loadDescription.count = pdState.loadDescription.maxCount THEN words ← 0;
};
GetLoadDescription: PROC [pdState: PDState] RETURNS [LoadDescription] = {
IF pdState.loadDescription = NIL THEN {
loadDescription: LoadDescription ← NEW[LoadDescriptionRep[maxLoadItems]];
countedVM: CountedVM.Handle ← CountedVM.Allocate[pdState.loadSizeInWords];
loadDescription.storageRef ← countedVM;
TRUSTED {loadDescription.pointer ← CountedVM.Pointer[countedVM]};
loadDescription.words ← CountedVM.Words[countedVM];
loadDescription.count ← 0;
pdState.loadDescription ← loadDescription;
};
RETURN [pdState.loadDescription]
};
loadBreakOffset: INTLAST[INT];
loadBreakCount: INT ← 0;
DebugLoad: PROC [loadOffset: INT] ~ {
IF loadOffset = loadBreakOffset THEN
set a breakpoint here to debug strange load contents.
loadBreakCount ← loadBreakCount + 1;
};
LoadRunGroup: PUBLIC PROC [pdState: PDState, deliverProc: DeliverRunGroupProc] RETURNS [loadReference: LoadReference] = TRUSTED {
highBit: CARDINAL = CARDINAL[LAST[NAT]] + 1;
loadDescription: LoadDescription ← GetLoadDescription[pdState];
scanLineNumber: CARDINAL ← 0;
maxLoc: INT ← pdState.loadSizeInWords;
loc: INT ← pdState.currentLoadLocation;
base: LONG POINTER TO CARDINAL ← loadDescription.pointer;
fMax: CARDINAL ← 0;
scanLineEmpty: BOOLEANTRUE;
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 loc+2 > maxLoc THEN ERROR;
IF scanLineEmpty THEN {(base+loc)^ ← 0; (base+loc+1)^ ← highBit; loc ← loc+2}
ELSE {(base+loc-1)^ ← (base+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 {
IF loc+2 > maxLoc THEN ERROR;
(base+loc)^ ← fMin; (base+loc+1)^ ← LAST[NAT]; loc ← loc+2;
fMin ← fMin + LAST[NAT]; fSize ← fSize - LAST[NAT];
};
IF loc+2 > maxLoc THEN ERROR;
(base+loc)^ ← fMin; (base+loc+1)^ ← fSize; loc ← loc+2;
fMax ← MAX[fMax, fMin+fSize];
};
origin: INT ← loc+1;
Reserve a word in the load for fMax.
loc ← loc + 2;
Will come back to fill in sSize.
IF loc > maxLoc THEN ERROR;
deliverProc[CaptureRun];
IF NOT scanLineEmpty THEN {(base+loc-1)^ ← (base+loc-1)^ + highBit; scanLineNumber ← scanLineNumber+1};
(base+origin-1)^ ← fMax;
Fill in fMax.
(base+origin)^ ← scanLineNumber;
Fill in sSize.
pdState.currentLoadLocation ← loc;
pdState.herald.maxLoadWord ← MAX[pdState.herald.maxLoadWord, loc];
loadReference ← loadDescription.count;
loadDescription.count ← loadDescription.count + 1;
loadDescription[loadReference] ← [
loadEntryType: runGroup,
offsetHighBits: Basics.HighHalf[origin],
offsetLowBits: Basics.LowHalf[origin],
pageOfMostRecentUse: 0,
numberOfPagesUsedIn: 0
];
DebugLoad[origin];
};
LoadContiguousSampleArray: PUBLIC PROC [pdState: PDState, sSize, fSize: CARDINAL, bitsPtr: LONG POINTER] RETURNS [loadReference: LoadReference] = TRUSTED {
loadDescription: LoadDescription ← GetLoadDescription[pdState];
source: LONG POINTER TO WORD ← bitsPtr;
wordsPerLine: NAT ← (fSize+(bitsPerWord-1))/bitsPerWord;
words: INT ← Basics.LongMult[sSize, wordsPerLine];
startOffset: INT ← pdState.currentLoadLocation;
destOffset: INT ← startOffset + SIZE[PDFileFormat.SampleArray];
endOffset: INT ← destOffset + words;
sampleArray: LONG POINTER TO PDFileFormat.SampleArray ← loadDescription.pointer + startOffset;
destBase: LONG POINTER TO WORD ← loadDescription.pointer + destOffset;
IF endOffset > pdState.loadSizeInWords THEN ERROR;
sampleArray.sSize ← sSize;
sampleArray.fSize ← fSize;
LongBlockTransfer[source: source, count: words, dest: destBase];
loadReference ← loadDescription.count;
loadDescription.count ← loadDescription.count + 1;
loadDescription[loadReference] ← [
loadEntryType: samples,
offsetHighBits: Basics.HighHalf[startOffset],
offsetLowBits: Basics.LowHalf[startOffset],
pageOfMostRecentUse: 0,
numberOfPagesUsedIn: 0
];
pdState.currentLoadLocation ← endOffset;
pdState.herald.maxLoadWord ← MAX[pdState.herald.maxLoadWord, endOffset];
DebugLoad[startOffset];
};
LoadContiguousColorTile: PUBLIC PROC [pdState: PDState, phase: CARDINAL, sMin, fMin: CARDINAL, sSize, fSize: CARDINAL, bitsPtr: LONG POINTER] RETURNS [loadReference: LoadReference] = TRUSTED {
loadDescription: LoadDescription ← GetLoadDescription[pdState];
source: LONG POINTER TO WORD ← bitsPtr;
wordsPerLine: NAT ← (fSize+(bitsPerWord-1))/bitsPerWord;
words: INT ← Basics.LongMult[sSize, wordsPerLine];
startOffset: INT ← pdState.currentLoadLocation;
destOffset: INT ← startOffset + SIZE[PDFileFormat.Tile];
endOffset: INT ← destOffset + words;
tile: LONG POINTER TO PDFileFormat.Tile ← loadDescription.pointer + startOffset;
destBase: LONG POINTER TO WORD ← loadDescription.pointer + destOffset;
IF endOffset > pdState.loadSizeInWords THEN ERROR;
tile.phase ← phase;
tile.sMin ← sMin;
tile.fMin ← fMin;
tile.sSize ← sSize;
tile.fSize ← fSize;
LongBlockTransfer[source: source, count: words, dest: destBase];
loadReference ← loadDescription.count;
loadDescription.count ← loadDescription.count + 1;
loadDescription[loadReference] ← [
loadEntryType: tile,
offsetHighBits: Basics.HighHalf[startOffset],
offsetLowBits: Basics.LowHalf[startOffset],
pageOfMostRecentUse: 0,
numberOfPagesUsedIn: 0
];
pdState.currentLoadLocation ← endOffset;
pdState.herald.maxLoadWord ← MAX[pdState.herald.maxLoadWord, endOffset];
DebugLoad[startOffset];
};
EndPage: PUBLIC PROC [pdState: PDState] = {
startBand: NAT ← pdState.sMinPage/pdState.herald.bandSSize;
endBand: NAT ← (pdState.sMaxPage+pdState.herald.bandSSize-1)/pdState.herald.bandSSize;
nBands: NATMAX[0, INTEGER[endBand]-startBand];
fSizePage: CARDINALMAX[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];
IF pdState.toners[t] THEN {
WriteStartImage[
pdState: pdState,
feed: t = pdState.firstToner AND pdState.feed,
strip: t = pdState.lastToner AND pdState.strip,
toner: t,
passBands: startBand,
nBands: nBands,
fMinPage: pdState.fMinPage,
fSizePage: fSizePage
];
WriteBands[pdState, bands, startBand, nBands];
pdState.currentImage ← pdState.currentImage + 1;
};
ENDLOOP;
pdState.sMinPage ← pdState.herald.imageSSize;
pdState.fMinPage ← pdState.herald.imageFSize;
pdState.sMaxPage ← pdState.fMaxPage ← 0;
IF pdState.overflowStream # NIL THEN pdState.overflowStream.SetIndex[0];
StartImage[pdState];
};
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: NATMAX[0, INTEGER[endBand]-startBand];
fSizePage: CARDINALMAX[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;
bands[i].bandBuffer.length ← 0;
bands[i].bandBuffer.overflowIndices ← NIL;
ENDLOOP
ENDLOOP;
IF pdState.overflowStream # NIL THEN {
pdState.overflowStream.SetIndex[0];
};
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];
IO.Close[pdState.stream];
IF pdState.overflowStream # NIL THEN {
pdState.overflowStream.SetIndex[0];
pdState.overflowStream.SetLength[0];
pdState.overflowStream.Close[abort: TRUE];
};
};
ObjectFallsOutsideOfDeclaredPageBounds: ERROR ~ CODE;
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];
IF pdState.sMaxPage > pdState.herald.imageSSize THEN ERROR ObjectFallsOutsideOfDeclaredPageBounds;
IF pdState.fMaxPage > pdState.herald.imageFSize THEN ERROR ObjectFallsOutsideOfDeclaredPageBounds;
};
SelectBandNoColor: PROC [pdState: PDState, sMin: CARDINAL, toner: Toner] = TRUSTED {
bandNum: NAT ← sMin/pdState.herald.bandSSize;
bands: Bands ← pdState.bands[toner];
IF bands[bandNum].bandBuffer = NIL THEN bands[bandNum].bandBuffer ← NEW[BandBufferRec];
pdState.selectedBands ← bands;
pdState.selectedBandNum ← bandNum;
};
SelectBand: PROC [pdState: PDState, sMin: CARDINAL, toner: Toner] = TRUSTED {
colorId: INT ← pdState.colorDescriptor[toner].colorId;
longPriority: Basics.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].bandBuffer = NIL THEN bands[bandNum].bandBuffer ← 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];
};
};
WriteOverflowBand: PROC [pdState: PDState, bandBuffer: BandBuffer] = TRUSTED {
bandDataPtr: LONG POINTER ← @(bandBuffer.word);
IF pdState.overflowStream = NIL THEN {
pdState.overflowStream ← FS.StreamOpen[fileName: "PDTemp$", accessOptions: $create];
Note - this relys on FS to do the right thing when multiple instances of the file writer are around. The version number mechanism should keep us out of trouble.
};
bandBuffer.overflowIndices ← CONS[
IO.GetIndex[pdState.overflowStream],
bandBuffer.overflowIndices
];
pdState.overflowStream.UnsafePutBlock[[base: bandDataPtr, startIndex: 0, count: bandBufferSize*bytesPerWord]];
bandBuffer.length ← 0;
};
EnterBandData: PROC [pdState: PDState, startPtr: LONG POINTER, wordCount: NAT] = TRUSTED {
source: LONG POINTER TO WORD ← startPtr;
bandBuffer: BandBuffer ← pdState.selectedBands[pdState.selectedBandNum].bandBuffer;
WHILE wordCount > 0 DO
IF wordCount <= bandBufferSize - bandBuffer.length THEN {
BlockTransfer[source: startPtr, count: wordCount, dest: @(bandBuffer.word[bandBuffer.length])];
startPtr ← startPtr + wordCount;
bandBuffer.length ← bandBuffer.length + wordCount;
wordCount ← 0;
}
ELSE {
count: NAT ← bandBufferSize - bandBuffer.length;
bufPtr: LONG POINTER ← @(bandBuffer.word);
BlockTransfer[source: startPtr, count: count, dest: bufPtr+bandBuffer.length];
startPtr ← startPtr + count;
bandBuffer.length ← bandBuffer.length + count;
wordCount ← wordCount - count;
WriteOverflowBand[pdState, bandBuffer];
};
ENDLOOP;
};
WriteLoadAdditions: PROC [pdState: PDState] = TRUSTED {
Writes out any additions to the font load
WHILE pdState.loadWrittenLength < pdState.currentLoadLocation DO
loadDescription: LoadDescription ← GetLoadDescription[pdState];
lengthOfAdditions: INT ← pdState.currentLoadLocation-pdState.loadWrittenLength;
lengthOfChunk: INTMIN[lengthOfAdditions, 8*1024];
unsafeBlock: IO.UnsafeBlock = [base: loadDescription.pointer+pdState.loadWrittenLength, startIndex: 0, count: 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 {
base: LONG POINTER ~ @lc;
pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: SIZE[LONG CARDINAL]*bytesPerWord]];
};
WriteCardinal: PROC [pdState: PDState, c: CARDINAL] = TRUSTED {
base: LONG POINTER ~ @c;
pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: SIZE[CARDINAL]*bytesPerWord]];
};
WriteHerald: PROC [pdState: PDState] = TRUSTED {
base: LONG POINTER ~ @pdState.herald;
pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: SIZE[PDFileFormat.Herald]*bytesPerWord]];
};
WriteControlCommand: PROC [pdState: PDState, controlCom: PDFileFormat.ControlCom] = TRUSTED {
command: PDFileFormat.Command ← [control[controlCom]];
base: LONG POINTER ~ @command;
pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: SIZE[PDFileFormat.Command]*bytesPerWord]];
};
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]
];
base: LONG POINTER ~ @startImageBuf;
pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: SIZE[StartImageBuf]*bytesPerWord]];
};
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
bandBuffer: BandBuffer ← bands[bandNum].bandBuffer;
IF bandBuffer # NIL THEN {
overflowIndices: LIST OF INTNIL;
Reverse the list of overflow indices.
WHILE bandBuffer.overflowIndices # NIL DO
t: LIST OF INT ← bandBuffer.overflowIndices;
bandBuffer.overflowIndices ← bandBuffer.overflowIndices.rest;
t.rest ← overflowIndices;
overflowIndices ← t;
ENDLOOP;
WHILE overflowIndices # NIL DO
overflowBuf: ARRAY [0..bandBufferSize) OF CARDINAL;
base: LONG POINTER ~ @overflowBuf;
pdState.overflowStream.SetIndex[overflowIndices.first];
IF bandBufferSize*bytesPerWord #
pdState.overflowStream.UnsafeGetBlock[[
base: base,
startIndex: 0,
count: bandBufferSize*bytesPerWord
]]
THEN ERROR;
pdState.stream.UnsafePutBlock[[base: base, startIndex: 0, count: bandBufferSize*bytesPerWord]];
{t: LIST OF INT ← overflowIndices; overflowIndices ← t.rest; t.rest ← NIL};
ENDLOOP;
pdState.stream.UnsafePutBlock[[base: LOOPHOLE[@(bandBuffer.word)], startIndex: 0, count: bandBuffer.length*bytesPerWord]];
bandBuffer.length ← 0;
};
WriteControlCommand[pdState, endBand];
bands[bandNum].colorId ← 0;
ENDLOOP;
};
END.