CIIImpl.mesa
Copyright Ó 1990, 1993 by Xerox Corporation. All rights reserved.
Michael Plass, June 29, 1994 9:02 am PDT
Russ Atkinson (RRA) October 22, 1993 2:30 pm PDT
DIRECTORY
Commander, CommanderOps, NotReallyAViewer,
Atom,
Basics,
CII USING [ApplyCCITTFacsimileDecompressionFilterProc, CIIEndType, CIIJointType, CleanupObject, ColorLookupTableType, ConicToProc, CProc, CurveToProc, DestroyClipperProc, DestroyColorOperatorProc, DestroyColorProc, DestroyFontProc, DestroyHalftonePropertiesProc, DestroyLookupTableProc, DestroyMaskProgramProc, DestroyProc, FillType, GeneratePathProc, GetColorLookupTableProc, HalftonePropertiesForSeparation, Handle, ImageSource, ImageSourceDestroyProc, ImageSourceObjectRep, ImageSourceReadProc, LineRunsRep, LineToProc, MakeLookupTableProc, MaskInfo, MoveToProc, ObjectRep, PathGenerator, PathSinkObjectRep, RasterRep, RegisterCleanupObjectProc, RES, RESFromErrorCode, RunRep, SampleRange, ScaledValue, SetColorLookupTableProc, SetColorTableProc, SetOutputBuffersProc, SetSeparationProc, ShowArgs, StrokeControlRep, SyncProc, VectorEndpoints, XChar, XChars],
CStrings,
CIIPrivate,
Imager,
ImagerError,
ImagerBox USING [Rectangle],
ImagerBrick,
ImagerClipper,
ImagerColor,
ImagerDevice,
ImagerDeviceColor,
ImagerDeviceInterchange,
ImagerDeviceVector,
ImagerDeviceWorks,
ImagerFont,
ImagerFontWorks,
ImagerImageWorks,
ImagerManhattan,
ImagerMaskCache,
ImagerPath,
ImagerPen,
ImagerPenExtras,
ImagerPixel,
ImagerPixelArray,
ImagerRaster,
ImagerSample,
ImagerScaled,
ImagerTransformation,
IO,
IOUtils,
PixelArrayCCITTG4Private,
RefTab,
RefText,
Rope,
RuntimeError,
Scaled,
SF,
UXStrings,
Vector2;
CIIImpl: MONITOR
IMPORTS Atom, Basics, CII, CStrings, Imager, ImagerColor, ImagerDevice, ImagerDeviceColor, ImagerDeviceInterchange, ImagerDeviceWorks, ImagerError, ImagerFont, ImagerFontWorks, ImagerImageWorks, ImagerManhattan, ImagerPath, ImagerPenExtras, ImagerPixel, ImagerPixelArray, ImagerRaster, ImagerSample, ImagerScaled, ImagerTransformation, IO, IOUtils, PixelArrayCCITTG4Private, RefTab, RefText, Rope, RuntimeError, Scaled, UXStrings, Vector2
EXPORTS CIIPrivate, CII
SHARES ImagerSample
~ BEGIN OPEN CII;
ROPE: TYPE ~ Rope.ROPE;
STREAM: TYPE ~ IO.STREAM;
Color: TYPE = ImagerColor.Color;
ColorRep: PUBLIC TYPE = ImagerColor.ColorRep;
ConstantColor: TYPE = ImagerColor.ConstantColor;
ColorOperator: TYPE = ImagerColor.ColorOperator;
ColorOperatorRep: PUBLIC TYPE = ImagerColor.ColorOperatorRep;
Device: TYPE = ImagerDevice.Device;
Rectangle: TYPE = ImagerBox.Rectangle;
DeviceClipper: TYPE = ImagerDevice.DeviceClipper;
Transformation: TYPE = ImagerTransformation.Transformation;
VEC: TYPE = Vector2.VEC;
FontRep: PUBLIC TYPE = ImagerFont.FontRep;
ok: RES = CII.RESFromErrorCode[$ok];
eof: RES = CII.RESFromErrorCode[$eof];
nilFault: RES = CII.RESFromErrorCode[$nilFault];
ioError: RES = CII.RESFromErrorCode[$ioError];
wrongType: RES = CII.RESFromErrorCode[$wrongType];
bounds: RES = CII.RESFromErrorCode[$bounds];
accessError: RES = CII.RESFromErrorCode[$accessError];
notImplemented: RES = CII.RESFromErrorCode[$notImplemented];
scanModeTranslate: ARRAY CIIPrivate.ScanMode OF ImagerTransformation.ScanMode ~ [
slowRightFastUp: [slow: right, fast: up],
slowDownFastRight: [slow: down, fast: right],
slowLeftFastDown: [slow: left, fast: down],
slowUpFastLeft: [slow: up, fast: left],
slowRightFastDown: [slow: right, fast: down],
slowDownFastLeft: [slow: down, fast: left],
slowLeftFastUp: [slow: left, fast: up],
slowUpFastRight: [slow: up, fast: right]
];
ScanModeTranslate: PUBLIC SAFE PROC [scanMode: CIIPrivate.ScanMode] RETURNS [ImagerTransformation.ScanMode] ~ CHECKED {
RETURN [scanModeTranslate[scanMode]]
};
CProcFromProc: PROC [p: PROC ANY RETURNS ANY] RETURNS [CProc] = INLINE {
Depends on Mimosa's PROC encoding.
r: POINTER TO ARRAY [0..1] OF CARD = LOOPHOLE[p];
IF r[1] # 0 THEN ERROR;
RETURN [[r[0]]]
};
GetState: PROC [h: Handle] RETURNS [State] = {
RETURN [NARROW[h.data]]
};
NoteRef: PROC [state: State, ref: REF] = {
Inner: RefTab.UpdateAction = CHECKED {
IF found
THEN {
WITH val SELECT FROM r: REF NAT => r­ ¬ r­ + 1 ENDCASE => ERROR;
RETURN [op: none]
}
ELSE {
RETURN [op: store, new: NEW[NAT ¬ 1]]
};
};
IF ref # NIL THEN RefTab.Update[state.refTab, ref, Inner];
};
DestroyAny: PROC [h: Handle, ref: REF] RETURNS [res: RES ¬ ok] = {
state: State = GetState[h];
Inner: RefTab.UpdateAction = CHECKED {
IF found
THEN {
WITH val SELECT FROM
r: REF NAT => {IF (r­ ¬ r­ - 1) = 0 THEN RETURN [op: delete]};
ENDCASE => ERROR;
RETURN [op: none]
}
ELSE {
res ¬ accessError;
RETURN [op: none]
};
};
IF state = NIL THEN RETURN [nilFault];
IF ref # NIL THEN RefTab.Update[state.refTab, ref, Inner];
};
Matrix: TYPE ~ ARRAY [0..6) OF REAL;
MakeTransformation: PROC [m: POINTER TO Matrix] RETURNS [Transformation] ~ {
RETURN [ImagerTransformation.Create[m[0], m[2], m[4], m[1], m[3], m[5]]]
};
SetTransformation: PROC [state: State, t: Transformation] ~ {
IF t = NIL THEN t ¬ identity;
state.transformation­ ¬ t­;
};
DecodeTransformation: PROC [t: Transformation, m: POINTER TO Matrix] ~ {
m[0] ¬ t.a; m[1] ¬ t.d;
m[2] ¬ t.b; m[3] ¬ t.e;
m[4] ¬ t.c; m[5] ¬ t.f;
};
GetMatrix: PUBLIC PROC [h: Handle, matrixResult: POINTER TO Matrix] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
IF matrixResult = NIL THEN RETURN [nilFault];
DecodeTransformation[state.transformation, matrixResult];
};
SetMatrix: PUBLIC PROC [h: Handle, matrix: POINTER TO Matrix] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
IF matrix = NIL
THEN { RETURN [nilFault] }
ELSE {
temp: Transformation ~ MakeTransformation[matrix];
SetTransformation[state, temp];
ImagerTransformation.Destroy[temp];
};
};
InitialTransformation: PROC [device: Device] RETURNS [Transformation] ~ {
m: Transformation = ImagerTransformation.XYToSF[device.parm.scanMode, device.parm.sSize, device.parm.fSize];
ImagerTransformation.ApplyPreScale2[m, Vector2.Div[device.parm.surfaceUnitsPerInch, 72.0]];
RETURN [m]
};
SetInitialMatrix: PUBLIC PROC [h: Handle, matrix: POINTER TO Matrix] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
state.initialTransformation ¬ MakeTransformation[matrix];
};
GetInitialMatrix: PUBLIC PROC [h: Handle, matrixResult: POINTER TO Matrix] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
IF state.initialTransformation = NIL THEN {
state.initialTransformation ¬ InitialTransformation[state.device];
};
DecodeTransformation[state.initialTransformation, matrixResult];
};
identity: Transformation ~ ImagerTransformation.Scale[1.0];
SetGray: PUBLIC PROC [h: Handle, gray: POINTER TO REAL] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
state.color ¬ ImagerColor.ColorFromGray[1.0-(gray­)];
};
SetRGB: PUBLIC PROC [h: Handle, rgb: POINTER TO ARRAY [0..3) OF REAL] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
state.color ¬ ImagerColor.ColorFromRGB[[rgb[0], rgb[1], rgb[2]]];
};
SetHSV: PUBLIC PROC [h: Handle, hsv: POINTER TO ARRAY [0..3) OF REAL] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
state.color ¬ ImagerColor.ColorFromHSV[hsv[0], hsv[1], hsv[2]];
};
SetCMYK: PUBLIC PROC [h: Handle, cmyk: POINTER TO ARRAY [0..4) OF REAL] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
state.color ¬ ImagerColor.ColorFromCMYK[[cmyk[0], cmyk[1], cmyk[2], cmyk[3]]];
};
MakeGrayColorOperator: PUBLIC PROC [h: Handle, sampleRange: POINTER TO SampleRange, sampleTableSize: CARD, sampleTable: POINTER TO ARRAY [0..0) OF REAL, colorOperatorResult: POINTER TO ColorOperator] RETURNS [res: RES¬ok] = {
ENABLE {
ImagerError.Error => { res ¬ CII.RESFromErrorCode[error.code]; CONTINUE };
RuntimeError.BoundsFault => { res ¬ bounds; CONTINUE };
RuntimeError.NilFault => { res ¬ nilFault; CONTINUE };
};
state: State = GetState[h];
SampleTable: SAFE PROC [i: NAT] RETURNS [REAL] = TRUSTED {
IF sampleTable = NIL THEN ERROR RuntimeError.NilFault;
RETURN [sampleTable[Basics.BoundsCheck[i, sampleTableSize]]]
};
co: ColorOperator = ImagerColor.NewColorOperatorGrayLinear[sWhite: sampleRange.sWhite, sBlack: sampleRange.sBlack, sampleTableSize: sampleTableSize, sampleTableProc: SampleTable];
NoteRef[state, colorOperatorResult­ ¬ co];
};
MakeSampleEncoding: PROC [sampleTableSize: NAT, sampleTable: POINTER TO ARRAY [0..0) OF REAL] RETURNS [s: ImagerColor.SampleEncoding] = {
s ¬ NEW[ImagerColor.SampleEncodingRep[sampleTableSize]];
FOR i: NAT IN [0..sampleTableSize) DO
s[i] ¬ sampleTable[i];
ENDLOOP;
};
MakeRGBColorOperator: PUBLIC PROC [h: Handle, sampleRange: POINTER TO SampleRange, sampleTableSize: CARD, sampleTableR: POINTER TO ARRAY [0..0) OF REAL, sampleTableG: POINTER TO ARRAY [0..0) OF REAL, sampleTableB: POINTER TO ARRAY [0..0) OF REAL, colorOperatorResult: POINTER TO ColorOperator] RETURNS [res: RES¬ok] ~ {
ENABLE {
ImagerError.Error => { res ¬ CII.RESFromErrorCode[error.code]; CONTINUE };
RuntimeError.BoundsFault => { res ¬ bounds; CONTINUE };
RuntimeError.NilFault => { res ¬ nilFault; CONTINUE };
};
state: State = GetState[h];
pixelEncoding: ImagerColor.PixelEncoding ¬ NIL;
co: ColorOperator ¬ NIL;
IF sampleTableSize # 0 THEN {
pixelEncoding ¬ NEW[ImagerColor.PixelEncodingRep[3]];
pixelEncoding[0] ¬ MakeSampleEncoding[sampleTableSize, sampleTableR];
pixelEncoding[1] ¬ MakeSampleEncoding[sampleTableSize, sampleTableG];
pixelEncoding[2] ¬ MakeSampleEncoding[sampleTableSize, sampleTableB];
};
co ¬ ImagerColor.NewColorOperatorRGB[sWhite: sampleRange.sWhite, sBlack: sampleRange.sBlack, map: pixelEncoding, appearanceHints: NIL];
NoteRef[state, colorOperatorResult­ ¬ co];
};
cmykSignalNames: ARRAY[0..4) OF ImagerColor.ConstantColor = [
ImagerColor.Find["Xerox/Solid/Cyan"],
ImagerColor.Find["Xerox/Solid/Magenta"],
ImagerColor.Find["Xerox/Solid/Yellow"],
ImagerColor.Find["Xerox/Solid/Black"]
];
CMYKSignalNames: SAFE PROC [signal: NAT] RETURNS [ConstantColor] ~ CHECKED {
RETURN [cmykSignalNames[signal]];
};
MakeCMYKColorOperator: PUBLIC PROC [h: Handle, sampleRange: POINTER TO SampleRange, sampleTableSize: CARD, sampleTableC: POINTER TO ARRAY [0..0) OF REAL, sampleTableM: POINTER TO ARRAY [0..0) OF REAL, sampleTableY: POINTER TO ARRAY [0..0) OF REAL, sampleTableK: POINTER TO ARRAY [0..0) OF REAL, colorOperatorResult: POINTER TO ColorOperator] RETURNS [res: RES¬ok] = {
ENABLE {
ImagerError.Error => { res ¬ CII.RESFromErrorCode[error.code]; CONTINUE };
RuntimeError.BoundsFault => { res ¬ bounds; CONTINUE };
RuntimeError.NilFault => { res ¬ nilFault; CONTINUE };
};
state: State = GetState[h];
pixelEncoding: ImagerColor.PixelEncoding ¬ NIL;
co: ColorOperator ¬ NIL;
IF sampleTableSize # 0 THEN {
pixelEncoding ¬ NEW[ImagerColor.PixelEncodingRep[4]];
pixelEncoding[0] ¬ MakeSampleEncoding[sampleTableSize, sampleTableC];
pixelEncoding[1] ¬ MakeSampleEncoding[sampleTableSize, sampleTableM];
pixelEncoding[2] ¬ MakeSampleEncoding[sampleTableSize, sampleTableY];
pixelEncoding[3] ¬ MakeSampleEncoding[sampleTableSize, sampleTableK];
};
co ¬ ImagerColor.NewColorOperatorProcess[su: sampleRange.sWhite, sz: sampleRange.sBlack, signals: 4, map: pixelEncoding, signalType: $reflectance, signalNames: CMYKSignalNames];
NoteRef[state, colorOperatorResult­ ¬ co];
};
MakeHighlightColorOperator: PUBLIC PROC [h: Handle, sampleRange: POINTER TO SampleRange, baseColor: Color, highlightColor: Color, sampleTableSize: CARD, sampleTableBaseColor: POINTER TO ARRAY [0..0) OF REAL, sampleTableHighlightColor: POINTER TO ARRAY [0..0) OF REAL, colorOperatorResult: POINTER TO ColorOperator] RETURNS [res: RES¬ok] = {
ENABLE {
ImagerError.Error => { res ¬ CII.RESFromErrorCode[error.code]; CONTINUE };
RuntimeError.BoundsFault => { res ¬ bounds; CONTINUE };
RuntimeError.NilFault => { res ¬ nilFault; CONTINUE };
};
state: State = GetState[h];
pixelEncoding: ImagerColor.PixelEncoding ¬ NIL;
co: ColorOperator ¬ NIL;
IF sampleTableSize # 0 THEN {
pixelEncoding ¬ NEW[ImagerColor.PixelEncodingRep[2]];
pixelEncoding[0] ¬ MakeSampleEncoding[sampleTableSize, sampleTableBaseColor];
pixelEncoding[1] ¬ MakeSampleEncoding[sampleTableSize, sampleTableHighlightColor];
};
co ¬ ImagerColor.NewColorOperatorHighlight[
sWhite: sampleRange.sWhite,
sBlack: sampleRange.sBlack,
map: pixelEncoding,
baseColor: ImagerColor.NarrowToOpConstantColor[NARROW[baseColor]],
highlightColor: ImagerColor.NarrowToOpConstantColor[NARROW[highlightColor]],
appearanceHints: NIL
];
NoteRef[state, colorOperatorResult­ ¬ co];
};
MakeColor: PUBLIC PROC [h: Handle, colorOperator: ColorOperator, samplesPerPixel: CARD, pixel: POINTER TO ARRAY [0..0) OF REAL, colorResult: POINTER TO Color] RETURNS [res: RES¬ok] = {
ENABLE {
ImagerError.Error => { res ¬ CII.RESFromErrorCode[error.code]; CONTINUE };
RuntimeError.BoundsFault => { res ¬ bounds; CONTINUE };
RuntimeError.NilFault => { res ¬ nilFault; CONTINUE };
};
Pixel: SAFE PROC [sampleIndex: NAT] RETURNS [REAL] = TRUSTED {
RETURN [pixel[Basics.BoundsCheck[sampleIndex, samplesPerPixel]]]
};
state: State = GetState[h];
co: REF ¬ colorOperator;
color: Color ¬ ImagerColor.ColorFromPixel[NARROW[co], Pixel];
NoteRef[state, colorResult­ ¬ color];
};
MakeSampledBlack: PUBLIC PROC [h: Handle, bitmap: POINTER TO RasterRep, pixelToDevice: POINTER TO Matrix, clear: BOOL, colorResult: POINTER TO Color] RETURNS [res: RES¬ok] = {
ENABLE {
ImagerError.Error => { res ¬ CII.RESFromErrorCode[error.code]; CONTINUE };
RuntimeError.BoundsFault => { res ¬ bounds; CONTINUE };
RuntimeError.NilFault => { res ¬ nilFault; CONTINUE };
};
state: State = GetState[h];
sm: ImagerSample.RasterSampleMap = MakeSampleMap[bitmap, ObtainDesc[state]];
pm: ImagerPixel.PixelMap = ImagerPixel.MakePixelMap[ImagerSample.Copy[sm]];
pa: ImagerPixelArray.PixelArray = ImagerPixelArray.FromPixelMap[
pixelMap: pm,
box: pm.box,
scanMode: [slow: right, fast: up],
immutable: TRUE
];
color: Color = ImagerColor.MakeSampledBlack[
pa: pa,
um: MakeTransformation[pixelToDevice],
clear: clear
];
ReleaseDesc[state, sm];
NoteRef[state, colorResult­ ¬ color];
};
GetColor: PUBLIC PROC [h: Handle, colorResult: POINTER TO Color] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
NoteRef[state, colorResult­ ¬ state.color];
};
SetColor: PUBLIC PROC [h: Handle, color: REF] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
WITH color SELECT FROM
color: Color => state.color ¬ color;
ENDCASE => RETURN [wrongType];
};
State: TYPE ~ REF StateRep;
StateRep: TYPE ~ CIIPrivate.StateRep;
StateRep: TYPE ~ RECORD [
refTab: RefTab.Ref, -- Things passed out to clients & not destroyed, w/ ref counts
device: ImagerDevice.Device,
initialTransformation: ImagerTransformation.Transformation, -- for GetInitialMatrix
savedDevice: ImagerDevice.Device ¬ NIL, -- For use during BuildClipper scope
color: ImagerColor.Color, -- color that has been set by the client
dcolor: ImagerColor.Color, -- color that has been pushed into the device
transformation: ImagerTransformation.Transformation, -- client to device
viewClipper: ImagerDevice.DeviceClipper,
clientClipper: ImagerClipper.Clipper,
halftoneProperties: REF HalftonePropertiesRep, -- set by the client
dhalftoneProperties: REF HalftonePropertiesRep, -- pushed into the device
cp: ImagerDeviceVector.DVec,
scratchDesc: ImagerSample.RasterSampleMap,
cleanups: LIST OF CII.CleanupObject
];
Validate: PROC [state: State] ~ {
IF state.savedDevice # NIL THEN RETURN; -- ignore color changes during capture.
IF state.dcolor # state.color THEN {
device: Device ~ state.device;
WITH state.color SELECT FROM
color: Color => {
device.class.SetColor[device, color, identity];
state.dcolor ¬ color;
};
ENDCASE => ERROR;
};
};
MaskDeviceTrapezoid: PUBLIC PROC [h: Handle, sMin, fMin, sMax, fMax: INT, f0, df0, f1, df1: ScaledValue] RETURNS [RES¬ok] = {
state: State = GetState[h];
device: Device ~ state.device;
Validate[state];
IF FALSE AND device.state.allow.regionFill
THEN {
ERROR; -- Should implement this.
}
ELSE {
Boxes: SAFE PROC [boxAction: SF.BoxAction] = CHECKED {
s: INT ¬ sMin;
halfMinusEps: ImagerScaled.Value = [pair[hi: 0, lo: (LAST[CARD16]/2)]];
fA: ImagerScaled.Value ¬ ImagerScaled.PLUS[f0, halfMinusEps];
fB: ImagerScaled.Value ¬ ImagerScaled.PLUS[f1, halfMinusEps];
WHILE s < sMax DO
f0: INTEGER ¬ ImagerScaled.Floor[fA];
f1: INTEGER ¬ ImagerScaled.Floor[fB];
IF f0 > f1 THEN {t: INTEGER ¬ f0; f0 ¬ f1; f1 ¬ t};
IF f0 < fMin THEN f0 ¬ fMin;
IF f1 > fMax THEN f1 ¬ fMax;
IF f0 < f1 THEN { boxAction[[[s, f0], [s+1, f1]]] };
s ¬ s + 1;
fA ¬ Scaled.PLUS[fA, df0];
fB ¬ Scaled.PLUS[fB, df1];
ENDLOOP;
};
device.class.MaskBoxes[device, [[sMin, fMin], [sMax, fMax]], Boxes]
};
};
MaskRuns: PUBLIC PROC [h: Handle, sMin: INT, numOfLines: CARD, lineRuns: POINTER TO ARRAY [0..0) OF LineRunsRep] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
bounds: SF.Box ¬ [min: SF.maxVec, max: SF.minVec];
Bound: SAFE PROC [box: SF.Box] = CHECKED {
IF box.min.s < bounds.min.s THEN bounds.min.s ¬ box.min.s;
IF box.min.f < bounds.min.f THEN bounds.min.f ¬ box.min.f;
IF box.max.s > bounds.max.s THEN bounds.max.s ¬ box.max.s;
IF box.max.f > bounds.max.f THEN bounds.max.f ¬ box.max.f;
};
Boxes: SF.BoxGenerator = TRUSTED {
FOR i: NAT IN [0..numOfLines) DO
lr: LineRunsRep = lineRuns[i];
FOR j: NAT IN [0..lr.numOfRuns) DO
r: POINTER TO RunRep = @(lr.run[j]);
fMin: INT = r.fMin;
boxAction[[[sMin+i, fMin], [sMin+i+1, fMin+r.fSize]]];
ENDLOOP;
ENDLOOP;
};
Boxes[Bound];
IF bounds.min.s < bounds.max.s THEN {
Validate[state];
state.device.class.MaskBoxes[state.device, bounds, Boxes];
};
};
PathOps: TYPE ~ RECORD [
moveTo: ImagerPath.MoveToProc,
lineTo: ImagerPath.LineToProc,
curveTo: ImagerPath.CurveToProc,
conicTo: ImagerPath.ConicToProc
];
MoveTo: CII.MoveToProc ~ {
pathOps: POINTER TO PathOps = LOOPHOLE[sink.data];
pathOps.moveTo[p­];
RETURN [ok]
};
LineTo: CII.LineToProc ~ {
pathOps: POINTER TO PathOps = LOOPHOLE[sink.data];
pathOps.lineTo[p­];
RETURN [ok]
};
CurveTo: CII.CurveToProc ~ {
pathOps: POINTER TO PathOps = LOOPHOLE[sink.data];
pathOps.curveTo[p[0], p[1], p[2]];
RETURN [ok]
};
ConicTo: CII.ConicToProc ~ {
pathOps: POINTER TO PathOps = LOOPHOLE[sink.data];
pathOps.conicTo[c.p1, c.p2, c.s];
RETURN [ok]
};
InvokePath: PROC [pathGenerator: PathGenerator, opsP: POINTER TO PathOps] RETURNS [RES] = {
procRep: RECORD [cproc: CProc, link: CARD] ¬ [pathGenerator.proc, 0];
generatePath: CII.GeneratePathProc ¬ LOOPHOLE[@procRep];
pathSinkObjectRep: PathSinkObjectRep ¬ [
data: opsP,
moveTo: CProcFromProc[MoveTo],
lineTo: CProcFromProc[LineTo],
curveTo: CProcFromProc[CurveTo],
conicTo: CProcFromProc[ConicTo]
];
RETURN [generatePath[pathGenerator, @pathSinkObjectRep]];
};
Clip: PUBLIC PROC [h: Handle, pathGenerator: PathGenerator, fillType: FillType] RETURNS [res: RES¬ok] ~ {
state: State = GetState[h];
Path: ImagerPath.PathProc ~ TRUSTED {
ops: PathOps ¬ [moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, conicTo: conicTo];
res ¬ InvokePath[pathGenerator: pathGenerator, opsP: @ops];
};
outline: ImagerPath.Outline ~ ImagerPath.OutlineFromPath[path: Path, m: state.transformation];
newClipper: ImagerClipper.Clipper ~ CONS[
[outline: outline, oddWrap: fillType=eo, exclude: FALSE],
state.clientClipper
];
RETURN SetClipper[h, newClipper];
};
GetClipper: PUBLIC PROC [h: Handle, clipperResult: POINTER TO ImagerClipper.Clipper] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
NoteRef[state, clipperResult­ ¬ state.clientClipper];
};
SetClipper: PUBLIC PROC [h: Handle, clipper: ImagerClipper.Clipper] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
state.clientClipper ¬ clipper;
ValidateClipper[state];
};
ValidateClipper: PUBLIC PROC [state: State] = {
NOTE: We could defer this work until masking time, if that seems important.
ImagerDeviceWorks.Clip[device: state.device, viewClipper: state.viewClipper, clipperToDevice: identity, clientClipper: state.clientClipper];
};
MaskFill: PUBLIC PROC [h: Handle, pathGenerator: PathGenerator, fillType: FillType] RETURNS [res: RES¬ok] ~ {
state: State = GetState[h];
Path: ImagerPath.PathProc ~ TRUSTED {
ops: PathOps ¬ [moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, conicTo: conicTo];
res ¬ InvokePath[pathGenerator: pathGenerator, opsP: @ops];
};
Validate[state];
ImagerDeviceWorks.MaskFill[device: state.device, path: Path, oddWrap: fillType=eo, pathToDevice: state.transformation];
};
MaskRectangle: PUBLIC PROC [h: Handle, rect: POINTER TO Rectangle] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
Validate[state];
ImagerDeviceWorks.MaskRectangle[state.device, rect­, state.transformation];
};
CIIEndType: TYPE = MACHINE DEPENDENT {squareEnd, buttEnd, roundEnd, triangularEnd};
CIIJointType: TYPE = MACHINE DEPENDENT {miterJoint, bevelJoint, roundJoint, triangularJoint, noJoint, miterclipJoint, miterbevelJoint};
MaskStroke: PUBLIC PROC [h: Handle, pathGenerator: PathGenerator, s: POINTER TO StrokeControlRep] RETURNS [res: RES¬ok] ~ {
IF s.stamp # 6218 THEN RETURN [wrongType] ELSE {
ENABLE ImagerError.Error => { res ¬ RESFromErrorCode[error.code]; CONTINUE };
state: State = GetState[h];
Path: ImagerPath.PathProc ~ TRUSTED {
ops: PathOps ¬ [moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, conicTo: conicTo];
res ¬ InvokePath[pathGenerator: pathGenerator, opsP: @ops];
};
pen: ImagerPen.Pen ~ ImagerPenExtras.MakeThickenedTransformedCircle[s.strokeWidth, state.transformation, s.thickening, s.minThickness];
Validate[state];
FIXTHIS - should do a table to translate end & joint types.
IF s.dashCount = 0
THEN {
ImagerDeviceWorks.MaskStroke[device: state.device, path: Path, closed: s.closed, pathToDevice: state.transformation, end: ORD[s.end], joint: ORD[s.joint], miterLimit: s.miterLimit, pen: pen];
}
ELSE {
Pattern: SAFE PROC [i: NAT] RETURNS [REAL] = TRUSTED { RETURN [s.dashArray[i]] };
ImagerDeviceWorks.MaskDashedStroke[device: state.device, path: Path, patternLen: s.dashCount, pattern: Pattern, offset: s.dashOffset, length: s.dashCorrectLength, closed: s.closed, pathToDevice: state.transformation, end: ORD[s.end], joint: ORD[s.joint], miterLimit: s.miterLimit, pen: pen];
};
};
};
MaskVector: PUBLIC PROC [h: Handle, endpoints: POINTER TO VectorEndpoints, s: POINTER TO StrokeControlRep] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
pen: ImagerPen.Pen ~ ImagerPenExtras.MakeThickenedTransformedCircle[s.strokeWidth, state.transformation, s.thickening];
Validate[state];
ImagerDeviceWorks.MaskVector[device: state.device, p1: endpoints.p1, p2: endpoints.p2, pointsToDevice: state.transformation, end: ORD[s.end], pen: pen];
};
PixelMapFromRasters: PUBLIC PROC [samplesPerPixel: CARD, buffers: POINTER TO ARRAY[0..0) OF POINTER TO RasterRep] RETURNS [ImagerPixel.PixelMap] ~ {
a: ARRAY [0..5) OF ImagerSample.RasterSampleMap ¬ ALL[NIL];
IF samplesPerPixel > LENGTH[a] THEN ImagerError.Error[[$notImplemented, "not implemented: too many samples per pixel"]];
FOR i: CARD IN [0..samplesPerPixel) DO
a[i] ¬ MakeSampleMap[buffers[i]];
ENDLOOP;
RETURN [ImagerPixel.MakePixelMap[a[0], a[1], a[2], a[3], a[4]]]
};
MakeSampleMap: PUBLIC PROC [raster: POINTER TO RasterRep, scratch: ImagerSample.RasterSampleMap ¬ NIL] RETURNS [ImagerSample.RasterSampleMap] ~ {
words: NAT = (raster.bitsPerLine * (raster.sMaxBox-raster.sMinBox) + raster.bitIndex + BITS[WORD] -1) / BITS[WORD]; -- ImagerSample.WordsForMap won't do, because it cannot take raster.bitIndex into account.
RETURN [
ImagerSample.UnsafeNewSampleMap[
box: [[raster.sMinBox, raster.fMinBox], [raster.sMaxBox, raster.fMaxBox]],
bitsPerSample: raster.bitsPerSample,
bitsPerLine: raster.bitsPerLine,
base: [word: raster.basePointer, bit: raster.bitIndex],
ref: LOOPHOLE[raster.ref],
words: words,
scratchDescriptor: scratch
]
];
};
ObtainDesc: PROC [state: State] RETURNS [ImagerSample.RasterSampleMap] = INLINE {
desc: ImagerSample.RasterSampleMap ¬ state.scratchDesc;
state.scratchDesc ¬ NIL;
RETURN [desc]
};
ReleaseDesc: PROC [state: State, desc: ImagerSample.RasterSampleMap] = INLINE {
desc.base.word ¬ NIL;
desc.ref ¬ NIL;
state.scratchDesc ¬ desc;
};
MaskBitmap: PUBLIC PROC [h: Handle, raster: POINTER TO RasterRep, background: Color] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
bitmap: ImagerSample.RasterSampleMap = MakeSampleMap[raster, ObtainDesc[state]];
InternalMaskBitmap[state, bitmap, background];
ReleaseDesc[state, bitmap];
};
InternalMaskBitmap: PROC [state: State, bitmap: ImagerSample.RasterSampleMap, background: Color] = {
IF background # NIL THEN {
temp: ImagerSample.RasterSampleMap = ImagerSample.ObtainScratchMap[box: ImagerSample.GetBox[bitmap]];
foreground: Color = state.color;
ImagerSample.Transfer[dst: temp, src: bitmap, function: [null, complement]];
state.color ¬ background;
Validate[state];
ImagerDeviceWorks.MaskBitmap[device: state.device, bitmap: temp, bitsToDevice: state.transformation];
state.color ¬ foreground;
ImagerSample.ReleaseScratchMap[temp];
};
Validate[state];
ImagerDeviceWorks.MaskBitmap[device: state.device, bitmap: bitmap, bitsToDevice: state.transformation];
};
MaskProgram: TYPE = REF TEXT;
MaskProgramRep: PUBLIC TYPE = TEXT;
BadMaskProgram: ERROR;
Op: TYPE = MACHINE DEPENDENT {loop, jz, emit, load0, load1, load2, load3, load4, load5, load6, load7, load8, load9, store0, store1, store2, store3, store4, store5, store6, store7, store8, store9, add0, add1, add2, add3, add4, add5, add6, add7, add8, add9, sub0, sub1, sub2, sub3, sub4, sub5, sub6, sub7, sub8, sub9, shift0, shift1, shift2, shift3, shift4, shift5, shift6, shift7, shift8, shift9, not, int1, int2, int4, word1, word2, word4, clear, octal0, octal1, octal2, octal3, octal4, octal5, octal6, octal7};
MakeMaskProgram: PUBLIC PROC [h: Handle, codeVersion: INT, bigEndian: BOOL, codeString: UXStrings.CString, maskProgramResult: POINTER TO MaskProgram] RETURNS [res: RES¬ok] = {
ENABLE BadMaskProgram => { res ¬ RESFromErrorCode[$syntax]; CONTINUE };
state: State = GetState[h];
prog: REF TEXT = Rope.ToRefText[UXStrings.ToRope[codeString, 32767]];
compiled: REF TEXT ¬ RefText.New[prog.length]; -- prog.length is a good size estimate
LoopContext: TYPE = RECORD [start: NAT, fixups: LIST OF NAT];
stack: LIST OF LoopContext ¬ NIL;
i: NAT ¬ 0;
loc: NAT ¬ 0;
emitbyte: PROC [byte: BYTE] = {
compiled ¬ RefText.AppendChar[compiled, VAL[byte]];
loc ¬ loc + 1;
};
emitop: PROC [op: Op, offset: BYTE ¬ 0] = {emitbyte[ORD[op]+offset]};
emitfixups: PROC [f: LIST OF NAT, to: NAT] = {
FOR tail: LIST OF NAT ¬ f, tail.rest UNTIL tail = NIL DO
compiled[tail.first] ¬ VAL[to-(tail.first+1)];
ENDLOOP;
};
GetRegSpec: PROC RETURNS [[0..9]] = {
i¬i+1;
IF i >= prog.length THEN ERROR BadMaskProgram ELSE {
ch: CHAR = prog[i];
SELECT ch FROM
IN ['0..'9] => RETURN [ch-'0];
ENDCASE => ERROR BadMaskProgram;
};
};
GetLenSpec: PROC RETURNS [[0..2]] = {
i¬i+1;
IF i >= prog.length THEN ERROR BadMaskProgram;
SELECT prog[i] FROM
'1 => RETURN [0];
'2 => RETURN [1];
'4 => RETURN [2];
ENDCASE => ERROR BadMaskProgram;
};
maskProgramResult­ ¬ NIL;
IF NOT bigEndian THEN RETURN [notImplemented];
WHILE i<prog.length DO
SELECT prog[i] FROM
'{ => { stack ¬ CONS[[start: loc, fixups: NIL], stack]};
'} => {
IF stack = NIL THEN ERROR BadMaskProgram;
emitop[$loop];
emitbyte[loc+1-stack.first.start];
emitfixups[stack.first.fixups, loc];
stack ¬ stack.rest;
};
'X => {
IF stack = NIL THEN ERROR BadMaskProgram;
emitop[$jz];
stack.first.fixups ¬ CONS[loc, stack.first.fixups];
emitbyte[0];
};
'L => {
emitop[$load0, GetRegSpec[]];
};
'S => {
emitop[$store0, GetRegSpec[]];
};
'+ => {
emitop[$add0, GetRegSpec[]];
};
'- => {
emitop[$sub0, GetRegSpec[]];
};
'^ => {
emitop[$shift0, GetRegSpec[]];
};
'~ => {
emitop[$not];
};
'F => {
emitop[$int1, GetLenSpec[]];
};
'W => {
emitop[$word1, GetLenSpec[]];
};
'= => {
emitop[$clear];
};
'E => {
emitop[$emit];
};
ENDCASE => {
val: INT = prog[i] - '0;
IF val IN [0..7]
THEN { emitop[$octal0, val] }
ELSE ERROR BadMaskProgram;
};
i ¬ i + 1;
ENDLOOP;
NoteRef[state, maskProgramResult­ ¬ compiled];
};
SignExtendByte: SAFE PROC [byte: BYTE] RETURNS [INT] = CHECKED {
RETURN [byte - (byte/127*256)]
};
Shift: SAFE PROC [a, b: INT] RETURNS [INT] = CHECKED {
w: CARD ¬ LOOPHOLE[a, CARD];
w ¬ Basics.BITSHIFT[w, b];
RETURN [LOOPHOLE[w, INT]];
};
SignedHalfwords: TYPE = RECORD [PACKED SEQUENCE COMPUTED CARDINAL OF INT16];
UnsignedHalfwords: TYPE = RECORD [PACKED SEQUENCE COMPUTED CARDINAL OF CARD16];
MaskDeviceBoxes: PUBLIC PROC [h: Handle, sMin, fMin, sMax, fMax: INT, boxOrder: INT, maskProgram: MaskProgram, maskDataByteCount: INT, maskData: POINTER] RETURNS [res: RES ¬ ok] = {
state: State = GetState[h];
Validate[state];
IF maskProgram = NIL THEN RETURN [nilFault];
IF sMin < sMax AND fMin < fMax THEN {
GenerateBoxes: SAFE PROC [boxAction: SF.BoxAction] = CHECKED {
c: REF TEXT = maskProgram;
pc: NAT ¬ 0;
reg: ARRAY [0..9] OF INT ¬ [sMin, fMin, sMax, fMax, 0, 0, 0, 0, 0, 0];
A: INT ¬ 0;
src: POINTER TO Basics.RawBytes = LOOPHOLE[maskData];
len: INT = maskDataByteCount;
i: INT ¬ 0;
WHILE pc < c.length DO
op: Op = VAL[ORD[c[pc]]];
pc ¬ pc + 1;
SELECT op FROM
loop => { pc ¬ pc + 1 - ORD[c[pc]] };
jz => { pc ¬ pc + 1 + (IF A = 0 THEN ORD[c[pc]] ELSE 0) };
emit => {
s0: INT = MAX[reg[0], sMin];
f0: INT = MAX[reg[1], fMin];
s1: INT = MIN[reg[2], sMax];
f1: INT = MIN[reg[3], fMax];
IF s0 < s1 AND f0 < f1 THEN boxAction[[[s0, f0], [s1, f1]]];
};
load0 => A ¬ reg[0];
load1 => A ¬ reg[1];
load2 => A ¬ reg[2];
load3 => A ¬ reg[3];
load4 => A ¬ reg[4];
load5 => A ¬ reg[5];
load6 => A ¬ reg[6];
load7 => A ¬ reg[7];
load8 => A ¬ reg[8];
load9 => A ¬ reg[9];
store0 => reg[0] ¬ A;
store1 => reg[1] ¬ A;
store2 => reg[2] ¬ A;
store3 => reg[3] ¬ A;
store4 => reg[4] ¬ A;
store5 => reg[5] ¬ A;
store6 => reg[6] ¬ A;
store7 => reg[7] ¬ A;
store8 => reg[8] ¬ A;
store9 => reg[9] ¬ A;
add0 => A ¬ A+reg[0];
add1 => A ¬ A+reg[1];
add2 => A ¬ A+reg[2];
add3 => A ¬ A+reg[3];
add4 => A ¬ A+reg[4];
add5 => A ¬ A+reg[5];
add6 => A ¬ A+reg[6];
add7 => A ¬ A+reg[7];
add8 => A ¬ A+reg[8];
add9 => A ¬ A+reg[9];
sub0 => A ¬ A-reg[0];
sub1 => A ¬ A-reg[1];
sub2 => A ¬ A-reg[2];
sub3 => A ¬ A-reg[3];
sub4 => A ¬ A-reg[4];
sub5 => A ¬ A-reg[5];
sub6 => A ¬ A-reg[6];
sub7 => A ¬ A-reg[7];
sub8 => A ¬ A-reg[8];
sub9 => A ¬ A-reg[9];
shift0 => A ¬ Shift[A, reg[0]];
shift1 => A ¬ Shift[A, reg[1]];
shift2 => A ¬ Shift[A, reg[2]];
shift3 => A ¬ Shift[A, reg[3]];
shift4 => A ¬ Shift[A, reg[4]];
shift5 => A ¬ Shift[A, reg[5]];
shift6 => A ¬ Shift[A, reg[6]];
shift7 => A ¬ Shift[A, reg[7]];
shift8 => A ¬ Shift[A, reg[8]];
shift9 => A ¬ Shift[A, reg[9]];
not => { A ¬ IF A=0 THEN 1 ELSE 0 };
int1 => TRUSTED { IF i >= len THEN EXIT;
A ¬ SignExtendByte[src[i]]; i ¬ i+1 };
int2 => TRUSTED { IF i >= len THEN EXIT;
A ¬ (LOOPHOLE[maskData, POINTER TO SignedHalfwords]+i)[0]; i ¬ i+2 };
int4 => TRUSTED { IF i >= len THEN EXIT;
A ¬ (LOOPHOLE[maskData, POINTER TO INT32]+i)­; i ¬ i+4 };
word1 => TRUSTED { IF i >= len THEN EXIT;
A ¬ src[i]; i ¬ i+1 };
word2 => TRUSTED { IF i >= len THEN EXIT;
A ¬ (LOOPHOLE[maskData, POINTER TO UnsignedHalfwords]+i)[0]; i ¬ i+2 };
word4 => TRUSTED { IF i >= len THEN EXIT;
A ¬ (LOOPHOLE[maskData, POINTER TO INT32]+i)­; i ¬ i+4 };
clear => { A ¬ 0 };
octal0 => A ¬ A * 8 + 0;
octal1 => A ¬ A * 8 + 1;
octal2 => A ¬ A * 8 + 2;
octal3 => A ¬ A * 8 + 3;
octal4 => A ¬ A * 8 + 4;
octal5 => A ¬ A * 8 + 5;
octal6 => A ¬ A * 8 + 6;
octal7 => A ¬ A * 8 + 7;
ENDCASE => ERROR;
ENDLOOP;
};
IF (boxOrder > 1) OR (state.device.state.allow.multipleCoverage) OR (state.device.state.allow.unorderedBoxes AND (boxOrder > 0))
THEN {
state.device.class.MaskBoxes[state.device, [[sMin, fMin], [sMax, fMax]], GenerateBoxes];
}
ELSE {
In this case, the device really wants the boxes in a fussier order than the client is willing to generate, so we need to work a little harder.
p: ImagerManhattan.Polygon = ImagerManhattan.CreateFromBoxes[GenerateBoxes];
IF p # NIL THEN {
Generate: SAFE PROC [boxAction: SF.BoxAction] = CHECKED {
ImagerManhattan.Map[p, boxAction, NOT state.device.state.allow.unorderedBoxes];
};
state.device.class.MaskBoxes[state.device, ImagerManhattan.BoundingBox[p], Generate];
ImagerManhattan.Destroy[p];
};
};
};
};
BuildClipperBegin: PUBLIC PROC [h: Handle] RETURNS [res: RES ¬ ok] ~ {
state: State = GetState[h];
IF state.savedDevice # NIL THEN RETURN [RESFromErrorCode[$invalidOperationSequence]];
state.savedDevice ¬ state.device;
state.device ¬ MakeCaptureDevice[state.device.parm];
state.device.state.allow ¬ [unorderedBoxes: TRUE, multipleCoverage: TRUE];
ImagerDeviceWorks.Clip[device: state.device, viewClipper: state.viewClipper, clipperToDevice: identity, clientClipper: state.clientClipper];
};
BuildClipperEnd: PUBLIC PROC [h: Handle] RETURNS [res: RES ¬ ok] ~ {
state: State = GetState[h];
IF state.savedDevice = NIL THEN RETURN [RESFromErrorCode[$invalidOperationSequence]];
state.clientClipper ¬ ClipperFromCapturedMasks[state.device];
state.device ¬ state.savedDevice;
state.savedDevice ¬ NIL;
ImagerDeviceWorks.Clip[device: state.device, viewClipper: state.viewClipper, clipperToDevice: identity, clientClipper: state.clientClipper];
ValidateHalftoneProperties[state];
};
CaptureData: TYPE ~ REF CaptureDataRep;
CaptureDataRep: TYPE ~ RECORD [
boxes: LIST OF SF.Box ¬ NIL,
boxesLast: LIST OF SF.Box ¬ NIL
];
MakeCaptureDevice: PROC [parm: ImagerDevice.DeviceParm] RETURNS [ImagerDevice.Device] = {
parm ¬ ImagerDevice.MakeDeviceParm[class: captureClass, sSize: parm.sSize, fSize: parm.fSize, scanMode: parm.scanMode, surfaceUnitsPerInch: parm.surfaceUnitsPerInch, surfaceUnitsPerPixel: parm.surfaceUnitsPerPixel, fontCache: parm.fontCache, parameters: parm.parameters];
RETURN [ImagerDevice.MakeDevice[class: captureClass, parm: parm, data: NEW[CaptureDataRep ¬ []]]]
};
ManhattanFromCapturedMasks: PROC [data: CaptureData] RETURNS [ImagerManhattan.Polygon] = {
p: ImagerManhattan.Polygon ¬ data.boxes;
data.boxes ¬ data.boxesLast ¬ NIL;
[] ¬ ImagerManhattan.Validate[p !
ImagerManhattan.InvalidManhattanPolygon => {
p ¬ ImagerManhattan.Canonicalize[p];
CONTINUE;
};
];
RETURN [p];
};
ClipperFromCapturedMasks: PROC [device: ImagerDevice.Device] RETURNS [ImagerClipper.Clipper] = {
WITH device.data SELECT FROM
data: CaptureData => {
p: ImagerManhattan.Polygon ¬ ManhattanFromCapturedMasks[data];
Path: ImagerPath.PathProc = CHECKED {
FOR tail: LIST OF SF.Box ¬ p, tail.rest UNTIL tail = NIL DO
moveTo[[tail.first.min.s, tail.first.min.f]];
lineTo[[tail.first.max.s, tail.first.min.f]];
lineTo[[tail.first.max.s, tail.first.max.f]];
lineTo[[tail.first.min.s, tail.first.max.f]]
ENDLOOP
};
outline: ImagerPath.Outline = ImagerPath.OutlineFromPath[Path];
ImagerManhattan.Destroy[p];
RETURN [LIST[[outline: outline]]]
}
ENDCASE => RETURN [NIL]
};
captureClass: ImagerDevice.DeviceClass ~ NEW[ImagerDevice.DeviceClassRep ¬ [
SetColor: CaptureSetColor,
MaskBoxes: CaptureMaskBoxes
]];
CaptureSetColor: SAFE PROC [device: Device, color: Color, viewToDevice: Transformation] ~ CHECKED {
data: CaptureData ~ NARROW[device.data];
};
CaptureMaskBoxes: SAFE PROC [device: Device, bounds: SF.Box, boxes: SF.BoxGenerator] ~ CHECKED {
data: CaptureData ~ NARROW[device.data];
new: ImagerManhattan.Polygon ~ ImagerManhattan.CreateFromBoxes[boxes];
IF new # NIL THEN {
IF data.boxes # NIL THEN {
last: ImagerManhattan.Polygon ¬ new;
WHILE last.rest # NIL DO last ¬ last.rest ENDLOOP;
last.rest ¬ data.boxes;
};
data.boxes ¬ new;
};
};
FindFont: PUBLIC PROC [h: Handle, fontName: UXStrings.CString, fontResult: POINTER TO ImagerFont.Font] RETURNS [res: RES ¬ ok] ~ {
state: State = GetState[h];
rope: ROPE ~ UXStrings.ToRope[fontName, 256];
IF fontResult = NIL THEN RETURN [nilFault];
fontResult­ ¬ NIL;
NoteRef[state, fontResult­ ¬ ImagerFont.Find[rope, noSubstitute ! ImagerError.Error => {res ¬ CII.RESFromErrorCode[error.code]; CONTINUE}]];
};
ModifyFont: PUBLIC PROC [h: Handle, font: REF, mp: POINTER TO Matrix, fontResult: POINTER TO ImagerFont.Font] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
IF fontResult = NIL THEN RETURN [nilFault];
fontResult­ ¬ NIL;
WITH font SELECT FROM
font: ImagerFont.Font => {
m: Transformation ~ MakeTransformation[mp];
new: ImagerFont.Font ~ ImagerFont.Modify[font, m];
NoteRef[state, fontResult­ ¬ new];
ImagerTransformation.Destroy[m];
};
ENDCASE => RETURN [wrongType];
};
MakeFontAtom: PUBLIC PROC [h: Handle, font: REF, mp: POINTER TO Matrix, fontResult: POINTER TO ImagerFont.Font] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
IF fontResult = NIL THEN RETURN [nilFault];
fontResult­ ¬ NIL;
WITH font SELECT FROM
font: ImagerFont.Font => {
m: Transformation ~ MakeTransformation[mp];
ImagerTransformation.ApplyTranslateTo[m, [0, 0]];
NoteRef[state, fontResult­ ¬ ImagerFont.Modify[font, m]];
ImagerTransformation.Destroy[m];
};
ENDCASE => RETURN [wrongType];
};
ApplyHardChar: PROC [proc: CProc, h: Handle, arg: POINTER TO ShowArgs] ~ MACHINE CODE {
"+#define ApplyHardChar←HELP(p,a,b) APPLY(p)(a,b)\n";
"#define APPLY(proc) (*((funptr)(proc)))\n";
"typedef word (*funptr)();\n";
".ApplyHardChar←HELP";
};
ApplyHardMetrics: PROC [proc: CProc, h: Handle, arg: POINTER TO ShowArgs, charMask: ImagerMaskCache.CharMask] ~ MACHINE CODE {
"+#define ApplyHardMetrics←HELP(p,a,b,c) APPLY(p)(a,b,c)\n";
".ApplyHardMetrics←HELP";
};
debugging: BOOL ¬ FALSE;
Debugging: PROC [new: CARD] RETURNS [old: BOOL] ~ {
old ¬ debugging;
debugging ¬ new#0;
};
Debug: PROC [cp: ImagerDeviceVector.DVec, p: POINTER TO ShowArgs] ~ {
s: CARD ¬ LOOPHOLE[p];
BEGIN ENABLE ABORTED => CONTINUE; ERROR END;
};
worryNat: NAT = LAST[NAT15] / 2 - 1;
worryReal: REAL ¬ worryNat;
CPIn: PROC [cp: ImagerDeviceVector.DVec, s: POINTER TO ShowArgs] ~ {
IF debugging THEN Debug[cp, s];
IF ABS[s.cp.x] < worryReal AND ABS[s.cp.y] < worryReal
THEN {
cp.scaled ¬ TRUE;
cp.sv.s ¬ Scaled.FromReal[s.cp.x];
cp.sv.f ¬ Scaled.FromReal[s.cp.y];
}
ELSE {
cp.fv ¬ s.cp;
cp.scaled ¬ FALSE;
};
};
CPOut: PROC [cp: ImagerDeviceVector.DVec, s: POINTER TO ShowArgs] ~ {
IF debugging THEN Debug[cp, s];
IF cp.scaled THEN {
cp.scaled ¬ FALSE;
cp.fv.x ¬ Scaled.Float[cp.sv.s];
cp.fv.y ¬ Scaled.Float[cp.sv.f];
};
s.cp ¬ cp.fv;
};
Ref: PROC [ref: REF] RETURNS [REF] = INLINE { RETURN [ref] };
Show: PUBLIC PROC [h: Handle, s: POINTER TO ShowArgs] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
device: Device ~ state.device;
fontAtom: ImagerFont.Font ~ s.fontAtom;
cp: ImagerDeviceVector.DVec ~ state.cp;
String: ImagerFont.XStringProc ~ TRUSTED {
PROC [charAction: XCharProc]
UNTIL s.start >= s.end DO
charAction[s.characters[s.start]];
s.start ¬ s.start + 1;
ENDLOOP;
};
HardChar: ImagerFont.XCharProc ~ TRUSTED {
CPOut[cp, s];
ApplyHardChar[s.hardChar, h, s];
CPIn[cp, s];
};
HardMetrics: SAFE PROC [charMask: ImagerMaskCache.CharMask] ~ TRUSTED {
CPOut[cp, s];
ApplyHardMetrics[s.hardMetrics, h, s, charMask];
CPIn[cp, s];
};
WITH Ref[fontAtom] SELECT FROM
font: ImagerFont.Font => NULL;
ENDCASE => RETURN [wrongType];
WITH Ref[cp] SELECT FROM
cp: ImagerDeviceVector.DVec => NULL;
ENDCASE => RETURN [wrongType];
Validate[state];
CPIn[cp, s];
ImagerDeviceWorks.Show[
device: device,
fontAtom: fontAtom,
string: String,
cp: cp,
hardChar: HardChar,
hardMetrics: HardMetrics,
easyMetrics: s.easyMetrics,
noImage: s.noImage
];
CPOut[cp, s];
};
scratchContext: Imager.Context ¬ NIL;
ObtainScratchContext: ENTRY PROC RETURNS [context: Imager.Context] ~ {
context ¬ scratchContext; scratchContext ¬ NIL
};
ReleaseScratchContext: ENTRY PROC [context: Imager.Context] ~ {
scratchContext ¬ context;
};
DoHardChar: PUBLIC PROC [h: Handle, s: POINTER TO ShowArgs] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
iState: ImagerDeviceInterchange.InterchangeState ~ ImagerDeviceInterchange.ObtainInterchangeState[];
context: Imager.Context ¬ ObtainScratchContext[];
char: XChar ~ s.characters[s.start];
esc: VEC ~ ImagerFont.Escapement[s.fontAtom, char];
iState.device ¬ state.device;
iState.clientToView ¬ ImagerTransformation.Scale[1];
iState.viewToSurface ¬ ImagerTransformation.Scale[1];
iState.surfaceToDevice ¬ ImagerTransformation.Scale[1];
iState.color ¬ state.color;
context ¬ ImagerRaster.ContextFromInterchangeState[iState, context];
Imager.SetXY[context, s.cp];
Imager.Trans[context];
ImagerFontWorks.MaskChar[s.fontAtom, char, context];
IF debugging THEN Debug[NIL, s];
s.cp.x ¬ s.cp.x + esc.x;
s.cp.y ¬ s.cp.y + esc.y;
ReleaseScratchContext[context];
state.dcolor ¬ NIL;
};
DoHardMetrics: PUBLIC PROC [h: Handle, s: POINTER TO ShowArgs, maskInfo: POINTER TO MaskInfo] RETURNS [RES¬ok] ~ {
state: State = GetState[h];
char: XChar ~ s.characters[s.start];
esc: VEC ~ ImagerFont.Escapement[s.fontAtom, char];
s.cp.x ¬ s.cp.x + esc.x;
s.cp.y ¬ s.cp.y + esc.y;
};
BufferedSeparationImage: PUBLIC PROC [h: Handle, buffers: POINTER TO ARRAY[0..0) OF POINTER TO RasterRep, samplesPerPixel: CARD, sMin, sMax: INT, colorOperator: ColorOperator, interpolate: BOOL] RETURNS [res: RES ¬ ok] = {
ENABLE ImagerError.Error => { res ¬ RESFromErrorCode[error.code]; CONTINUE };
state: State = GetState[h];
device: Device = state.device;
pixelMap: ImagerPixel.PixelMap = PixelMapFromRasters[samplesPerPixel, buffers];
box: SF.Box ¬ pixelMap.box;
IF box.min.s < sMin THEN box.min.s ¬ sMin;
IF box.max.s > sMax THEN box.max.s ¬ sMax;
ImagerImageWorks.DrawBufferedImage[device: device, buffer: pixelMap, box: box, colorOperator: colorOperator, pixelToView: state.transformation, viewToDevice: identity];
};
BufferedInterleavedImage: PUBLIC PROC [h: Handle, buffer: POINTER TO RasterRep, samplesPerPixel: CARD, sMin, sMax: INT, colorOperator: ColorOperator, interpolate: BOOL] RETURNS [res: RES ¬ ok] = {
ENABLE ImagerError.Error => { res ¬ RESFromErrorCode[error.code]; CONTINUE };
state: State = GetState[h];
device: Device = state.device;
sampleMap: ImagerSample.SampleMap = MakeSampleMap[buffer];
box: SF.Box ¬ sampleMap.GetBox;
IF box.min.s < sMin THEN box.min.s ¬ sMin;
IF box.max.s > sMax THEN box.max.s ¬ sMax;
box.min.f ¬ box.min.f / samplesPerPixel;
box.max.f ¬ box.max.f / samplesPerPixel;
ImagerImageWorks.DrawInterleavedImage[device: device, buffer: sampleMap, samplesPerPixel: samplesPerPixel, box: box, colorOperator: colorOperator, pixelToView: state.transformation, viewToDevice: identity];
};
MesaProcRep: TYPE = RECORD [cProc: CProc, link: CARD];
ImageSourceStreamRep: TYPE = RECORD [source: ImageSource, read: ImageSourceReadProc, destroy: ImageSourceDestroyProc, readProcRep: MesaProcRep, destroyProcRep: MesaProcRep];
ImageSourceUnsafeGetBlock: IO.UnsafeGetBlockProc = {
PROC [self: IO.STREAM, block: UnsafeBlock] RETURNS [nBytesRead: INT]
data: REF ImageSourceStreamRep = NARROW[self.streamData];
res: RES ¬ ok;
nbytesResult: CARD ¬ 0;
ASSUMES byte addressing, big-endian c semantics
res ¬ data.read[self: data.source, buf: block.base+block.startIndex, nbytes: block.count, nbytesResult: @nbytesResult];
IF res#ok THEN ERROR IO.Error[$Failure, self, LIST[NEW[RES¬res]]];
RETURN [nbytesResult]
};
ImageSourceClose: IO.CloseProc = TRUSTED {
data: REF ImageSourceStreamRep = NARROW[self.streamData];
res: RES ¬ ok;
res ¬ data.destroy[data.source];
self.streamProcs ¬ IOUtils.closedStreamProcs;
self.streamData ¬ NIL;
IF res#ok THEN ERROR IO.Error[$Failure, self, LIST[NEW[RES¬res]]];
};
imageSourceStreamProcs: REF IO.StreamProcs = IO.CreateStreamProcs[
variety: $input,
class: $CIIImageSource,
unsafeGetBlock: ImageSourceUnsafeGetBlock,
close: ImageSourceClose
];
StreamFromImageSource: PROC [source: ImageSource] RETURNS [IO.STREAM] = {
data: REF ImageSourceStreamRep = NEW[ImageSourceStreamRep];
data.source ¬ source;
data.readProcRep ¬ [source.read, 0];
data.destroyProcRep ¬ [source.destroy, 0];
data.read ¬ LOOPHOLE[@data.readProcRep];
data.destroy ¬ LOOPHOLE[@data.destroyProcRep];
RETURN [IO.CreateStream[streamProcs: imageSourceStreamProcs, streamData: data]];
};
StreamImage: PUBLIC PROC [h: Handle, sSize: CARD, fSize: CARD, bitsPerSample: CARD, samplesPerPixel: CARD, padMod: CARD, co: ImagerColor.ColorOperator, interpolate: BOOL, source: ImageSource] RETURNS [res: RES ¬ ok] = {
ENABLE ImagerError.Error => {
res ¬ CII.RESFromErrorCode[error.code];
CONTINUE;
};
state: State = GetState[h];
stream: IO.STREAM = StreamFromImageSource[source];
device: Device = state.device;
ImagerImageWorks.StreamImage[device: device, sSize: sSize, fSize: fSize, bitsPerSample: bitsPerSample, samplesPerPixel: samplesPerPixel, padMod: padMod, pixelToView: state.transformation, viewToDevice: identity, co: co, source: stream];
IO.Close[stream];
};
ChooseBandSize: PROC [sSize: NAT, fSize: NAT] RETURNS [NAT] = {
RETURN [MIN[sSize, 64]]
};
GetUnsafeBlock: PROC [map: ImagerSample.RasterSampleMap] RETURNS [Basics.UnsafeBlock] ~ {
Like ImagerSample.GetUnsafeBlock, but allows up to 31 pad bits per scan line.
size: SF.Vec ~ ImagerSample.GetSize[map];
base: POINTER TO Basics.RawBytes = LOOPHOLE[map.GetBase.word];
startIndex: NAT = map.GetBase.bit/8;
IF size.s = 0 OR size.f = 0
THEN RETURN [[base: base, startIndex: startIndex, count: 0]]
ELSE {
bitsPerLine: CARD ~ map.GetBitsPerLine;
dataBitsPerLine: CARD ~ CARD[map.GetBitsPerSample]*CARD[size.f];
fillBitsPerLine: [0..32) ~ bitsPerLine - dataBitsPerLine;
padStart: [0..0] ~ map.GetBase.bit MOD 8;
nBytes: NAT ~ (CARD[size.s]*bitsPerLine + 7)/8;
RETURN [[base: LOOPHOLE[map.GetBase.word], startIndex: map.GetBase.bit/8, count: nBytes]]
};
};
MaskStreamBits: PUBLIC PROC [h: Handle, sSize: CARD, fSize: CARD, padMod: CARD, source: ImageSource, background: Color] RETURNS [res: RES ¬ ok] = {
ENABLE ImagerError.Error => {
res ¬ CII.RESFromErrorCode[error.code];
CONTINUE;
};
state: State = GetState[h];
stream: IO.STREAM = StreamFromImageSource[source];
IF sSize # 0 AND fSize # 0 THEN {
sSizeNat: NAT ¬ sSize;
fSizeNat: NAT ~ fSize;
bandSize: NAT ~ ChooseBandSize[sSize: sSizeNat, fSize: fSizeNat];
fSizeBand: NAT ~ fSizeNat;
padModPred: NAT = padMod-1;
bitsPerLine: NAT ~ (fSize+padModPred)/padMod*padMod;
bandStore: ImagerSample.RasterSampleMap ~ ImagerSample.ObtainScratchMap[box: [min: [0, 0], max: [s: bandSize, f: fSizeBand]], bitsPerSample: 1, bitsPerLine: bitsPerLine];
band: ImagerSample.RasterSampleMap ¬ NIL; -- valid band data
box: SF.Box ¬ []; -- the part to image this time around.
DO
newBand: ImagerSample.RasterSampleMap ¬ NIL;
readBand: ImagerSample.RasterSampleMap ¬ NIL;
box.min.s ¬ box.max.s;
box.min.f ¬ 0;
box.max.s ¬ box.max.s+bandSize;
box.max.f ¬ fSize;
IF box.max.s > sSizeNat THEN box.max.s ¬ sSizeNat;
IF box.min.s >= box.max.s THEN EXIT;
readBand ¬ newBand ¬ NARROW[ImagerSample.ReIndex[map: bandStore, delta: [s: box.min.s, f: 0], box: [min: [0, 0], max: [sSizeNat, fSizeBand]]]];
IF band # NIL THEN {
ImagerSample.Transfer[dst: newBand, src: band];
readBand ¬ NARROW[ImagerSample.Clip[readBand, [min: [band.GetBox.max.s, 0], max: SF.maxVec]]];
};
band ¬ newBand;
TRUSTED {
block: Basics.UnsafeBlock ~ GetUnsafeBlock[readBand];
bytes: INT ~ IO.UnsafeGetBlock[stream, block];
IF bytes < block.count THEN {
Premature end; chop off the image, as per section 4.10.2
box.max.s ¬ sSizeNat ¬ readBand.GetBox.min.s + ((bytes*8)/bitsPerLine);
band ¬ NARROW[ImagerSample.Clip[band, [max: [sSizeNat, fSizeBand]]]];
};
};
InternalMaskBitmap[state, band, background];
ENDLOOP;
ImagerSample.ReleaseScratchMap[bandStore];
};
};
ApplyCCITTFacsimileDecompressionFilter: PUBLIC ApplyCCITTFacsimileDecompressionFilterProc = {
[h: Handle, input: ImageSource, k: INT, requireEOL: BOOL, padMod: CARD, sSize: CARD, fSize: CARD, endOfBlock: BOOL, blackIs1: BOOL, msbFirst: BOOL, damagedRowsBeforeError: INT, filteredResult: POINTER TO ImageSource] RETURNS [RES]
IF h = NIL OR h.data = NIL OR filteredResult = NIL THEN RETURN [nilFault];
filteredResult­ ¬ NIL;
SELECT padMod FROM
1 => IF (fSize MOD 8) # 0 THEN GO TO notYet;
8, 16, 32 => {};
ENDCASE => GO TO notYet;
SELECT TRUE FROM
requireEOL => GO TO notYet;
fSize NOT IN [1..32000] => GO TO notYet;
sSize NOT IN [0..32000] => GO TO notYet;
endOfBlock => GO TO notYet;
damagedRowsBeforeError # 0 => GO TO notYet;
ENDCASE => {
We think that we can handle this
state: State = GetState[h];
st: IO.STREAM = StreamFromImageSource[input];
g4: G4Data = PixelArrayCCITTG4Private.FromStream[st, fSize];
words: CARDINAL = (fSize+BITS[WORD]-1)/BITS[WORD];
buf: REF Basics.RawBytes = NEW[Basics.RawBytes[words * BYTES[WORD]]];
bp: BytesPtr = LOOPHOLE[buf];
fsd: FaxSourceData = NEW[FaxSourceDataRep ¬
[h: h, st: st, g4: g4, buf: buf, bp: bp, sSize: sSize, fSize: fSize]];
result: REF CII.ImageSourceObjectRep = NEW[CII.ImageSourceObjectRep ¬ [
data: LOOPHOLE[fsd],
read: CProcFromProc[FaxSourceRead],
destroy: CProcFromProc[FaxSourceDestroy]]];
g4.scanLength ¬ fSize;
g4.reverseBits ¬ msbFirst;
Note: "reversed" means reversed from normal PC world order. Adobe behavior is reverseBits = true! msbFirst means that the first bit is the high-order bit in the byte.
g4.k ¬ k;
g4.useFastScan ¬ TRUE;
g4.reverseBits ¬ NOT msbFirst;
g4.sSize ¬ sSize;
g4.lineBuffer ¬ ImagerSample.ObtainUnsafeDescriptor[size: [s: 1, f: fSize], bitsPerSample: 1, bitsPerLine: fSize, base: [LOOPHOLE[buf], 0], ref: buf, words: words];
fsd.mod ¬ padMod;
fsd.rem ¬ 0;
fsd.pos ¬ 0;
fsd.invert ¬ NOT blackIs1;
NoteRef[state, fsd];
NoteRef[state, result];
filteredResult­ ¬ LOOPHOLE[result];
RETURN [ok];
};
EXITS notYet => RETURN [notImplemented];
};
G4Data: TYPE = PixelArrayCCITTG4Private.Data;
FaxSourceData: TYPE = REF FaxSourceDataRep;
FaxSourceDataRep: TYPE = RECORD [
h: Handle ¬ NIL,
st: IO.STREAM ¬ NIL,
g4: G4Data ¬ NIL,
buf: BytesRef ¬ NIL,
bp: BytesPtr ¬ NIL,
mod: CARDINAL ¬ 0,
pos: CARDINAL ¬ 0,
rem: CARDINAL ¬ 0,
fSize: INTEGER ¬ 0,
sSize: INTEGER ¬ 0,
s: INTEGER ¬ 0,
invert: BOOL ¬ FALSE
];
BytesPtr: TYPE = POINTER TO Basics.RawBytes;
BytesRef: TYPE = REF Basics.RawBytes;
FaxSourceRead: CII.ImageSourceReadProc = {
[self: ImageSource, buf: POINTER, nbytes: CARD, nbytesResult: POINTER TO CARD] RETURNS [RES]
fsd: FaxSourceData = LOOPHOLE[self.data];
rem: CARDINAL ¬ 0;
IF nbytesResult = NIL THEN RETURN [nilFault];
nbytesResult­ ¬ 0;
IF fsd = NIL THEN RETURN [nilFault];
IF nbytes = 0 THEN RETURN [bounds];
IF fsd.g4.end THEN RETURN [eof];
rem ¬ fsd.rem;
IF rem = 0 THEN {
Refill the line buffer
fSize: CARDINAL = fsd.fSize;
fMod: [0..BITS[WORD]) = fSize MOD BITS[WORD];
PixelArrayCCITTG4Private.FillLineBuffer[fsd.g4, fsd.s, fsd.invert];
IF fsd.g4.error # NIL THEN {fsd.g4.end ¬ TRUE; RETURN [ioError]};
fsd.s ¬ fsd.s + 1;
SELECT fsd.mod FROM
16 => rem ¬ ((fSize+15) / 16) * 2;
32 => rem ¬ ((fSize+31) / 32) * 4;
ENDCASE => rem ¬ (fSize+7) / 8;
IF fMod # 0 THEN {
Pad out the last valid word in the buffer
WordPtr: TYPE = POINTER TO WORD;
mask: WORD ¬ Basics.BITRSHIFT[WORD.LAST, fMod];
wp: WordPtr = LOOPHOLE[fsd.bp, WordPtr] + SIZE[WORD]*(fSize / BITS[WORD]);
w: WORD ¬ wp­;
w ¬ w - Basics.BITAND[w, mask];
IF fsd.invert THEN w ¬ w + mask;
wp­ ¬ w;
};
fsd.pos ¬ 0;
};
IF rem < nbytes THEN nbytes ¬ rem;
Basics.MoveBytes[
dstBase: LOOPHOLE[buf, BytesPtr], dstStart: 0,
srcBase: fsd.bp, srcStart: fsd.pos,
count: nbytes];
fsd.rem ¬ rem - nbytes;
fsd.pos ¬ fsd.pos + nbytes;
nbytesResult­ ¬ nbytes;
RETURN [ok];
};
FaxSourceDestroy: CII.ImageSourceDestroyProc = {
[self: ImageSource] RETURNS [RES]
fsd: FaxSourceData = LOOPHOLE[self.data];
IF fsd # NIL THEN {
h: Handle = fsd.h;
state: State = GetState[fsd.h];
g4: G4Data = fsd.g4;
ImagerSample.ReleaseDescriptor[g4.lineBuffer];
g4.lineBuffer ¬ NIL;
PixelArrayCCITTG4Private.Close[g4];
[] ¬ DestroyAny[h, fsd];
fsd.h ¬ NIL;
self.data ¬ NIL;
};
RETURN [ok];
};
HalftoneProperties: TYPE = REF HalftonePropertiesRep;
HalftonePropertiesRep: PUBLIC TYPE = CIIPrivate.HalftonePropertiesRep;
MakeHalftoneProperties: PUBLIC PROC [h: Handle, separationCount: INT, halftonePropertiesForSeparation: POINTER TO ARRAY [0..0) OF HalftonePropertiesForSeparation, halftonePropertiesResult: POINTER TO HalftoneProperties] RETURNS [res: RES ¬ ok] = {
state: State = GetState[h];
p: ImagerBrick.HalftoneProperties ¬ NIL;
FOR i: INT DECREASING IN [0..separationCount) DO
s: POINTER TO HalftonePropertiesForSeparation = @(halftonePropertiesForSeparation[i]);
type: ATOM = NIL;
toner: ImagerBrick.Toner = VAL[ORD[s.toner]];
maxSample: CARDINAL = s.maxSample;
thresholds: ImagerSample.RasterSampleMap = MakeSampleMap[@(s.thresholds), ObtainDesc[state]];
brick: ImagerBrick.Brick = [maxSample: s.maxSample, sampleMap: ImagerSample.Copy[thresholds], phase: s.phase];
p ¬ CONS[[type: type, toner: toner, brick: brick, propList: NIL], p];
ReleaseDesc[state, thresholds];
ENDLOOP;
NoteRef[state, halftonePropertiesResult­ ¬ NEW[HalftonePropertiesRep ¬ [p]]];
};
ValidateHalftoneProperties: PROC [state: State] = {
IF state.halftoneProperties = NIL THEN state.halftoneProperties ¬ NEW[HalftonePropertiesRep ¬ [NIL]];
IF state.savedDevice = NIL AND state.halftoneProperties # state.dhalftoneProperties AND state.device.class.SetHalftoneProperties # NIL THEN {
state.device.class.SetHalftoneProperties[state.device, state.halftoneProperties.p];
state.dhalftoneProperties ¬ state.halftoneProperties;
};
};
SetHalftoneProperties: PUBLIC PROC [h: Handle, halftoneProperties: HalftoneProperties] RETURNS [res: RES ¬ ok] = {
state: State = GetState[h];
state.halftoneProperties ¬ halftoneProperties;
ValidateHalftoneProperties[state];
};
GetHalftoneProperties: PUBLIC PROC [h: Handle, halftonePropertiesResult: POINTER TO HalftoneProperties] RETURNS [res: RES ¬ ok] = {
state: State = GetState[h];
ValidateHalftoneProperties[state];
NoteRef[state, halftonePropertiesResult­ ¬ state.halftoneProperties];
};
Destroy: PUBLIC DestroyProc = {
res: RES ¬ ok;
IF h = NIL THEN RETURN [nilFault] ELSE {
state: State = GetState[h];
IF state = NIL THEN RETURN [nilFault];
UNTIL state.cleanups = NIL DO
cleanupObject: CleanupObject = state.cleanups.first;
IF UnRegisterCleanupObject[h, cleanupObject] # ok THEN ERROR;
[] ¬ ApplyCleanupObject[cleanupObject.Cleanup, cleanupObject, h];
ENDLOOP;
IF state.refTab.GetSize[] # 0 THEN res ¬ accessError;
};
IF NOT handles.Delete[h] THEN res ¬ accessError;
h.data ¬ NIL;
RETURN [res]
};
ApplyCleanupObject: PROC [cleanup: CProc, self: CII.CleanupObject, h: CII.Handle] RETURNS [RES] = MACHINE CODE {
"+#define ApplyCleanupObject←HELP(p,a,b) APPLY(p)(a,b)\n";
".ApplyCleanupObject←HELP"
};
DestroyColor: PUBLIC DestroyColorProc = {RETURN DestroyAny[h, color]};
DestroyColorOperator: PUBLIC DestroyColorOperatorProc = {RETURN DestroyAny[h, colorOperator]};
DestroyClipper: PUBLIC DestroyClipperProc = {RETURN DestroyAny[h, clipper]};
DestroyFont: PUBLIC DestroyFontProc = {RETURN DestroyAny[h, font]};
DestroyMaskProgram: PUBLIC DestroyMaskProgramProc = {RETURN DestroyAny[h, maskProgram]};
DestroyHalftoneProperties: PUBLIC DestroyHalftonePropertiesProc = {
RETURN DestroyAny[h, halftoneProperties]
};
DestroyLookupTable: PUBLIC DestroyLookupTableProc = {
RETURN DestroyAny[h, lookupTable]
};
DefaultSetOutputBuffers: PUBLIC SetOutputBuffersProc = {
RETURN [notImplemented]
};
DefaultSetSeparation: PUBLIC SetSeparationProc = {
RETURN [notImplemented]
};
LookupTableRep: PUBLIC TYPE = ImagerDeviceColor.LookupTableRep;
clttTranslate: ARRAY ColorLookupTableType OF ImagerDeviceColor.ColorLookupTableType = [redTransfer: redTransfer, greenTransfer: greenTransfer, blueTransfer: blueTransfer, grayTransfer: grayTransfer, blackGeneration: blackGeneration, undercolorRemoval: undercolorRemoval];
MakeLookupTable: PUBLIC MakeLookupTableProc = {
state: State = GetState[h];
new: ImagerDeviceColor.LookupTable = NEW[LookupTableRep[tableSize]];
IF table[0] + table[tableSize-1] NOT IN [-10.0..10.0] THEN ERROR; -- sanity check
FOR i: INT IN [0..tableSize) DO new[i] ¬ table[i] ENDLOOP;
NoteRef[state, lookupTableResult­ ¬ new];
RETURN [ok]
};
SetColorLookupTable: PUBLIC SetColorLookupTableProc = {
state: State = GetState[h];
control: ImagerDeviceColor.DeviceColorControl = ImagerDeviceColor.GetDeviceColorControl[state.device];
ImagerDeviceColor.SetLookupTable[control, clttTranslate[which], lookupTable];
RETURN [ok]
};
GetColorLookupTable: PUBLIC GetColorLookupTableProc = {
state: State = GetState[h];
control: ImagerDeviceColor.DeviceColorControl = ImagerDeviceColor.GetDeviceColorControl[state.device];
NoteRef[state, lookupTableResult­ ¬ control.table[clttTranslate[which]]];
RETURN [ok]
};
DefaultSetColorTable: PUBLIC SetColorTableProc = {
IF CStrings.Strlen[format] = 0 THEN RETURN [ok] ELSE RETURN [notImplemented];
};
AtomFromCString: PUBLIC PROC [s: CStrings.CString] RETURNS [ATOM] = {
G: SAFE PROC [C: PROC [CHAR]] = TRUSTED {
FOR i: NAT15 ¬ 0, i+1 UNTIL s[i]=0C DO C[s[i]] ENDLOOP;
};
RETURN [Atom.MakeAtomFromChars[G]]
};
MatchCString: PUBLIC PROC [s: CStrings.CString, text: REF TEXT] RETURNS [BOOL] = {
FOR i: NAT IN [0..text.length) DO
IF s[i] # text[i] THEN RETURN [FALSE];
ENDLOOP;
RETURN [s[text.length] = 0C]
};
DefaultSync: PUBLIC SyncProc = {
IF MatchCString[operationName, "sync"] THEN RETURN [ok] ELSE RETURN [notImplemented];
};
RegisterCleanupObject: PUBLIC RegisterCleanupObjectProc = {
state: State = GetState[h];
IF cleanupObject = NIL THEN RETURN [nilFault];
state.cleanups ¬ CONS[cleanupObject, state.cleanups];
RETURN [ok]
};
UnRegisterCleanupObject: PUBLIC RegisterCleanupObjectProc = {
state: State = GetState[h];
prev: LIST OF CleanupObject ¬ NIL;
FOR tail: LIST OF CleanupObject ¬ state.cleanups, tail.rest UNTIL tail = NIL DO
IF tail.first = cleanupObject THEN {
IF prev = NIL THEN state.cleanups ¬ tail.rest ELSE prev.rest ¬ tail.rest;
tail.rest ¬ NIL;
tail.first ¬ NIL;
RETURN [ok]
};
prev ¬ tail;
ENDLOOP;
RETURN [accessError]
};
DefaultSetupArrayParamSize: PUBLIC CIIPrivate.SetupArrayParamSizeProc = {
RETURN [accessError]
};
DefaultSetupIntParam: PUBLIC CIIPrivate.SetupIntParamProc = {
RETURN [accessError]
};
DefaultSetupFloatParam: PUBLIC CIIPrivate.SetupFloatParamProc = {
RETURN [accessError]
};
DefaultSetupNameParam: PUBLIC CIIPrivate.SetupNameParamProc = {
RETURN [accessError]
};
DefaultCreateHandleFromRasters: PUBLIC CIIPrivate.CreateHandleFromRastersProc = {
RETURN [accessError]
};
setuphandles: RefTab.Ref = RefTab.Create[];
DestroySetupObject: CIIPrivate.DestroySetupObjectProc = {
res: RES ¬ ok;
IF s = NIL THEN RETURN [nilFault];
IF NOT setuphandles.Delete[s] THEN res ¬ accessError;
s.data ¬ NIL;
RETURN [res]
};
SetupStandardParams: PUBLIC CIIPrivate.SetupStandardParamsProc = {
s.data.sSizeDevice ¬ sSizeDevice;
s.data.fSizeDevice ¬ fSizeDevice;
s.data.scanMode ¬ ScanModeTranslate[scanMode];
s.data.surfaceUnitsPerInchX ¬ surfaceUnitsPerInchX;
s.data.surfaceUnitsPerInchY ¬ surfaceUnitsPerInchY;
RETURN [ok]
};
CreateSetupHandle: PUBLIC PROC [
data: REF,
SetupArrayParamSize: CIIPrivate.SetupArrayParamSizeProc,
SetupIntParam: CIIPrivate.SetupIntParamProc,
SetupFloatParam: CIIPrivate.SetupFloatParamProc,
SetupNameParam: CIIPrivate.SetupNameParamProc,
CreateHandleFromRasters: CIIPrivate.CreateHandleFromRastersProc
] RETURNS [CIIPrivate.SetupHandle] = {
h: CIIPrivate.SetupHandle = NEW[CIIPrivate.SetupObjectRep[7]];
<< September 21, 1993 2:12:39 pm PDT >>
<< >>
h[0] ¬ CProcFromProc[SetupStandardParams];
h[1] ¬ CProcFromProc[SetupArrayParamSize];
h[2] ¬ CProcFromProc[SetupIntParam];
h[3] ¬ CProcFromProc[SetupFloatParam];
h[4] ¬ CProcFromProc[SetupNameParam];
h[5] ¬ CProcFromProc[CreateHandleFromRasters];
h[6] ¬ CProcFromProc[DestroySetupObject];
h.data ¬ NEW[CIIPrivate.SetupHandleDataRep ¬ [
data: data,
sSizeDevice: 0,
fSizeDevice: 0,
scanMode: [slow: right, fast: up],
surfaceUnitsPerInchX: 1,
surfaceUnitsPerInchY: 1
]];
[] ¬ RefTab.Insert[setuphandles, h, h];
RETURN [h]
};
handles: RefTab.Ref = RefTab.Create[];
MakeHandle: PUBLIC PROC [data: REF, SetOutputBuffers: SetOutputBuffersProc, SetSeparation: SetSeparationProc, SetColorTable: SetColorTableProc, Sync: SyncProc] RETURNS [Handle] = {
state: State = NARROW[data];
h: REF ObjectRep = NEW[ObjectRep[59]];
IF state.refTab # NIL THEN ERROR; -- That's my field, bub!
state.refTab ¬ RefTab.Create[];
h.data ¬ state;
-- Generated code:
<< October 28, 1993 12:22:43 pm PDT >>
h[0] ¬ CProcFromProc[Destroy];
h[1] ¬ CProcFromProc[DestroyColor];
h[2] ¬ CProcFromProc[DestroyColorOperator];
h[3] ¬ CProcFromProc[DestroyClipper];
h[4] ¬ CProcFromProc[DestroyFont];
h[5] ¬ CProcFromProc[SetMatrix];
h[6] ¬ CProcFromProc[GetMatrix];
h[7] ¬ CProcFromProc[GetInitialMatrix];
h[8] ¬ CProcFromProc[SetInitialMatrix];
h[9] ¬ CProcFromProc[MakeGrayColorOperator];
h[10] ¬ CProcFromProc[MakeRGBColorOperator];
h[11] ¬ CProcFromProc[MakeCMYKColorOperator];
h[12] ¬ CProcFromProc[MakeHighlightColorOperator];
h[13] ¬ CProcFromProc[MakeColor];
h[14] ¬ CProcFromProc[MakeSampledBlack];
h[15] ¬ CProcFromProc[SetColor];
h[16] ¬ CProcFromProc[SetGray];
h[17] ¬ CProcFromProc[SetRGB];
h[18] ¬ CProcFromProc[SetHSV];
h[19] ¬ CProcFromProc[SetCMYK];
h[20] ¬ CProcFromProc[GetColor];
h[21] ¬ CProcFromProc[MaskRectangle];
h[22] ¬ CProcFromProc[MaskFill];
h[23] ¬ CProcFromProc[Clip];
h[24] ¬ CProcFromProc[GetClipper];
h[25] ¬ CProcFromProc[SetClipper];
h[26] ¬ CProcFromProc[BuildClipperBegin];
h[27] ¬ CProcFromProc[BuildClipperEnd];
h[28] ¬ CProcFromProc[MaskStroke];
h[29] ¬ CProcFromProc[MaskBitmap];
h[30] ¬ CProcFromProc[MaskDeviceTrapezoid];
h[31] ¬ CProcFromProc[DestroyMaskProgram];
h[32] ¬ CProcFromProc[MakeMaskProgram];
h[33] ¬ CProcFromProc[MaskDeviceBoxes];
h[34] ¬ CProcFromProc[FindFont];
h[35] ¬ CProcFromProc[ModifyFont];
h[36] ¬ CProcFromProc[MakeFontAtom];
h[37] ¬ CProcFromProc[DoHardChar];
h[38] ¬ CProcFromProc[DoHardMetrics];
h[39] ¬ CProcFromProc[Show];
h[40] ¬ CProcFromProc[BufferedSeparationImage];
h[41] ¬ CProcFromProc[BufferedInterleavedImage];
h[42] ¬ CProcFromProc[StreamImage];
h[43] ¬ CProcFromProc[MaskStreamBits];
h[44] ¬ CProcFromProc[ApplyCCITTFacsimileDecompressionFilter];
h[45] ¬ CProcFromProc[MakeHalftoneProperties];
h[46] ¬ CProcFromProc[SetHalftoneProperties];
h[47] ¬ CProcFromProc[GetHalftoneProperties];
h[48] ¬ CProcFromProc[DestroyHalftoneProperties];
h[49] ¬ CProcFromProc[SetSeparation];
h[50] ¬ CProcFromProc[SetOutputBuffers];
h[51] ¬ CProcFromProc[SetColorTable];
h[52] ¬ CProcFromProc[MakeLookupTable];
h[53] ¬ CProcFromProc[DestroyLookupTable];
h[54] ¬ CProcFromProc[SetColorLookupTable];
h[55] ¬ CProcFromProc[GetColorLookupTable];
h[56] ¬ CProcFromProc[Sync];
h[57] ¬ CProcFromProc[RegisterCleanupObject];
h[58] ¬ CProcFromProc[UnRegisterCleanupObject];
[] ¬ RefTab.Insert[handles, h, h];
RETURN [h]
};
END.