PDFileWriterImpl:
CEDAR
PROGRAM
IMPORTS Basics, CountedVM, FS, IO, PrincOpsUtils
EXPORTS PDFileWriter
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 INT ← NIL,
word: ARRAY [0..bandBufferSize) OF WORD
];
ColorDescriptor:
TYPE =
MACHINE
DEPENDENT
RECORD [
colorId: INT ← 0, -- bumped whenever the color changes.
enabled: BOOLEAN ← TRUE,
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: BOOLEAN ← TRUE,
strip: BOOLEAN ← TRUE,
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.STREAM ← NIL
];
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.loadSizeInWords ← maxLoadWords;
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:
BOOLEAN ←
TRUE] ~ {
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: 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
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: 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
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: CARDINAL ← IF 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: 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 {
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: CARDINAL ← IF 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: 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;
};
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: INT ← LAST[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: 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 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: 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];
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: 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;
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: INT ← MIN[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 INT ← NIL;
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.