Imager.mesa -- Copyright (C) 1984 Xerox Corporation. All rights reserved.
Michael Plass, February 20, 1984 9:15:15 am PST
Doug Wyatt, July 2, 1984 1:24:34 pm PDT
The Imager provides a rich set of facilities for creating two-dimensional images on a variety of devices; images can be specified in a way that is independent of any particular imaging device.
DIRECTORY
Atom USING [PropList],
Font USING [FONT],
ImagerBasic USING [ColorRep, Pair, PathMapType, PixelArray],
ImagerTransform USING [Transformation, TransformationRec],
Rope USING [ROPE];
Imager: CEDAR DEFINITIONS
~ BEGIN
Introduction
The imaging model
Prose.
Contexts
Context: TYPE ~ REF ContextRep;
ContextRep: TYPE ~ RECORD[
class: Class, -- procedures for the context class
state: REF, -- state of the imager variables, if available
data: REF, -- instance data, type depends on the class
propList: Atom.PropList -- a property list
];
Create: PROC[deviceType: ATOM, data: REFNIL] RETURNS [Context];
For making a new context.
The data field is optional; its type is dependent on the deviceType.
Errors
Error: ERROR[errorCode: ErrorCode];
ErrorCode: TYPE ~ ATOM;
$Bug -- detected an internal inconsistency
$Unimplemented -- operation not provided for this context
$NotYetImplemented -- part of the Imager implementation is incomplete
$InvalidState -- context.state is NIL or has wrong type
$ZeroDivideInCorrectSpace -- CorrectSpace calculation tried to divide by zero
$UnableToProperlyAdjustMaskPositions -- Correct failed to achieve target measure
$UnknownSpecialColor -- unrecognized atom for a special Color
$UnknownColorModel -- unrecognized colorOperator for a sampled color
$MustBeRopeOrRefText -- characters argument is not ROPE or REF TEXT
$UnimplementedSpecialOp -- unrecognized op for SpecialOp
State
The state of the imager is contained in two places: the page image, and the imager variables.
cpx, cpy: REAL
correctMX, correctMY: REAL
T: Transformation
priorityImportant: BOOL
font: FONT
color: Color
noImage: BOOL
strokeWidth: REAL
strokeEnd: StrokeEnd
underlineStart: REAL
amplifySpace: REAL
correctShrink: REAL
correctTX, correctTY: REAL
clipper: Clipper
The variables differ in their treatment by the Do-operators below: the non-persistent variables are restored by DoSave; all variables are restored by DoSaveAll.
DoSave: PROC[context: Context, body: PROC];
DoSaveAll: PROC[context: Context, body: PROC];
Priority
SetPriorityImportant: PROC[context: Context, priorityImportant: BOOL];
Set the current value of priorityImportant.
A change to the image induced by a mask operator is said to be "ordered" if priorityImportant is TRUE, and "unordered" if priorityImportant is FALSE. The rule is that the priority order of all ordered image changes must be preserved; the imager is allowed to alter priority order among unordered changes, or between ordered and unordered changes. Because preserving priority order may require more computation than allowing arbitrary reordering of objects, creators should leave priorityImportant FALSE if possible (this is the default). [[Change default to TRUE?]]
Property lists
The following procedures provide a property-list mechanism. The key-value association is saved and restored by DoSave and DoSaveAll.
PutProp: PROC[context: Context, key: REF, value: REF];
Put (key, value) on the context's property list.
GetProp: PROC[context: Context, key: REF] RETURNS[value: REF];
Get key's value from the context's property list.
RemProp: PROC[context: Context, key: REF];
Remove key from the context's property list.
Transformations
Creating transformations
Transformation: TYPE ~ ImagerTransform.Transformation;
Matrix: TYPE ~ ImagerTransform.TransformationRec;
MakeT: PROC[Matrix] RETURNS[Transformation];
OpenT: PROC[Transformation] RETURNS[Matrix];
Scale: PROC[s: REAL] RETURNS[Transformation];
Scale2: PROC[sx, sy: REAL] RETURNS[Transformation];
Rotate: PROC[a: REAL] RETURNS[Transformation];
Translate: PROC[x, y: REAL] RETURNS[Transformation];
Concat: PROC[m, n: Transformation] RETURNS[Transformation];
Invert: PROC[m: Transformation] RETURNS[Transformation];
Applying transformations
Transform: PROC[m: Transformation, p: Pair] RETURNS[Pair];
TransformVec: PROC[m: Transformation, p: Pair] RETURNS[Pair];
InverseTransform: PROC[m: Transformation, p: Pair] RETURNS[Pair];
InverseTransformVec: PROC[m: Transformation, p: Pair] RETURNS[Pair];
The current transformation
ConcatT: PROC[context: Context, m: Transformation];
ScaleT: PROC[context: Context, s: REAL];
Equivalent to context.ConcatT[Scale[s]].
micasToMeters: REAL ~ 0.00001;
inchesToMeters: REAL ~ micasToMeters*2540;
pointsToMeters: REAL ~ inchesToMeters/72.27;
Some commonly used scale factors.
Scale2T: PROC[context: Context, sx, sy: REAL];
Equivalent to context.ConcatT[Scale2[sx, sy]].
RotateT: PROC[context: Context, a: REAL];
Equivalent to context.ConcatT[Rotate[a]]. Angle a is measured in degrees.
Positive angles will rotate subsequent geometrical figures counterclockwise.
TranslateT: PROC[context: Context, x, y: REAL];
Equivalent to context.ConcatT[Translate[x, y]]
Move: PROC[context: Context];
Modify T so that the origin maps to the current position.
Trans: PROC[context: Context];
Modify T so that the origin maps to the rounded current position.
The rounding in Trans implies that any coordinates to which T is subsequently applied will be translated by an integral number of grid points. This convention allows often-used instances such as characters to be scan-converted once and then translated at will. Trans is designed together with SetXYRel (see below) to achieve positioning precision, while still letting each instance of a character be scan-converted identically.
Mask operators
The mask operators are the central focus of the imager, for they determine the shapes of primitive images that are laid down on the image. Mask operators are available to make images of rectangles, line drawings, or filled outlines, and to use a pixel array to specify samples of the mask.
When a mask operator is executed, the page image is altered. The operation of a mask operator is controlled in part by its arguments and in part by imager variables:
— The current transformation, T, transforms the specified mask shape to determine the coordinates of the mask on the image.
— The current color governs the color of the object that will be placed on the image.
— If priorityImportant is TRUE, the priority order of objects laid down is preserved.
— If noImage is TRUE, mask operators will have no effect on the image, although they will have the proper effect on the imager variables.
Shapes are defined geometrically in terms of segments, trajectories, and outlines. A segment is a directed segment of a straight line, cubic curve, or conic section; it has a start point and an end point. A trajectory is a sequence of connected segments; the end point of a segment coincides with the start point ot the next one. A closed trajectory is a trajectory that closes upon itself, that is, the end point of the last segment in the trajectory coincides with the start point of the first segment. An outline is a collection of trajectories; each trajectory in an outline is implicitly closed by a straight-line segment linking the end point of the last segment with the start point of the first segment.
Trajectories
A Trajectory is an immutable value. MoveTo creates a new trajectory; other operations add a straight or curved segment and return an extended trajectory. Every trajectory has a last point (lp); the lp is the end point of the trajectory's last segment.
Pair: TYPE ~ ImagerBasic.Pair; -- RECORD[x, y: REAL]
Trajectory: TYPE ~ REF TrajectoryRep;
TrajectoryRep: TYPE ~ RECORD[
prev: Trajectory, -- the preceding trajectory
lp: Pair, -- the last point
variant: SELECT tag: * FROM
move => [], -- begin new trajectory at lp
line => [], -- straight line, endpoints [prev.lp, lp]
curve => [p1, p2: Pair], -- cubic curve, Bezier control points [prev.lp, p1, p2, lp]
conic => [p1: Pair, r: REAL], -- conic curve, control points [prev.lp, p1, lp]
ENDCASE
];
TrajectoryList: TYPE ~ LIST OF Trajectory;
LastPoint: PROC[t: Trajectory] RETURNS[x, y: REAL];
LastPointP: PROC[t: Trajectory] RETURNS[Pair];
Return t's lp.
MoveTo: PROC[x, y: REAL] RETURNS[Trajectory];
MoveToP: PROC[p: Pair] RETURNS[Trajectory];
Create a new trajectory, containing a single vertex. Its lp is p.
LineTo: PROC[t: Trajectory, x, y: REAL] RETURNS[Trajectory];
LineToP: PROC[t: Trajectory, p: Pair] RETURNS[Trajectory];
Extend t with a straight line segment. The lp of the result is p.
LineToX: PROC[t: Trajectory, x: REAL] RETURNS[Trajectory];
LineToY: PROC[t: Trajectory, y: REAL] RETURNS[Trajectory];
LineToX is equivalent to t.LineTo[x, t.lp.y].
LineToY is equivalent to t.LineTo[t.lp.x, y].
CurveTo: PROC[t: Trajectory, x1, y1, x2, y2, x3, y3: REAL] RETURNS[Trajectory];
CurveToP: PROC[t: Trajectory, p1, p2, p3: Pair] RETURNS[Trajectory];
Extend t with a cubic curve segment. The lp of the result is p3.
Let p0 = t.lp. The curve segment is defined by Bezier control points p0, p1, p2, p3. It starts at p0, tangent to the line joining p0 and p1, and ends at p3, tangent to the line joining p2 and p3. It is bounded by the quadrilateral with vertices p0, p1, p2, p3.
ConicTo: PROC[t: Trajectory, x1, y1, x2, y2: REAL, r: REAL] RETURNS[Trajectory];
ConicToP: PROC[t: Trajectory, p1, p2: Pair, r: REAL] RETURNS[Trajectory];
Extend t with a segment of a conic section. The lp of the result is p2.
Let p0 = t.lp. Let m be the midpoint of the line joining p0 and p2. Let p be the point on the line joining m and p1 such that Length[m, p]/Length[m, p1] = r. The curve segment starts at p0, passes through p, and ends at p2. It is a line if r=0; an ellipse if 0<r<1/2; a parabola if r=1/2; a hyperbola if 1/2<r<1. It is bounded by the triangle with vertices p0, p1, p2.
ArcTo: PROC[t: Trajectory, x1, y1, x2, y2: REAL] RETURNS[Trajectory];
ArcToP: PROC[t: Trajectory, p1, p2: Pair] RETURNS[Trajectory];
Extend t with a circular arc. The lp of the result is p2.
Let p0 = t.lp. The arc starts at p0, passes through p1, and ends at p2. It is best for p1 to lie near the halfway point along the arc. If p0 and p2 are coincident, ArcTo produces a circle: p1 lies on the circle diametrically opposite p0. If p0, p1, and p2 are colinear, the effect is t.LineToP[p1].LineToP[p2].
PathProc: TYPE ~ ImagerBasic.PathMapType;
MapTrajectory: PathProc; -- for a Trajectory
MapTrajectoryList: PathProc; -- for a TrajectoryList
Filled areas
MaskFill: PROC[context: Context, outline: REF];
The mask is defined as the region inside the outline obtained by transforming the given outline with the current transformation T. The outline argument may have any of the following types: Trajectory, LIST OF Trajectory, Polygon.
Trajectories and outlines are given a geometrical interpretation only when they are used as a mask. At this point, the numbers describing the trajectory or outline are interpreted as defining geometry in the master coordinate system, which the imager operators MaskFill and MaskStroke convert to the device coordinate system by applying the current transformation T. Thus the value of T while a trajectory or outline is constructed is ignored; only the value of T when the mask operator is executed is important.
Operations that take an outline argument, such as MaskFill, need to decide which points lie "inside" the outline. If no trajectory in the outline intersects itself or another trajectory, the inside of the outline is unambiguous. In other cases, to decide if a point lies inside an outline, it is necessary to compute the point's winding number. The winding number counts the number of times the point is surrounded by an outline: it is the number of closed trajectories in the outline that are wound clockwise around the point. The imager uses the convention that points with non-zero winding number lie inside the outline. Note that for multi-trajectory outlines, the order in which points on a trajectory are specified is important.
MaskFillPath: PROC[context: Context, pathProc: PathProc, pathData: REFNIL];
Strokes
SetStrokeWidth: PROC[context: Context, strokeWidth: REAL];
Establish the width for following strokes.
StrokeEnd: TYPE ~ {
square, -- Square off the end after extending the stroke by half its width
butt, -- Square off the end flush with the endpoint
round -- Round the end with a semicircular cap
};
SetStrokeEnd: PROC[context: Context, strokeEnd: StrokeEnd];
Establish endpoint treatment for following strokes.
MaskStroke: PROC[context: Context, stroke: REF];
The stroke is first broadened to have uniform width strokeWidth, fitted with the endpoints specified by strokeEnd, then transformed by the current transformation T, and used as a mask to alter the image. Joints between segments of the trajectory are mitered, i.e., sides of the stroke are extended until they meet. Segments of a trajectory meeting at an acute angle will thus generate long, sharp corners.
If square or butt end geometry is undetermined because the trajectory starts or ends with a segment whose start and end points coincide, an error occurs.
To generate strokes with rounded joints between segments, rather than mitered joints, call MaskStroke separately for each segment, using round stroke ends.
MaskStrokeClosed: PROC[context: Context, stroke: REF];
Like MaskStroke, except that each trajectory is closed if necessary with a straight line back to its starting point, and all joints between segments are mitered. The current strokeEnd setting has no effect.
MaskStrokePath: PROC[context: Context, pathProc: PathProc, pathData: REFNIL];
MaskStrokeClosedPath: PROC[context: Context, pathProc: PathProc, pathData: REFNIL];
Rectangles and vectors
MaskRectangle: PROC[context: Context, x, y, w, h: REAL];
MaskRectangleI: PROC[context: Context, x, y, w, h: INTEGER]
~ INLINE { context.class.MaskRectangleI[context, x, y, w, h] };
Fill a rectangular area with the given origin, width and height.
Equivalent to context.MaskFill[MoveTo[x, y].LineToX[x+w].LineToY[y+h].LineToX[x]].
Box: TYPE ~ RECORD[xmin, ymin, xmax, ymax: REAL];
MaskBox: PROC[context: Context, box: Box];
Equivalent to context.MaskRectangle[
x: box.xmin, y: box.ymin, w: box.xmax-box.xmin, h: box.ymax-box.ymin].
Convenient for former users of Graphics.DrawBox.
MaskVector: PROC[context: Context, x1, y1, x2, y2: REAL];
MaskVectorI: PROC[context: Context, x1, y1, x2, y2: INTEGER]
~ INLINE { context.class.MaskVectorI[context, x1, y1, x2, y2] };
MaskVectorP: PROC[context: Context, p1, p2: Pair];
Draw a straight line segment, using the current stroke width and ends.
Equivalent to context.MaskStroke[MoveToP[p1].LineToP[p2]].
Inhibiting mask operators
SetNoImage: PROC[context: Context, noImage: BOOL];
Set the current value of noImage.
Text
Current position operators
The imaging operators make it easy to locate a graphical object such as a character at the current position. The current position is measured in the view coordinate system, and is recorded in two persistent imager variables, cpx and cpy. It is by altering the current position that an operator displaying a character specifies where the next character on the text line should usually lie. The following operators change the current position.
SetXY: PROC[context: Context, x, y: REAL];
SetXYI: PROC[context: Context, x, y: INTEGER]
~ INLINE { context.class.SetXYI[context, x, y] };
SetXYP: PROC[context: Context, p: Pair];
Set the current position.
SetXYRel: PROC[context: Context, x, y: REAL];
SetXYRelI: PROC[context: Context, x, y: INTEGER]
~ INLINE { context.class.SetXYRelI[context, x, y] };
SetXYRelP: PROC[context: Context, p: Pair];
Add a relative displacement to the current position.
SetXRel: PROC[context: Context, x: REAL];
SetXRelI: PROC[context: Context, x: INTEGER]
~ INLINE { context.class.SetXYRelI[context, x, 0] };
Equivalent to context.SetXYRel[x, 0]
SetYRel: PROC[context: Context, y: REAL];
SetYRelI: PROC[context: Context, y: INTEGER]
~ INLINE { context.class.SetXYRelI[context, 0, y] };
Equivalent to context.SetXYRel[0, y]
Character operators
The most common shapes are those used to make images of characters; these masks are specified in sets of pre-defined operators called fonts.
FONT: TYPE ~ Font.FONT;
ROPE: TYPE ~ Rope.ROPE;
FindFont: PROC[name: ROPE] RETURNS[FONT];
ModifyFont: PROC[font: FONT, m: Transformation] RETURNS[FONT];
MakeFont: PROC[name: ROPE, size: REAL] RETURNS[FONT];
SetFont: PROC[context: Context, font: FONT];
ShowRope: PROC[context: Context, rope: ROPE, start: INT ← 0, len: INTINT.LAST];
ShowText: PROC[context: Context, text: REF READONLY TEXT, start: NAT ← 0, len: NATNAT.LAST];
ShowChar: PROC[context: Context, char: CHAR];
SetAmplifySpace: PROC[context: Context, amplifySpace: REAL];
Underlining
Character strings can be underlined by placing a rectangle of appropriate width and height just below the string. The width of the rectangle will be determined by the width of the character string. The position of the underline along the baseline will be determined by the current position, but because of spacing corrections the current position cannot be anticipated accurately when the master is created. The operators StartUnderline and MaskUnderline are provided to help position underlines accurately. They assume a master coordinate system in which the baseline is oriented in the positive x direction.
StartUnderline: PROC[context: Context];
Remember the x component of the current position as the starting point for an underline.
MaskUnderline: PROC[context: Context, dy, h: REAL];
MaskUnderlineI: PROC[context: Context, dy, h: INTEGER]
~ INLINE { context.class.MaskUnderlineI[context, dy, h] };
The text starting at the point previously identified by StartUnderline and ending at the current position will be underlined with a rectangle of height h and top a distance dy below the current position. For example, to underline the word Hello, the client might call:
context.StartUnderline[]; context.ShowRope["Hello"]; context.MaskUnderline[4, 1];
Spacing correction
CorrectMask: PROC[context: Context];
CorrectSpace: PROC[context: Context, x, y: REAL];
CorrectSpaceP: PROC[context: Context, p: Pair];
Correct: PROC[context: Context, body: PROC];
SetCorrectMeasure: PROC[context: Context, x, y: REAL];
SetCorrectMeasureP: PROC[context: Context, p: Pair];
SetCorrectTolerance: PROC[context: Context, x, y: REAL];
SetCorrectToleranceP: PROC[context: Context, p: Pair];
SetCorrectShrink: PROC[context: Context, correctShrink: REAL];
Space: PROC[context: Context, x: REAL];
SpaceI: PROC[context: Context, x: INTEGER]
~ INLINE { context.class.SpaceI[context, x] };
Pixel arrays
PixelArray: TYPE ~ ImagerBasic.PixelArray;
MakePixelArrayFromBits: PROC[
bitPointer: LONG POINTER TO PACKED ARRAY [0..0) OF [0..1],
bitsPerLine, samplesPerLine, numberOfLines: NAT
] RETURNS [PixelArray];
Manufactures a one-bit-per-sample/one-sample-per-pixel PixelArray from a bitmap. The bitmap is assumed to be oriented like a screen bitmap, so
bitPointer^[0] is the sample for the upper-left-hand corner,
bitPointer^[samplesPerLine-1] is for the upper-right-hand corner, and
bitPointer^[bitsPerLine*(numberOfLines-1)+samplesPerLine-1] is for the lower-right-hand corner.
MaskPixel: PROC[context: Context, pa: PixelArray];
Color
The color that will be deposited on the page image is determined by the value of the color variable when a mask operator is invoked. Wherever the mask allows it, the color specified by the imager variable color is deposited on the page image, obliterating any color previously laid down at the same position on the page. There are two ways to specify color: a constant color, and color sampled on a raster. A value of type Color fully specifies a color; a subtype ConstantColor is used for constant colors (ConstantColor widens to Color).
Constant color
ConstantColor: TYPE ~ REF ImagerBasic.ColorRep[constant];
MakeGray: PROC[f: REAL] RETURNS[ConstantColor];
Make a shade of gray specified by the fraction f: 0 means white, 1 means black.
black: ConstantColor; -- MakeGray[1]
white: ConstantColor; -- MakeGray[0]
Sampled color
Color: TYPE ~ REF ImagerBasic.ColorRep;
SetSampledColor: PROC[context: Context, pa: PixelArray, pixelT: Transformation, colorOperator: ATOM ← $Intensity];
SetSampledBlack: PROC[context: Context, pa: PixelArray, pixelT: Transformation, transparent: BOOLEANFALSE];
These operations set a sampled color with a transformation of
Concat[pixelT, context.state.T].
For example, if the current coordinate system were in meters, and the client wished to set a 10-by-10 stipple pattern that repeated every 1 cm, the following would work:
pattern: PACKED ARRAY [0..100) OF [0..1] ← [1, 0, 1, 1, ... 0];
pixelArray: PixelArray;
TRUSTED {pixelArray ← MakePixelArrayFromBits[@pattern, 10, 10, 10]};
SetSampledBlack[context, pixelArray, Scale[0.001]];
The current color
SetColor: PROC[context: Context, color: Color];
Set the value of the color variable.
SetGray: PROC[context: Context, f: REAL];
Equivalent to context.SetColor[MakeGray[f]]
Clipping
ClipOutline: PROC[context: Context, outline: REF];
ClipOutlinePath: PROC[context: Context, pathProc: PathProc, pathData: REFNIL];
ExcludeOutline: PROC[context: Context, outline: REF];
ExcludeOutlinePath: PROC[context: Context, pathProc: PathProc, pathData: REFNIL];
ClipRectangle: PROC[context: Context, x, y, w, h: REAL];
ClipRectangleI: PROC[context: Context, x, y, w, h: INTEGER];
ExcludeRectangle: PROC[context: Context, x, y, w, h: REAL];
ExcludeRectangleI: PROC[context: Context, x, y, w, h: INTEGER];
Private details
Class: TYPE ~ REF ClassRep;
ClassRep: TYPE ~ RECORD[
type: ATOM,
DoSave: PROC[context: Context, body: PROC] ←,
DoSaveAll: PROC[context: Context, body: PROC] ←,
SetPriorityImportant: PROC[context: Context, priorityImportant: BOOL] ←,
SetFont: PROC[context: Context, font: FONT] ←,
SetColor: PROC[context: Context, color: Color] ←,
SetNoImage: PROC[context: Context, noImage: BOOL] ←,
SetStrokeWidth: PROC[context: Context, strokeWidth: REAL] ←,
SetStrokeEnd: PROC[context: Context, strokeEnd: StrokeEnd] ←,
SetAmplifySpace: PROC[context: Context, amplifySpace: REAL] ←,
SetCorrectShrink: PROC[context: Context, correctShrink: REAL] ←,
ConcatT: PROC[context: Context, m: Transformation] ←,
ScaleT: PROC[context: Context, s: REAL] ←,
Scale2T: PROC[context: Context, sx, sy: REAL] ←,
RotateT: PROC[context: Context, a: REAL] ←,
TranslateT: PROC[context: Context, x, y: REAL] ←,
Move: PROC[context: Context] ←,
Trans: PROC[context: Context] ←,
ShowRope: PROC[context: Context, rope: ROPE, start, len: INT] ←,
ShowText: PROC[context: Context, text: REF READONLY TEXT, start, len: NAT] ←,
ShowChar: PROC[context: Context, char: CHAR] ←,
SetXY: PROC[context: Context, x, y: REAL] ←,
SetXYI: PROC[context: Context, x, y: INTEGER] ←,
SetXYRel: PROC[context: Context, x, y: REAL] ←,
SetXYRelI: PROC[context: Context, x, y: INTEGER] ←,
SetSampledColor: PROC[context: Context, pa: PixelArray, pixelT: Transformation, colorOperator: ATOM] ←,
SetSampledBlack: PROC[context: Context, pa: PixelArray, pixelT: Transformation, transparent: BOOL] ←,
SetGray: PROC[context: Context, f: REAL] ←,
MaskFill: PROC[context: Context, pathProc: PathProc, pathData: REF] ←,
MaskStroke: PROC[context: Context, pathProc: PathProc, pathData: REF] ←,
MaskStrokeClosed: PROC[context: Context, pathProc: PathProc, pathData: REF] ←,
MaskVector: PROC[context: Context, x1, y1, x2, y2: REAL] ←,
MaskVectorI: PROC[context: Context, x1, y1, x2, y2: INTEGER] ←,
MaskRectangle: PROC[context: Context, x, y, w, h: REAL] ←,
MaskRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ←,
StartUnderline: PROC[context: Context] ←,
MaskUnderline: PROC[context: Context, dy, h: REAL] ←,
MaskUnderlineI: PROC[context: Context, dy, h: INTEGER] ←,
MaskPixel: PROC[context: Context, pa: PixelArray] ←,
ClipOutline: PROC[context: Context, pathProc: PathProc, pathData: REF] ←,
ExcludeOutline: PROC[context: Context, pathProc: PathProc, pathData: REF] ←,
ClipRectangle: PROC[context: Context, x, y, w, h: REAL] ←,
ClipRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ←,
ExcludeRectangle: PROC[context: Context, x, y, w, h: REAL] ←,
ExcludeRectangleI: PROC[context: Context, x, y, w, h: INTEGER] ←,
CorrectMask: PROC[context: Context] ←,
CorrectSpace: PROC[context: Context, x, y: REAL] ←,
Correct: PROC[context: Context, body: PROC] ←,
SetCorrectMeasure: PROC[context: Context, x, y: REAL] ←,
SetCorrectTolerance: PROC[context: Context, x, y: REAL] ←,
Space: PROC[context: Context, x: REAL] ←,
SpaceI: PROC[context: Context, x: INTEGER] ←
];
END.