ImagerRasterImpl.mesa
Copyright © 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, November 1, 1985 9:31:41 am PST
Doug Wyatt, March 7, 1986 11:52:57 am PST
DIRECTORY
Basics USING [bitsPerWord, LongMult],
Imager USING [black, Box, ClassRep, Color, ColorOperator, Context, ContextRep, DoSave, DoSaveAll, Error, MaskBits, MaskRectangle, MaskRectangleI, metersPerInch, PixelArray, SetColor, SetXY, StateRep, Trans, white],
ImagerBackdoor USING [Clipper, Visibility],
ImagerBox USING [BoxFromRect],
ImagerCache USING [Ref],
ImagerDevice,
ImagerFont USING [Font, XChar, XStringProc],
ImagerFontPrivate USING [FontImpl, FontImplRep, MakeFontAtom],
ImagerManhattan USING [BoundingBox, Copy, CreateFromBox, Destroy, DestructiveClip, DestructiveDifference, DestructiveIntersection, Polygon],
ImagerPath USING [ArcToConics, ConicToCurves, MapOutline, Outline, PathProc],
ImagerPixelArray,
ImagerPrivate USING [Class, ClassRep],
ImagerRaster USING [FontTuner],
ImagerRasterPrivate USING [AndFlags, CharArrayRep, Data, DataRep, Flags, NotFlags, OrFlags, RasterShow, RasterShowText],
ImagerSample,
ImagerScanConverter USING [BoundingBox, ConvertToManhattanPolygon, ConvertToRuns, CreatePath, DevicePath],
ImagerState USING [ChangeFlags, notChanged, State, StateClip, StateClipRectangle, StateClipRectangleI, StateConcatT, StateCorrect, StateCorrectMask, StateCorrectSpace, StateDontCorrect, StateDoSave, StateGetClipper, StateGetColor, StateGetCP, StateGetFont, StateGetInt, StateGetReal, StateGetT, StateMaskUnderline, StateMove, StateRep, StateRotateT, StateScale2T, StateSetClipper, StateSetColor, StateSetCorrectMeasure, StateSetCorrectTolerance, StateSetFont, StateSetGray, StateSetInt, StateSetReal, StateSetSampledBlack, StateSetSampledColor, StateSetT, StateSetXY, StateSetXYRel, StateSpace, StateStartUnderline, StateTranslateT],
ImagerStroke USING [PathFromStroke],
ImagerTransformation USING [ApplyCat, ApplyPostConcat, ApplyPostTranslate, ApplyPreConcat, ApplyPreTranslate, ApplyTranslateTo, InverseTransform, InverseTransformRectangle, Rectangle, Rotate, Scale, Scale2, Transform, Transformation, TransformationRep],
Process USING [CheckForAbort],
Real USING [Fix, FScale, LargestNumber, Round],
RealFns USING [AlmostEqual, SqRt],
Rope USING [ROPE],
Vector2 USING [Add, Sub, Mul, Length, Div, Square, VEC],
VM USING [AddressForPageNumber, Free, Interval, PagesForWords, SimpleAllocate];
ImagerRasterImpl: CEDAR PROGRAM
IMPORTS Basics, Imager, ImagerBox, ImagerFontPrivate, ImagerManhattan, ImagerManhattanExtras, ImagerMask, ImagerPath, ImagerPixelArray, ImagerRasterPrivate, ImagerSample, ImagerScanConverter, ImagerState, ImagerStroke, ImagerTransformation, Process, Real, RealFns, Vector2, VM
EXPORTS Imager, ImagerBackdoor, ImagerFont, ImagerRaster, ImagerRasterPrivate
~ BEGIN OPEN ImagerState, ImagerRasterPrivate;
Class: TYPE ~ ImagerPrivate.Class;
ClassRep: PUBLIC TYPE ~ ImagerPrivate.ClassRep; -- export to Imager.ClassRep
State: TYPE ~ ImagerState.State;
StateRep: PUBLIC TYPE ~ ImagerState.StateRep; -- export to Imager.StateRep
ROPE: TYPE ~ Rope.ROPE;
CharMask: TYPE ~ ImagerDevice.CharMask;
Clipper: TYPE ~ ImagerBackdoor.Clipper;
Color: TYPE ~ Imager.Color;
ColorOperator: TYPE ~ Imager.ColorOperator;
Context: TYPE ~ Imager.Context;
Device: TYPE ~ ImagerDevice.Device;
BoxAction: TYPE ~ ImagerDevice.BoxAction;
DevicePath: TYPE ~ ImagerScanConverter.DevicePath;
DeviceRectangle: TYPE ~ ImagerPixelMap.DeviceRectangle;
Font: TYPE ~ ImagerFont.Font;
ManhattanPolygon: TYPE ~ ImagerManhattan.Polygon;
PathProc: TYPE ~ ImagerPath.PathProc;
Outline: TYPE ~ ImagerPath.Outline;
PixelArray: TYPE ~ Imager.PixelArray;
Rectangle: TYPE ~ ImagerTransformation.Rectangle;
Transformation: TYPE ~ ImagerTransformation.Transformation;
TransformationRep: TYPE ~ ImagerTransformation.TransformationRep;
VEC: TYPE ~ Vector2.VEC;
XChar: TYPE ~ ImagerFont.XChar;
XStringProc: TYPE ~ ImagerFont.XStringProc;
FontImpl: TYPE ~ ImagerFontPrivate.FontImpl;
FontImplRep: PUBLIC TYPE ~ ImagerFontPrivate.FontImplRep; -- export to to ImagerFont
Create: PUBLIC PROC [device: Device, pixelUnits: BOOL,
fontCache: ImagerCache.Ref, rastWeight: REAL, fontTuner: ImagerRaster.FontTuner, class: Class
] RETURNS [Context] ~ {
data: Data ~ NEW[DataRep ← [device: device]];
state: State ~ NEW[StateRep ← []];
metersToSurface: VEC ~ device.surfaceUnitsPerInch.Div[Imager.metersPerInch];
data.rastWeight ← rastWeight;
data.fontTuner ← fontTuner;
data.viewToDevice ← ImagerTransformation.Scale[1];
data.clientToDevice ← ImagerTransformation.Scale[1];
data.maskToDevice ← ImagerTransformation.Scale[1];
data.charToDevice ← ImagerTransformation.Scale[1];
data.fontCache ← fontCache;
data.charArray ← NEW[CharArrayRep ← ALL[NIL]];
DViewReset[data];
IF pixelUnits THEN state.T ← ImagerTransformation.Scale[1]
ELSE state.T ← ImagerTransformation.Scale2[metersToSurface];
state.color ← Imager.black;
IF class=NIL THEN class ← rasterClass;
RETURN[NEW[Imager.ContextRep ← [class: class, state: state, data: data]]];
};
CreateClass: PUBLIC PROC [type: ATOM] RETURNS [Class] ~ {
class: Class ~ NEW[ClassRep ← rasterClass^];
class.type ← type;
RETURN[class];
};
ValidateClientToDevice: PROC [data: Data, state: State] ~ {
data.clientToDevice.ApplyCat[state.T, data.viewToDevice];
data.valid.clientToDevice ← TRUE;
};
ValidateFontInfo: PROC [data: Data, state: State] ~ {
font: Font ~ state.font;
IF font = NIL THEN ERROR Imager.Error[[code: $noFont, explanation: "Failed to set font before calling Show."]]
ELSE {
impl: FontImpl ~ font.impl;
IF NOT data.valid.clientToDevice THEN ValidateClientToDevice[data, state];
data.charToDevice^ ← data.clientToDevice^;
data.charToDevice.ApplyTranslateTo[[0, 0]];
data.charToDevice.ApplyPreConcat[font.charToClient];
data.fontAtom ← ImagerFontPrivate.MakeFontAtom[impl.typeface, data.charToDevice];
data.valid.fontInfo ← TRUE;
};
};
ValidateClientClipper: PROC [data: Data, state: State] ~ {
cc: ImagerManhattan.Polygon ← NIL;
ImagerManhattan.Destroy[data.clientClipMask];
cc ← ImagerManhattan.Copy[data.viewClipMask];
IF data.specialClipPresent THEN {
cc ← ImagerManhattan.DestructiveClip[cc, data.specialClipRect];
};
FOR each: Clipper ← state.clipper, each.rest UNTIL each=NIL DO
outline: Outline ~ each.first.outline;
exclude: BOOL ~ each.first.exclude;
path: PathProc ~ { ImagerPath.MapOutline[outline: outline,
moveTo: moveTo, lineTo: lineTo, curveTo: curveTo,
conicTo: conicTo, arcTo: arcTo] };
this: ManhattanPolygon;
data.devicePath ← ImagerScanConverter.CreatePath[path: path,
transformation: data.viewToDevice, clipBox: data.viewClipBox,
scratch: data.devicePath];
this ← ImagerScanConverter.ConvertToManhattanPolygon[
devicePath: data.devicePath, oddWrap: outline.oddWrap,
clipBox: data.viewClipBox];
cc ← CombineManhattan[cc, this, exclude];
ImagerManhattan.Destroy[this];
ENDLOOP;
data.clientClipMask ← cc;
data.clientClipBox ← ImagerManhattan.BoundingBox[cc];
data.clientClipBoxOnly ← (cc=NIL OR cc.rest=NIL);
data.valid.clientClipper ← TRUE;
};
ValidateColor: PROC [data: Data, state: State] ~ {
device: Device ~ data.device;
device.class.SetColor[device, state.color, data.viewToDevice];
data.valid.deviceColor ← TRUE;
};
ValidatePriority: PROC [data: Data, state: State] ~ {
device: Device ~ data.device;
device.class.SetPriority[device, state.np.priorityImportant#0];
data.valid.devicePriority ← TRUE;
};
NoteStateChanges: PUBLIC PROC [data: Data, state: State] ~ {
changed: ImagerState.ChangeFlags ~ state.changed;
state.changed ← ImagerState.notChanged;
IF changed.T THEN data.valid.clientToDevice ← data.valid.fontInfo ← FALSE;
IF changed.color THEN data.valid.deviceColor ← FALSE;
IF changed.priority THEN data.valid.devicePriority ← FALSE;
IF changed.clipper THEN data.valid.clientClipper ← FALSE;
IF changed.font THEN data.valid.fontInfo ← FALSE;
};
ValidateIfNeeded: PUBLIC PROC [data: Data, state: State, needs: Flags] ~ {
fix: Flags ~ AndFlags[needs, NotFlags[data.valid]];
IF fix.clientToDevice THEN ValidateClientToDevice[data, state];
IF fix.deviceColor THEN ValidateColor[data, state];
IF fix.devicePriority THEN ValidatePriority[data, state];
IF fix.clientClipper THEN ValidateClientClipper[data, state];
IF fix.fontInfo THEN ValidateFontInfo[data, state];
IF AndFlags[data.valid, needs]#needs THEN ERROR;
};
Validate: PROC [data: Data, state: State, needs: Flags] ~ INLINE {
IF state.changed#ImagerState.notChanged THEN NoteStateChanges[data, state];
IF AndFlags[data.valid, needs]#needs THEN ValidateIfNeeded[data, state, needs];
};
Verify: PROC [data: Data, needs: Flags] ~ INLINE {
IF AndFlags[data.valid, needs]#needs THEN ERROR;
};
EasyTransformation: PROC [m: Transformation] RETURNS [BOOL] ~ INLINE {
RETURN[m.form>=3 AND m.integerTrans];
};
TransformBox: PROC [m: Transformation, x, y, w, h: INTEGER, clip: Box ← maxBox]
RETURNS [Box] ~ {
IF EasyTransformation[m] THEN {
x0: INT ~ INT[x]; y0: INT ~ INT[y]; x1: INT ~ x0+INT[w]; y1: INT ~ y0+INT[h];
ts: INT ~ INT[m.tx]; tf: INT ~ INT[m.ty];
s0, s1, f0, f1: INT;
box: Box ← clip;
SELECT m.form FROM
3 => { s0 ← ts + x0; s1 ← ts + x1; f0 ← tf + y0; f1 ← tf + y1 };
4 => { s0 ← ts + x0; s1 ← ts + x1; f0 ← tf - y0; f1 ← tf - y1 };
5 => { s0 ← ts - x0; s1 ← ts - x1; f0 ← tf + y0; f1 ← tf + y1 };
6 => { s0 ← ts - x0; s1 ← ts - x1; f0 ← tf - y0; f1 ← tf - y1 };
7 => { s0 ← ts + y0; s1 ← ts + y1; f0 ← tf + x0; f1 ← tf + x1 };
8 => { s0 ← ts + y0; s1 ← ts + y1; f0 ← tf - x0; f1 ← tf - x1 };
9 => { s0 ← ts - y0; s1 ← ts - y1; f0 ← tf + x0; f1 ← tf + x1 };
10 => { s0 ← ts - y0; s1 ← ts - y1; f0 ← tf - x0; f1 ← tf - x1 };
ENDCASE => ERROR;
IF s0>s1 THEN { s2: INT ~ s0; s0 ← s1; s1 ← s2 };
IF f0>f1 THEN { f2: INT ~ f0; f0 ← f1; f1 ← f2 };
IF s0>box.max.s THEN s0 ← s1 ← box.max.s;
IF s1<box.min.s THEN s0 ← s1 ← box.min.s;
IF f0>box.max.f THEN f0 ← f1 ← box.max.f;
IF f1<box.min.f THEN f0 ← f1 ← box.min.f;
IF s0>box.min.s THEN box.min.s ← s0;
IF s1<box.max.s THEN box.max.s ← s1;
IF f0>box.min.f THEN box.min.f ← f0;
IF f1<box.max.f THEN box.max.f ← f1;
RETURN[Box];
};
ERROR;
};
TestBox: PROC [m: Transformation, x, y, w, h: INTEGER, clip: Box ← maxBox]
RETURNS [Visibility] ~ {
IF EasyTransformation[m] THEN {
x0: INT ~ INT[x]; y0: INT ~ INT[y]; x1: INT ~ x0+INT[w]; y1: INT ~ y0+INT[h];
ts: INT ~ INT[m.tx]; tf: INT ~ INT[m.ty];
s0, s1, f0, f1, smin, fmin, smax, fmax: INT;
box: Box ~ clip;
SELECT m.form FROM
3 => { s0 ← ts + x0; s1 ← ts + x1; f0 ← tf + y0; f1 ← tf + y1 };
4 => { s0 ← ts + x0; s1 ← ts + x1; f0 ← tf - y0; f1 ← tf - y1 };
5 => { s0 ← ts - x0; s1 ← ts - x1; f0 ← tf + y0; f1 ← tf + y1 };
6 => { s0 ← ts - x0; s1 ← ts - x1; f0 ← tf - y0; f1 ← tf - y1 };
7 => { s0 ← ts + y0; s1 ← ts + y1; f0 ← tf + x0; f1 ← tf + x1 };
8 => { s0 ← ts + y0; s1 ← ts + y1; f0 ← tf - x0; f1 ← tf - x1 };
9 => { s0 ← ts - y0; s1 ← ts - y1; f0 ← tf + x0; f1 ← tf + x1 };
10 => { s0 ← ts - y0; s1 ← ts - y1; f0 ← tf - x0; f1 ← tf - x1 };
ENDCASE => ERROR;
IF s0>s1 THEN { s2: INT ~ s0; s0 ← s1; s1 ← s2 };
IF f0>f1 THEN { f2: INT ~ f0; f0 ← f1; f1 ← f2 };
IF s0>=box.max.s THEN RETURN[none];
IF s1<=box.min.s THEN RETURN[none];
IF f0>=box.max.f THEN RETURN[none];
IF f1<=box.min.f THEN RETURN[none];
IF s0<box.min.s THEN RETURN[part];
IF s1>box.max.s THEN RETURN[part];
IF f0<box.min.f THEN RETURN[part];
IF f1>box.max.f THEN RETURN[part];
RETURN[all];
};
ERROR;
};
boxesFromPathNeeds: Flags ~ [clientClipper: TRUE];
PathToBoxes: PROC [data: Data, path: PathProc,
oddWrap: BOOLFALSE, transformation: Transformation ← NIL,
action: PROC [boxes: BoxGenerator, bounds: Box]
] ~ {
clipBox: Box ~ data.clientClipBox;
clipMask: ManhattanPolygon ~ data.clientClipMask;
devicePath: DevicePath ~ data.devicePath ← ImagerScanConverter.CreatePath[path: path,
transformation: transformation, clipBox: clipBox, scratch: data.devicePath];
bounds: Box ~ ImagerScanConverter.BoundingBox[devicePath, clipBox];
boxes: BoxGenerator ~ {
IF clipMask.rest=NIL THEN {
ImagerScanConverter.ConvertToBoxes[devicePath: devicePath, oddWrap: oddWrap,
clipBox: bounds, boxAction: boxAction, runs: runs];
}
ELSE {
rem: ManhattanPolygon ← clipMask;
clipAction: BoxAction ~ {
WHILE rem#NIL AND rem.first.max.s<=box.min.s DO rem ← rem.rest ENDLOOP;
FOR l: LIST OF DeviceRectangle ← rem, l.rest UNTIL l=NIL OR l.first.min.s>=box.max.s DO
clippedBox: Box ~ l.first.Intersect[box];
IF clippedBox.Nonempty THEN boxAction[clippedBox];
ENDLOOP;
};
ImagerScanConverter.ConvertToBoxes[devicePath: devicePath, oddWrap: oddWrap,
clipBox: bounds, boxAction: clipAction, runs: runs];
};
};
Verify[data, boxesFromPathNeeds];
Process.CheckForAbort[];
IF bounds.Nonempty THEN action[boxes, bounds];
};
BoxToBoxes: PROC [data: Data, box: Box,
action: PROC [boxes: BoxGenerator, bounds: Box]
] ~ {
bounds: Box ~ data.clientClipBox.Intersect[box];
boxes: BoxGenerator ~ {
clipMask: ManhattanPolygon ~ data.clientClipMask;
IF clipMask.rest=NIL AND NOT runs THEN boxAction[bounds]
ELSE ImagerManhattan.Clip[clipMask, bounds, boxAction, runs];
};
Verify[data, boxesFromPathNeeds];
Process.CheckForAbort[];
IF Nonempty[bounds] THEN action[boxes, bounds];
};
maskPathNeeds: Flags ~ OrFlags[boxesFromPathNeeds, [deviceColor: TRUE, devicePriority: TRUE]];
MaskPath: PROC [data: Data, path: PathProc, oddWrap: BOOLFALSE,
transformation: Transformation ← NIL] ~ {
maskPathAction: PROC [bounds: Box, boxes: BoxGenerator] ~ {
device: Device ~ data.device;
device.class.MaskBoxes[device: device, bounds: bounds, boxes: boxes];
};
Verify[data, maskPathNeeds];
PathToBoxes[data: data, path: path, oddWrap: oddWrap,
transformation: transformation, action: maskPathAction];
};
MaskBox: PROC [data: Data, box: Box] ~ {
maskBoxAction: PROC [boxes: BoxGenerator, bounds: Box] ~ {
device: Device ~ data.device;
device.class.MaskBoxes[device: device, boxes: boxes, bounds: bounds];
};
Verify[data, maskPathNeeds];
BoxToBoxes[data: data, box: box, action: maskBoxAction];
};
maskNeeds: Flags ~ OrFlags[maskPathNeeds, [clientToDevice: TRUE]];
RasterMaskFill: PROC [context: Context, path: PathProc, oddWrap: BOOL] ~ {
state: State ~ context.state;
IF state.np.noImage=0 THEN {
data: Data ~ NARROW[context.data];
Validate[data, state, maskNeeds];
MaskPath[data: data, path: path, oddWrap: oddWrap, transformation: data.clientToDevice];
};
};
specialRectangles: BOOLTRUE;
RasterMaskRectangle: PROC [context: Context, r: Rectangle] ~ {
state: State ~ context.state;
IF state.np.noImage=0 THEN {
data: Data ~ NARROW[context.data];
Validate[data, state, maskNeeds];
IF specialRectangles AND data.clientToDevice.form#0 THEN {
clientToDevice: Transformation ~ data.clientToDevice;
clip: Box ~ data.clientClipBox;
p0: VEC ~ ImagerTransformation.Transform[clientToDevice, [r.x, r.y]];
p1: VEC ~ ImagerTransformation.Transform[clientToDevice, [r.x+r.w, r.y+r.h]];
s0: INT ← Real.Fix[MAX[MIN[p0.x+0.5, clip.max.s], clip.min.s]];
s1: INT ← Real.Fix[MAX[MIN[p1.x+0.5, clip.max.s], clip.min.s]];
f0: INT ← Real.Fix[MAX[MIN[p0.y+0.5, clip.max.f], clip.min.f]];
f1: INT ← Real.Fix[MAX[MIN[p1.y+0.5, clip.max.f], clip.min.f]];
Process.CheckForAbort[];
IF s1<s0 THEN { temp: INT ~ s0; s0 ← s1; s1 ← temp };
IF f1<f0 THEN { temp: INT ~ f0; f0 ← f1; f1 ← temp };
IF s0<s1 AND f0<f1 THEN MaskBox[data, [min: [s: s0, f: f0], max: [s: s1, f: f1]]];
}
ELSE {
rectanglePath: PathProc ~ {
moveTo[[r.x, r.y]];
lineTo[[r.x+r.w, r.y]];
lineTo[[r.x+r.w, r.y+r.h]];
lineTo[[r.x, r.y+r.h]];
};
MaskPath[data: data, path: rectanglePath, transformation: data.clientToDevice];
};
};
};
RasterMaskRectangleI: PROC [context: Context, x, y, w, h: INTEGER] ~ {
state: State ~ context.state;
IF state.np.noImage=0 THEN {
data: Data ~ NARROW[context.data];
Validate[data, state, maskNeeds];
IF data.clientToDevice.form>=3 AND data.clientToDevice.integerTrans THEN {
box: Box ~ TransformBox[data.clientToDevice, x, y, w, h, data.clientClipBox];
MaskBox[data, box];
}
ELSE RasterMaskRectangle[context, [x: x, y: y, w: w, h: h]];
};
};
RasterMaskUnderline: PROC [context: Context, dy, h: REAL] ~ {
state: State ~ context.state;
USING [T, color, clipper, underlineStart, noImage, priorityImportant]
IF state.np.noImage=0 THEN {
end: VEC ~ state.T.InverseTransform[state.p.cp]; -- current position (client space)
start: VEC ~ [state.np.underlineStart, end.y-dy-h]; -- corner of underline (client space)
underline: PROC ~ {
Imager.SetXY[context, start];
Imager.Trans[context];
Imager.MaskRectangle[context, [0, 0, end.x-start.x, h]];
};
Imager.DoSaveAll[context, underline];
};
};
RasterMaskStroke: PROC [context: Context, path: PathProc, closed: BOOLFALSE] ~ {
state: State ~ context.state;
USING [T, color, clipper, strokeWidth, strokeStyle, noImage, priorityImportant]
IF state.np.noImage=0 THEN {
data: Data ~ NARROW[context.data];
strokePath: PathProc ~ {
ImagerStroke.PathFromStroke[path: path, closed: closed, m: data.clientToDevice,
width: state.np.strokeWidth, end: state.np.strokeEnd, joint: state.np.strokeJoint,
moveTo: moveTo, lineTo: lineTo, conicTo: conicTo, curveTo: curveTo];
};
Validate[data, state, maskNeeds];
MaskPath[data: data, path: strokePath];
};
};
RasterMaskVector: PROC [context: Context, p1, p2: VEC] ~ {
vectorPath: PathProc ~ { moveTo[p1]; lineTo[p2] };
RasterMaskStroke[context: context, path: vectorPath, closed: FALSE];
};
RasterMaskDashedStroke: PROC [context: Context, path: PathProc,
patternLen: NAT, pattern: PROC [i: NAT] RETURNS [REAL], offset, length: REAL] ~ {
dashedPath: PathProc ~ {
ImagerStroke.Dashes[path: path,
patternLen: patternLen, pattern: pattern, offset: offset, length: length,
moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, conicTo: conicTo
];
};
RasterMaskStroke[context, dashedPath];
};
bitsPerWord: NAT ~ Basics.bitsPerWord;
SMul: PROC [a: INTEGER, b: INTEGER] RETURNS [INT] ~ INLINE {RETURN [IF a#0 THEN Smul[a,b] ELSE 0]};
Smul: PROC [a: INTEGER, b: INTEGER] RETURNS [INT] ~ {
Overflow cannot happen.
HighBit: PROC [a: INTEGER] RETURNS [[0..1]] ~ INLINE {
RETURN [LOOPHOLE[a, PACKED ARRAY [0..Basics.bitsPerWord) OF [0..1]][0]];
};
Card: PROC [i: INTEGER] RETURNS [NAT] ~ INLINE {RETURN [LOOPHOLE[i]]};
SELECT HighBit[a]*2+HighBit[b] FROM
0 => RETURN [Basics.LongMult[Card[a], Card[b]]];
1 => RETURN [-Basics.LongMult[Card[a], Card[-b]]];
2 => RETURN [-Basics.LongMult[Card[-a], Card[b]]];
3 => RETURN [Basics.LongMult[Card[-a], Card[-b]]];
ENDCASE => ERROR;
};
worryReal: REALLAST[NAT]*0.5;
IsAllInteger: PROC [m: Transformation] RETURNS [BOOL] ~ {
Is: PROC [r: REAL] RETURNS [BOOL] ~ {
IF r IN [-worryReal..worryReal] THEN {
ir: INT ~ Real.Round[r];
IF r = ir THEN RETURN [TRUE];
IF RealFns.AlmostEqual[r, Real.Round[r], -18] THEN RETURN [TRUE];
};
RETURN [FALSE];
};
RETURN [Is[m.a] AND Is[m.b] AND Is[m.c] AND Is[m.d] AND Is[m.e] AND Is[m.f]];
};
Ceiling: PROC [r: REAL] RETURNS [i: INT] ~ {
i ← Real.Round[r];
IF i < r THEN i ← i + 1;
};
SF: TYPE ~ RECORD [s, f: INT];
ClippedBounds: PROC [clipBox: DeviceBox, p0, p1: SF] RETURNS [DeviceBox] ~ {
Computes bounding box of p0 and p1, clipped against clipBox.
IF p0.s > p1.s THEN {t: INT ← p0.s; p0.s ← p1.s; p1.s ← t};
IF p0.f > p1.f THEN {t: INT ← p0.f; p0.f ← p1.f; p1.f ← t};
p0.s ← MAX[p0.s, clipBox.smin];
p0.f ← MAX[p0.f, clipBox.fmin];
p1.s ← MIN[p1.s, clipBox.smax];
p1.f ← MIN[p1.f, clipBox.fmax];
IF p0.s < p1.s AND p0.f < p1.f THEN RETURN [[smin: p0.s, fmin: p0.f, smax: p1.s, fmax: p1.f]]
ELSE RETURN [[smin: clipBox.smin, fmin: clipBox.fmin, smax: clipBox.smin, fmax: clipBox.fmin]];
};
specialMaskBits: BOOLTRUE;
MaskSampledBits: PROC [data: Data, base: LONG POINTER, wordsPerLine: NAT,
sMin, fMin: NAT, sSize, fSize: NAT, maskToDevice: Transformation, constant: BOOL] ~ {
device: Device ~ data.device;
SELECT TRUE FROM
maskToDevice.form=3 AND maskToDevice.integerTrans AND device.class.MaskBits#NIL => {
smin: INT ~ maskToDevice.tx; smax: INT ~ smin+sSize;
fmin: INT ~ maskToDevice.ty; fmax: INT ~ fmin+fSize;
box: DeviceBox ← data.clientClipBox;
boxes: PROC[action: PROC[DeviceBox]] ~ {
ClipBoxToMask[box: box, mask: data.clientClipMask, action: action];
};
IF smin<box.smax AND smax>box.smin AND fmin<box.fmax AND fmax>box.fmin THEN {
IF box.smin<smin THEN box.smin ← smin; IF box.smax>smax THEN box.smax ← smax;
IF box.fmin<fmin THEN box.fmin ← fmin; IF box.fmax>fmax THEN box.fmax ← fmax;
device.class.MaskBits[device: device, srcBase: base, srcWordsPerLine: wordsPerLine,
ts: smin-sMin, tf: fmin-fMin, boxes: boxes];
};
};
specialMaskBits AND maskToDevice.form#0 AND IsAllInteger[maskToDevice] AND constant => {
a: INTEGER ~ Real.Round[maskToDevice.a];
b: INTEGER ~ Real.Round[maskToDevice.b];
c: INTEGER ~ maskToDevice.tx;
d: INTEGER ~ Real.Round[maskToDevice.d];
e: INTEGER ~ Real.Round[maskToDevice.e];
f: INTEGER ~ maskToDevice.ty;
SF: TYPE ~ RECORD [s, f: INT];
Map: PROC [x, y: INTEGER] RETURNS [SF] ~ {
RETURN [[SMul[a, x] + SMul[b, y] + c, SMul[d, x] + SMul[e, y] + f]];
};
box: DeviceBox ~ ClippedBounds[data.clientClipBox, [c, f], Map[sSize, fSize]];
boxes: PROC[action: PROC[DeviceBox]] ~ {
myAction: PROC[clipBox: DeviceBox] ~ {
run: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ {
clippedBox: DeviceBox ~ ClippedBounds[clipBox, Map[sMin, fMin], Map[sMin+1, fMin+fSize]];
IF clippedBox.smin # clippedBox.smax THEN action[clippedBox];
};
sb: Imager.Box ~ ImagerBox.BoxFromRect[
ImagerTransformation.InverseTransformRectangle[maskToDevice, [
x: clipBox.smin,
y: clipBox.fmin,
w: clipBox.smax-clipBox.smin,
h: clipBox.fmax-clipBox.fmin
]]
];
srcBox: DeviceBox ~ ClippedBounds[
clipBox: [smin: 0, fmin: 0, smax: sSize, fmax: fSize],
p0: [Real.Fix[sb.xmin], Real.Fix[sb.ymin]],
p1: [Ceiling[sb.xmax], Ceiling[sb.ymax]]
];
ImagerMask.RunsFromBits[base: base, wordsPerLine: wordsPerLine, sBits: srcBox.smin+sMin, fBits: srcBox.fmin+fMin, sSize: srcBox.smax-srcBox.smin, fSize: srcBox.fmax-srcBox.fmin, sRuns: srcBox.smin, fRuns: srcBox.fmin, run: run];
};
ClipBoxToMask[box: box, mask: data.clientClipMask, action: myAction];
};
device.class.MaskBoxes[device: device, bounds: box, boxes: boxes];
};
ENDCASE => HardMaskSampledBits[data, base, wordsPerLine, sMin, fMin, sSize, fSize, maskToDevice];
};
HardMaskSampledBits: PROC [data: Data, base: LONG POINTER, wordsPerLine: NAT,
sMin, fMin: NAT, sSize, fSize: NAT, maskToDevice: Transformation] ~ {
sampler: ImagerSample.Sampler ~ NEW[ImagerSample.SamplerRep ← []];
maskBitsAction: PROC [boxes: BoxGenerator, bounds: Box] ~ {
device: Device ~ data.device;
buffer: ImagerSample.SampleBuffer ~ ImagerSample.ObtainScratchBuffer[
iSize: 1, jSize: bounds.fmax-bounds.fmin];
maskBitsBoxes: BoxGenerator ~ {
maskBitsBox: BoxAction ~ {
state: {off, on} ← off;
run: Box ← box;
ImagerSample.GetPointSamples[sampler: sampler, s: sMin, f: fMin,
buffer: buffer, bi: 0, bj: 0, count: fSize];
FOR f: NAT IN[box.min.f..box.max.f) DO
value: ImagerSample.Sample ~ buffer[f-box.min.f];
SELECT state FROM
off => IF value#0 THEN { run.min.f ← f; state ← on };
on => IF value=0 THEN { run.max.f ← f; boxAction[run]; state ← off };
ENDCASE => ERROR;
ENDLOOP;
IF state=on THEN { run.max.f ← box.max.f; boxAction[run] };
};
boxes[maskBitsBox];
};
ImagerSample.SetSamplerPosition[sampler: sampler,
m: maskToDevice, s: bounds.smin, f: bounds.fmin];
device.class.MaskBoxes[device: device, boxes: maskBitsBoxes, bounds: bounds];
ImagerSample.ReleaseScratchBuffer[buffer];
};
maskBoundary: PathProc ~ {
moveTo[[0, 0]]; lineTo[[sSize, 0]]; lineTo[[sSize, fSize]]; lineTo[[0, fSize]];
};
sampler.base ← base;
sampler.wordsPerLine ← wordsPerLine;
sampler.bitsPerSample ← 1;
sampler.sMin ← sMin;
sampler.fMin ← fMin;
sampler.sSize ← sSize;
sampler.fSize ← fSize;
ImagerSample.SetSamplerIncrements[sampler, maskToDevice];
PathToBoxes[data: data, path: maskBoundary,
transformation: maskToDevice, action: maskBitsAction];
};
bitsToClient: Transformation ~ ImagerTransformation.SFToXY[scanMode: [xx], sSize: 0, fSize: 0];
RasterMaskBits: PROC [context: Context, bits: SampleMap, box: Box ← maxBox,
tx, ty: INTEGER ← 0] ~ {
state: State ~ context.state;
IF state.np.noImage=0 THEN {
data: Data ~ NARROW[context.data];
maskToDevice: Transformation ~ data.maskToDevice;
Validate[data, state, maskNeeds];
maskToDevice^ ← bitsToClient^;
maskToDevice.ApplyPostTranslate[[tx, ty]];
maskToDevice.ApplyPostConcat[data.clientToDevice];
MaskSampledBits[data: data, base: base, wordsPerLine: wordsPerLine,
sMin: sMin, fMin: fMin, sSize: sSize, fSize: fSize, maskToDevice: maskToDevice, constant: state.color.tag = constant];
};
};
RasterDrawBits: PROC [context: Context, base: LONG POINTER, wordsPerLine: NAT,
sMin, fMin: NAT ← 0, sSize, fSize: NAT, tx, ty: INTEGER] ~ {
drawBitsAction: PROC ~ {
Imager.SetColor[context: context, color: Imager.white];
Imager.MaskRectangleI[context: context, x: tx, y: ty, w: fSize, h: -sSize];
Imager.SetColor[context: context, color: Imager.black];
Imager.MaskBits[context: context, base: base, wordsPerLine: wordsPerLine,
sMin: sMin, fMin: fMin, sSize: sSize, fSize: fSize, tx: tx, ty: ty];
};
state: State ~ context.state;
IF state.np.noImage=0 THEN {
data: Data ~ NARROW[context.data];
maskToDevice: Transformation ~ data.maskToDevice;
Validate[data, state, maskNeeds];
maskToDevice^ ← bitsToClient^;
maskToDevice.ApplyPostTranslate[[tx, ty]];
maskToDevice.ApplyPostConcat[data.clientToDevice];
IF maskToDevice.form=3 AND maskToDevice.integerTrans AND data.device.class.DrawBits # NIL THEN {
smin: INT ~ maskToDevice.tx; smax: INT ~ smin+sSize;
fmin: INT ~ maskToDevice.ty; fmax: INT ~ fmin+fSize;
box: DeviceBox ← data.clientClipBox;
boxes: PROC[action: PROC[DeviceBox]] ~ {
ClipBoxToMask[box: box, mask: data.clientClipMask, action: action];
};
IF smin<box.smax AND smax>box.smin AND fmin<box.fmax AND fmax>box.fmin THEN {
device: Device ~ data.device;
IF box.smin<smin THEN box.smin ← smin; IF box.smax>smax THEN box.smax ← smax;
IF box.fmin<fmin THEN box.fmin ← fmin; IF box.fmax>fmax THEN box.fmax ← fmax;
device.class.DrawBits[device: device, srcBase: base, srcWordsPerLine: wordsPerLine,
ts: smin-sMin, tf: fmin-fMin, boxes: boxes];
};
}
ELSE Imager.DoSave[context, drawBitsAction];
};
};
RasterMaskPixel: PROC [context: Context, pa: PixelArray] ~ {
state: State ~ context.state;
IF pa.samplesPerPixel=1 THEN NULL
ELSE ERROR Imager.Error[[code: $illegalPixelMask,
explanation: "MaskPixel argument must have one sample per pixel."]];
IF ImagerPixelArray.MaxSampleValue[pa, 0]=1 THEN NULL
ELSE ERROR Imager.Error[[code: $illegalPixelMask,
explanation: "MaskPixel argument must have one bit per sample."]];
IF state.np.noImage=0 THEN TRUSTED {
rast: NAT ~ (pa.fSize+bitsPerWord)/bitsPerWord;
words: INT ~ Basics.LongMult[pa.sSize, rast];
vm: VM.Interval ~ VM.SimpleAllocate[VM.PagesForWords[words]];
pointer: LONG POINTER ~ VM.AddressForPageNumber[vm.page];
DoMask: UNSAFE PROC ~ {
data: Data ~ NARROW[context.data];
maskToDevice: Transformation ~ data.maskToDevice;
Validate[data, state, maskNeeds];
maskToDevice.ApplyCat[pa.m, data.clientToDevice];
ImagerPixelArray.UnsafeGetBits[pa: pa, i: 0, s: 0, f: 0,
dst: [word: pointer, bit: 0], dstBpl: rast*bitsPerWord,
width: pa.fSize, height: pa.sSize];
MaskSampledBits[data: data,
base: pointer, wordsPerLine: rast,
sMin: 0, fMin: 0, sSize: pa.sSize, fSize: pa.fSize,
maskToDevice: maskToDevice, constant: state.color.tag = constant];
};
DoMask[ ! UNWIND => VM.Free[vm]];
VM.Free[vm];
};
};
RasterGetBounds: PROC [context: Context] RETURNS [Rectangle] ~ {
state: State ~ context.state;
data: Data ~ NARROW[context.data];
Validate[data, state, [clientToDevice: TRUE, clientClipper: TRUE]];
RETURN[data.clientToDevice.InverseTransformRectangle[[
x: data.clientClipRect.sMin, y: data.clientClipRect.fMin,
w: data.clientClipRect.sSize, h: data.clientClipRect.fSize
]]];
};
DViewReset: PROC [data: Data] ~ {
data.viewToDevice^ ← data.device.surfaceToDevice^;
data.viewClipBox ← DeviceRectangleFromDeviceBox[data.device.box];
ImagerManhattan.Destroy[data.viewClipMask];
data.viewClipMask ← ImagerManhattan.CreateFromBox[data.viewClipBox];
data.valid.clientToDevice ← FALSE;
data.valid.clientClipper ← FALSE;
data.valid.fontInfo ← FALSE;
data.valid.deviceColor ← FALSE;
};
DViewTranslate: PROC [data: Data, x, y: INTEGER] ~ {
data.viewToDevice.ApplyPreTranslate[[x, y]];
data.valid.clientToDevice ← FALSE;
data.valid.clientClipper ← FALSE;
data.valid.deviceColor ← FALSE;
Note that translation doesn't invalidate charToDevice
};
DViewClipRectangleI: PROC [data: Data, x, y, w, h: INTEGER, exclude: BOOL] ~ {
viewToDevice: Transformation ~ data.viewToDevice;
IF viewToDevice.form=9 AND viewToDevice.integerTrans THEN {
old: ManhattanPolygon ~ data.viewClipMask;
smin: INTEGER ~ viewToDevice.tx-MAX[y, y+h];
fmin: INTEGER ~ viewToDevice.ty+MIN[x, x+w];
rect: DeviceRectangle ~ [sMin: smin, fMin: fmin, sSize: ABS[h], fSize: ABS[w]];
IF exclude THEN {
t: ManhattanPolygon ~ ImagerManhattan.CreateFromBox[rect];
data.viewClipMask ← ImagerManhattanExtras.DestructiveDifference[data.viewClipMask, t];
ImagerManhattan.Destroy[t];
}
ELSE data.viewClipMask ← ImagerManhattanExtras.DestructiveClip[data.viewClipMask, rect];
data.viewClipBox ← ImagerManhattan.BoundingBox[data.viewClipMask];
data.valid.clientClipper ← FALSE;
}
ELSE {
path: PathProc ~ {
moveTo[[x, y]];
lineTo[[x+w, y]];
lineTo[[x+w, y+h]];
lineTo[[x, y+h]];
};
DViewClip[data: data, path: path, oddWrap: FALSE, exclude: exclude];
};
};
CombineManhattan: PROC [a, b: ManhattanPolygon, exclude: BOOL] RETURNS [ManhattanPolygon] ~ {
IF exclude THEN RETURN [ImagerManhattan.DestructiveDifference[a, b]]
ELSE RETURN [ImagerManhattan.DestructiveIntersection[a, b]];
};
DViewClip: PROC [data: Data, path: PathProc, oddWrap: BOOL, exclude: BOOL] ~ {
this: ManhattanPolygon;
data.devicePath ← ImagerScanConverter.CreatePath[path: path,
transformation: data.viewToDevice, clipBox: data.viewClipBox,
scratch: data.devicePath];
this ← ImagerScanConverter.ConvertToManhattanPolygon[devicePath: data.devicePath,
clipBox: data.viewClipBox, oddWrap: oddWrap];
data.viewClipMask ← CombineManhattan[data.viewClipMask, this, exclude];
ImagerManhattan.Destroy[this];
data.viewClipBox ← ImagerManhattan.BoundingBox[data.viewClipMask];
data.valid.clientClipper ← FALSE;
};
ViewReset: PUBLIC PROC [context: Context] ~ {
WITH context.data SELECT FROM
data: Data => DViewReset[data];
ENDCASE => ERROR Imager.Error[[$unimplemented, "ViewReset not implemented"]];
};
ViewTranslateI: PUBLIC PROC [context: Context, x, y: INTEGER] ~ {
WITH context.data SELECT FROM
data: Data => DViewTranslate[data, x, y];
ENDCASE => ERROR Imager.Error[[$unimplemented, "ViewTranslateI not implemented"]];
};
ViewClip: PUBLIC PROC [context: Context, path: PathProc, oddWrap: BOOL, exclude: BOOL] ~ {
WITH context.data SELECT FROM
data: Data => DViewClip[data: data, path: path, oddWrap: oddWrap, exclude: exclude];
ENDCASE => ERROR Imager.Error[[$unimplemented, "ViewClip not implemented"]];
};
ViewClipRectangleI: PUBLIC PROC [context: Context, x, y, w, h: INTEGER, exclude: BOOL] ~ {
WITH context.data SELECT FROM
data: Data => DViewClipRectangleI[data: data, x: x, y: y, w: w, h: h, exclude: exclude];
ENDCASE => ERROR Imager.Error[[$unimplemented, "ViewClipRectangleI not implemented"]];
};
ViewFromClient: PUBLIC PROC [context: Context, p: VEC] RETURNS [VEC] ~ {
state: State ~ context.state;
IF state=NIL THEN ERROR Imager.Error[[$unimplemented, "ViewFromClient not implemented"]];
RETURN[state.T.Transform[p]];
};
ClientFromView: PUBLIC PROC [context: Context, p: VEC] RETURNS [VEC] ~ {
state: State ~ context.state;
IF state=NIL THEN ERROR Imager.Error[[$unimplemented, "ClientFromView not implemented"]];
RETURN[state.T.InverseTransform[p]];
};
DeviceFromView: PUBLIC PROC [context: Context, p: VEC] RETURNS [VEC] ~ {
WITH context.data SELECT FROM
data: Data => RETURN[data.viewToDevice.Transform[p]];
ENDCASE => ERROR Imager.Error[[$unimplemented, "DeviceFromView not implemented"]];
};
ViewFromDevice: PUBLIC PROC [context: Context, p: VEC] RETURNS [VEC] ~ {
WITH context.data SELECT FROM
data: Data => RETURN[data.viewToDevice.InverseTransform[p]];
ENDCASE => ERROR Imager.Error[[$unimplemented, "ViewFromDevice not implemented"]];
};
DeviceFromClient: PUBLIC PROC [context: Context, p: VEC] RETURNS [VEC] ~ {
WITH context.data SELECT FROM
data: Data => {
Validate[data, context.state, [clientToDevice: TRUE]];
RETURN[data.clientToDevice.Transform[p]];
};
ENDCASE => ERROR Imager.Error[[$unimplemented, "DeviceFromClient not implemented"]];
};
ClientFromDevice: PUBLIC PROC [context: Context, p: VEC] RETURNS [VEC] ~ {
WITH context.data SELECT FROM
data: Data => {
Validate[data, context.state, [clientToDevice: TRUE]];
RETURN[data.clientToDevice.InverseTransform[p]];
};
ENDCASE => ERROR Imager.Error[[$unimplemented, "ClientFromDevice not implemented"]];
};
MoveViewRectangle: PUBLIC PROC [context: Context,
width, height, fromX, fromY, toX, toY: INTEGER] ~ {
state: State ~ context.state;
WITH context.data SELECT FROM
data: Data => {
Validate[data, state, maskNeeds];
DMoveViewRectangle[data: data,
width: width, height: height, fromX: fromX, fromY: fromY, toX: toX, toY: toY];
};
ENDCASE => ERROR Imager.Error[[$unimplemented, "MoveViewRectangle not implemented"]];
};
DMoveViewRectangle: PROC [data: Data,
width, height, fromX, fromY, toX, toY: INTEGER] ~ {
viewToDevice: Transformation ~ data.viewToDevice;
IF EasyTransformation[viewToDevice] THEN {
box: Box ~ TransformBox[viewToDevice, toX, toY, width, height, data.viewClipBox];
boxes: BoxGenerator ~ {
ClipBoxToMask[data.viewClipMask, box,
};
boxes: PROC[action: PROC[Box]] ~ {
ClipBoxToMask[box: box, mask: data.viewClipMask, action: action];
};
IF smin<box.max.s AND smax>box.min.s AND fmin<box.max.f AND fmax>box.min.f THEN {
device: Device ~ data.device;
IF box.smin<smin THEN box.smin ← smin; IF box.smax>smax THEN box.smax ← smax;
IF box.fmin<fmin THEN box.fmin ← fmin; IF box.fmax>fmax THEN box.fmax ← fmax;
device.class.MoveBoxes[device: device, offset: [s: fromY-toY, f: toX-fromX], boxes: boxes];
};
}
ELSE ERROR; -- hard case
};
Visibility: TYPE ~ ImagerBackdoor.Visibility;
TestViewRectangle: PUBLIC PROC [context: Imager.Context, x, y, w, h: INTEGER]
RETURNS
[Visibility] ~ {
state: State ~ context.state;
WITH context.data SELECT FROM
data: Data => {
Validate[data, state, [clientToDevice: TRUE, clientClipper: TRUE]];
RETURN[DTestViewRectangle[data: data, x: x, y: y, w: w, h: h]];
};
ENDCASE => ERROR Imager.Error[[$unimplemented, "TestRectangleI not implemented"]];
};
DTestViewRectangle: PROC [data: Data, x, y, w, h: INTEGER] RETURNS [Visibility] ~ {
viewToDevice: Transformation ~ data.viewToDevice;
viewClipMask: ManhattanPolygon ~ data.viewClipMask;
IF viewClipMask=NIL THEN RETURN[none];
IF viewToDevice.form>=3 AND viewToDevice.integerTrans THEN {
visibility: Visiblity ← TestBox[viewToDevice, x, y, w, h, data.viewClipBox];
IF visibility=all AND viewClipMask.rest#NIL THEN visibility ← part;
RETURN[visibility];
}
ELSE {
rect: Rectangle ~ viewToDevice.TransformRectangle[[x, y, w, h]];
-- test against viewClipBox --
RETURN[part];
};
};
RasterGetClipper: PUBLIC PROC[context: Context] RETURNS[clipper: Clipper] ~ {
data: Data ~ NARROW[context.data];
IF data.specialClipPresent THEN {
ERROR Imager.Error[[$unimplemented, "GetClipper during ImagerOps.DoWithBuffer"]];
};
RETURN [ImagerState.StateGetClipper[context]];
};
rasterClass: Class ~ NEW[ClassRep ← [
type: $Raster,
DoSave: ImagerState.StateDoSave,
SetInt: ImagerState.StateSetInt,
SetReal: ImagerState.StateSetReal,
SetT: ImagerState.StateSetT,
SetFont: ImagerState.StateSetFont,
SetColor: ImagerState.StateSetColor,
SetClipper: ImagerState.StateSetClipper,
GetInt: ImagerState.StateGetInt,
GetReal: ImagerState.StateGetReal,
GetT: ImagerState.StateGetT,
GetFont: ImagerState.StateGetFont,
GetColor: ImagerState.StateGetColor,
GetClipper: RasterGetClipper,
ConcatT: ImagerState.StateConcatT,
Scale2T: ImagerState.StateScale2T,
RotateT: ImagerState.StateRotateT,
TranslateT: ImagerState.StateTranslateT,
Move: ImagerState.StateMove,
SetXY: ImagerState.StateSetXY,
SetXYRel: ImagerState.StateSetXYRel,
Show: ImagerRasterPrivate.RasterShow,
ShowText: ImagerRasterPrivate.RasterShowText,
StartUnderline: ImagerState.StateStartUnderline,
MaskUnderline: ImagerState.StateMaskUnderline,
CorrectMask: ImagerState.StateCorrectMask,
CorrectSpace: ImagerState.StateCorrectSpace,
Space: ImagerState.StateSpace,
SetCorrectMeasure: ImagerState.StateSetCorrectMeasure,
SetCorrectTolerance: ImagerState.StateSetCorrectTolerance,
Correct: ImagerState.StateCorrect,
DontCorrect: ImagerState.StateDontCorrect,
SetGray: ImagerState.StateSetGray,
SetSampledColor: ImagerState.StateSetSampledColor,
SetSampledBlack: ImagerState.StateSetSampledBlack,
MaskFill: RasterMaskFill,
MaskRectangle: RasterMaskRectangle,
MaskRectangleI: RasterMaskRectangleI,
MaskVector: RasterMaskVector,
MaskStroke: RasterMaskStroke,
MaskDashedStroke: RasterMaskDashedStroke,
MaskPixel: RasterMaskPixel,
MaskBits: RasterMaskBits,
DrawBits: RasterDrawBits,
Clip: ImagerState.StateClip,
ClipRectangle: ImagerState.StateClipRectangle,
ClipRectangleI: ImagerState.StateClipRectangleI,
GetCP: ImagerState.StateGetCP,
GetBoundingRectangle: RasterGetBounds,
propList: NIL
]];
END.