~
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[]];
};
'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]
};