ImagerImpl.mesa
Copyright © 1984, 1985, 1986 by Xerox Corporation. All rights reserved.
Michael Plass, November 1, 1985 9:37:58 am PST
Doug Wyatt, May 7, 1986 5:24:52 pm PDT
DIRECTORY
Atom USING [DottedPairNode, PropList],
CountedVM USING [Handle, SimpleAllocate],
Imager USING [Box, Color, ColorOperator, ConstantColor, Context, ErrorDesc, Font, Outline, PathProc, PixelArray, Rectangle, ROPE, StrokeEnd, StrokeJoint, Trajectory, Transformation, VEC, XChar, XStringProc],
ImagerBackdoor USING [Bitmap, BitmapRep, Clipper, IntKey, RealKey],
ImagerBox USING [],
ImagerColor USING [ColorFromGray],
ImagerColorPrivate USING [ColorFromStipple],
ImagerExtras USING [NewStrokeJoint],
ImagerFont USING [Extents, MapRope],
ImagerPath USING [MapOutline, MapTrajectory],
ImagerPixelMap USING [PixelMap, PixelMapRep],
ImagerPrivate USING [Class, ClassRep],
ImagerRaster USING [Create, NewBitmapDevice],
ImmutablePropList USING [],
Process USING [CheckForAbort];
ImagerImpl: CEDAR PROGRAM
IMPORTS CountedVM, ImagerColor, ImagerColorPrivate, ImagerFont, ImagerPath, ImagerRaster, Process
EXPORTS Imager, ImagerBackdoor, ImagerExtras, ImmutablePropList, ImagerBox
~ BEGIN OPEN Imager, ImagerBackdoor;
Class: TYPE ~ ImagerPrivate.Class;
ClassRep: PUBLIC TYPE ~ ImagerPrivate.ClassRep; -- export to Imager.ClassRep
Error: PUBLIC ERROR[error: ErrorDesc] ~ CODE;
GetClass: PUBLIC PROC[context: Context] RETURNS[ATOM] ~ {
class: Class ~ context.class;
RETURN[class.type];
};
GetProp: PUBLIC PROC[context: Context, key: REF] RETURNS[val: REF] ~ {
RETURN[Get[context.propList, key]];
};
PutProp: PUBLIC PROC[context: Context, key: REF, val: REF] ~ {
context.propList ← Put[context.propList, key, val];
};
DoSave: PUBLIC PROC[context: Context, action: PROC] ~ {
class: Class ~ context.class;
propList: Atom.PropList ~ context.propList;
class.DoSave[context: context, action: action, all: FALSE !
UNWIND
=> context.propList ← propList];
context.propList ← propList;
};
DoSaveAll: PUBLIC PROC[context: Context, action: PROC] ~ {
class: Class ~ context.class;
propList: Atom.PropList ~ context.propList;
class.DoSave[context: context, action: action, all: TRUE !
UNWIND
=> context.propList ← propList];
context.propList ← propList;
};
ConcatT: PUBLIC PROC[context: Context, m: Transformation] ~ {
class: Class ~ context.class;
class.ConcatT[context: context, m: m];
};
ScaleT: PUBLIC PROC[context: Context, s: REAL] ~ {
class: Class ~ context.class;
class.Scale2T[context: context, s: [s, s]];
};
Scale2T: PUBLIC PROC[context: Context, s: VEC] ~ {
class: Class ~ context.class;
class.Scale2T[context: context, s: s];
};
RotateT: PUBLIC PROC[context: Context, a: REAL] ~ {
class: Class ~ context.class;
class.RotateT[context: context, a: a];
};
TranslateT: PUBLIC PROC[context: Context, t: VEC] ~ {
class: Class ~ context.class;
class.TranslateT[context: context, t: t];
};
Move: PUBLIC PROC[context: Context] ~ {
class: Class ~ context.class;
class.Move[context: context, rounded: FALSE];
};
Trans: PUBLIC PROC[context: Context] ~ {
class: Class ~ context.class;
class.Move[context: context, rounded: TRUE];
};
SetXY: PUBLIC PROC[context: Context, p: VEC] ~ {
class: Class ~ context.class;
class.SetXY[context: context, p: p];
};
SetXYI: PUBLIC PROC[context: Context, x, y: INTEGER] ~ {
class: Class ~ context.class;
class.SetXY[context: context, p: [x, y]];
};
SetXYRel: PUBLIC PROC[context: Context, v: VEC] ~ {
class: Class ~ context.class;
class.SetXYRel[context: context, v: v];
};
SetXYRelI: PUBLIC PROC[context: Context, x, y: INTEGER] ~ {
class: Class ~ context.class;
class.SetXYRel[context: context, v: [x, y]];
};
SetXRel: PUBLIC PROC[context: Context, x: REAL] ~ {
class: Class ~ context.class;
class.SetXYRel[context: context, v: [x, 0]];
};
SetXRelI: PUBLIC PROC[context: Context, x: INTEGER] ~ {
class: Class ~ context.class;
class.SetXYRel[context: context, v: [x, 0]];
};
SetYRel: PUBLIC PROC[context: Context, y: REAL] ~ {
class: Class ~ context.class;
class.SetXYRel[context: context, v: [0, y]];
};
SetYRelI: PUBLIC PROC[context: Context, y: INTEGER] ~ {
class: Class ~ context.class;
class.SetXYRel[context: context, v: [0, y]];
};
SetFont: PUBLIC PROC[context: Context, font: Font] ~ {
class: Class ~ context.class;
class.SetFont[context: context, font: font];
};
SetAmplifySpace: PUBLIC PROC[context: Context, amplifySpace: REAL] ~ {
class: Class ~ context.class;
class.SetReal[context: context, key: $amplifySpace, val: amplifySpace];
};
Show: PUBLIC PROC[context: Context, string: XStringProc, xrel: BOOLFALSE] ~ {
class: Class ~ context.class;
Process.CheckForAbort[];
class.Show[context: context, string: string, xrel: xrel];
};
ShowAndFixedXRel: PUBLIC PROC[context: Context, string: XStringProc, x: REAL] ~ {
class: Class ~ context.class;
first: BOOLTRUE;
eachChar: PROC [char: XChar] ~ {
thisChar: XStringProc ~ { charAction[char] };
IF first THEN first ← FALSE ELSE class.SetXYRel[context, [x, 0]];
class.Show[context: context, string: thisChar, xrel: FALSE];
};
string[eachChar];
};
ShowChar: PUBLIC PROC[context: Context, char: CHAR] ~ {
string: XStringProc ~ { charAction[[set: 0, code: ORD[char]]] };
class: Class ~ context.class;
Process.CheckForAbort[];
class.Show[context: context, string: string, xrel: FALSE];
};
ShowXChar: PUBLIC PROC[context: Context, char: XChar] ~ {
string: XStringProc ~ { charAction[char] };
class: Class ~ context.class;
Process.CheckForAbort[];
class.Show[context: context, string: string, xrel: FALSE];
};
ShowRope: PUBLIC PROC[context: Context, rope: ROPE,
start: INT ← 0, len: INTINT.LAST, xrel: BOOLFALSE] ~ {
string: XStringProc ~ { ImagerFont.MapRope[
rope: rope, start: start, len: len, charAction: charAction] };
class: Class ~ context.class;
class.Show[context: context, string: string, xrel: xrel];
};
ShowText: PUBLIC PROC[context: Context, text: REF READONLY TEXT,
start: NAT ← 0, len: NATNAT.LAST, xrel: BOOLFALSE] ~ {
class: Class ~ context.class;
Process.CheckForAbort[];
class.ShowText[context: context, text: text, start: start, len: len, xrel: xrel];
};
StartUnderline: PUBLIC PROC[context: Context] ~ {
class: Class ~ context.class;
class.StartUnderline[context: context];
};
MaskUnderline: PUBLIC PROC[context: Context, dy, h: REAL] ~ {
class: Class ~ context.class;
class.MaskUnderline[context: context, dy: dy, h: h];
};
MaskUnderlineI: PUBLIC PROC[context: Context, dy, h: INTEGER] ~ {
class: Class ~ context.class;
class.MaskUnderline[context: context, dy: dy, h: h];
};
CorrectMask: PUBLIC PROC[context: Context] ~ {
class: Class ~ context.class;
class.CorrectMask[context: context];
};
CorrectSpace: PUBLIC PROC[context: Context, v: VEC] ~ {
class: Class ~ context.class;
class.CorrectSpace[context: context, v: v];
};
Space: PUBLIC PROC[context: Context, x: REAL] ~ {
class: Class ~ context.class;
class.Space[context: context, x: x];
};
SpaceI: PUBLIC PROC[context: Context, x: INTEGER] ~ {
class: Class ~ context.class;
class.Space[context: context, x: x];
};
SetCorrectMeasure: PUBLIC PROC[context: Context, v: VEC] ~ {
class: Class ~ context.class;
class.SetCorrectMeasure[context: context, v: v];
};
SetCorrectTolerance: PUBLIC PROC[context: Context, v: VEC] ~ {
class: Class ~ context.class;
class.SetCorrectTolerance[context: context, v: v];
};
SetCorrectShrink: PUBLIC PROC[context: Context, correctShrink: REAL] ~ {
class: Class ~ context.class;
class.SetReal[context: context, key: $correctShrink, val: correctShrink];
};
Correct: PUBLIC PROC[context: Context, action: PROC] ~ {
class: Class ~ context.class;
class.Correct[context: context, action: action];
};
DontCorrect: PUBLIC PROC[context: Context, action: PROC, saveCP: BOOLFALSE] ~ {
class: Class ~ context.class;
class.DontCorrect[context: context, action: action, saveCP: saveCP];
};
SetColor: PUBLIC PROC[context: Context, color: Color] ~ {
class: Class ~ context.class;
class.SetColor[context: context, color: color];
};
black: PUBLIC ConstantColor ← ImagerColor.ColorFromGray[1];
white: PUBLIC ConstantColor ← ImagerColor.ColorFromGray[0];
MakeGray: PUBLIC PROC[f: REAL] RETURNS[ConstantColor] ~ {
IF f>=1.0 THEN RETURN[black];
IF f<=0.0 THEN RETURN[white];
RETURN[ImagerColor.ColorFromGray[f]];
};
SetGray: PUBLIC PROC[context: Context, f: REAL] ~ {
class: Class ~ context.class;
class.SetGray[context: context, f: f];
};
SetSampledColor: PUBLIC PROC[context: Context, pa: PixelArray,
m: Transformation, colorOperator: ColorOperator] ~ {
class: Class ~ context.class;
class.SetSampledColor[context: context, pa: pa, m: m, colorOperator: colorOperator];
};
SetSampledBlack: PUBLIC PROC[context: Context, pa: PixelArray,
m: Transformation, clear: BOOLFALSE] ~ {
class: Class ~ context.class;
class.SetSampledBlack[context: context, pa: pa, m: m, clear: clear];
};
DrawSampledColor: PUBLIC PROC [context: Context, pa: PixelArray,
m: Transformation, colorOperator: ColorOperator, p: VEC] ~ {
drawSampledColorAction: PROC ~ {
TranslateT[context, p];
SetSampledColor[context, pa, m, colorOperator];
ConcatT[context, m];
ConcatT[context, pa.m];
MaskRectangle[context, [0, 0, pa.sSize, pa.fSize]];
};
DoSave[context, drawSampledColorAction];
};
SetPriorityImportant: PUBLIC PROC[context: Context, priorityImportant: BOOL] ~ {
class: Class ~ context.class;
class.SetInt[context: context, key: $priorityImportant, val: IF priorityImportant THEN 1 ELSE 0];
};
SetNoImage: PUBLIC PROC[context: Context, noImage: BOOL] ~ {
class: Class ~ context.class;
class.SetInt[context: context, key: $noImage, val: IF noImage THEN 1 ELSE 0];
};
MaskFill: PUBLIC PROC[context: Context, path: PathProc, parity: BOOLFALSE] ~ {
class: Class ~ context.class;
class.MaskFill[context: context, path: path, oddWrap: parity];
};
MaskFillTrajectory: PUBLIC PROC[context: Context, trajectory: Trajectory, parity: BOOLFALSE] ~ {
class: Class ~ context.class;
path: PathProc ~ { ImagerPath.MapTrajectory[trajectory: trajectory,
moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, conicTo: conicTo, arcTo: arcTo] };
class.MaskFill[context: context, path: path, oddWrap: parity];
};
MaskFillOutline: PUBLIC PROC[context: Context, outline: Outline, parity: BOOLFALSE] ~ {
class: Class ~ context.class;
path: PathProc ~ { ImagerPath.MapOutline[outline: outline,
moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, conicTo: conicTo, arcTo: arcTo] };
class.MaskFill[context: context, path: path, oddWrap: parity];
};
MaskRectangle: PUBLIC PROC[context: Context, r: Rectangle] ~ {
class: Class ~ context.class;
class.MaskRectangle[context: context, r: r];
};
MaskRectangleI: PUBLIC PROC[context: Context, x, y, w, h: INTEGER] ~ {
class: Class ~ context.class;
class.MaskRectangleI[context: context, x: x, y: y, w: w, h: h];
};
MaskBox: PUBLIC PROC[context: Context, box: Box] ~ {
class: Class ~ context.class;
class.MaskRectangle[context: context,
r: [x: box.xmin, y: box.ymin, w: box.xmax-box.xmin, h: box.ymax-box.ymin]];
};
SetStrokeWidth: PUBLIC PROC[context: Context, strokeWidth: REAL] ~ {
class: Class ~ context.class;
class.SetReal[context: context, key: $strokeWidth, val: strokeWidth];
};
SetStrokeEnd: PUBLIC PROC[context: Context, strokeEnd: StrokeEnd] ~ {
class: Class ~ context.class;
class.SetInt[context: context, key: $strokeEnd, val: ORD[strokeEnd]];
};
intFromOldStrokeJoint: ARRAY StrokeJoint OF NAT ← [mitered: 0, round: 2];
SetStrokeJoint: PUBLIC PROC[context: Context, strokeJoint: StrokeJoint] ~ {
class: Class ~ context.class;
class.SetInt[context: context, key: $strokeJoint, val: intFromOldStrokeJoint[strokeJoint]];
};
NewSetStrokeJoint: PUBLIC PROC[context: Context, strokeJoint: ImagerExtras.NewStrokeJoint] ~ {
class: Class ~ context.class;
class.SetInt[context: context, key: $strokeJoint, val: ORD[strokeJoint]];
};
MaskStroke: PUBLIC PROC[context: Context, path: PathProc,
closed: BOOLFALSE] ~ {
class: Class ~ context.class;
class.MaskStroke[context: context, path: path, closed: closed];
};
MaskStrokeTrajectory: PUBLIC PROC[context: Context, trajectory: Trajectory,
closed: BOOLFALSE] ~ {
class: Class ~ context.class;
path: PathProc ~ { ImagerPath.MapTrajectory[trajectory: trajectory,
moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, conicTo: conicTo, arcTo: arcTo] };
class.MaskStroke[context: context, path: path, closed: closed];
};
MaskVector: PUBLIC PROC[context: Context, p1, p2: VEC] ~ {
class: Class ~ context.class;
class.MaskVector[context: context, p1: p1, p2: p2];
};
MaskVectorI: PUBLIC PROC[context: Context, x1, y1, x2, y2: INTEGER] ~ {
class: Class ~ context.class;
class.MaskVector[context: context, p1: [x1, y1], p2: [x2, y2]];
};
MaskDashedStroke: PUBLIC PROC [context: Context, path: PathProc,
patternLen: NAT, pattern: PROC [NAT] RETURNS [REAL], offset, length: REAL] ~ {
class: Class ~ context.class;
class.MaskDashedStroke[context: context, path: path,
patternLen: patternLen, pattern: pattern, offset: offset, length: length];
};
MaskDashedStrokeTrajectory: PUBLIC PROC [context: Context, trajectory: Trajectory,
patternLen: NAT, pattern: PROC [NAT] RETURNS [REAL], offset, length: REAL] ~ {
class: Class ~ context.class;
path: PathProc ~ { ImagerPath.MapTrajectory[trajectory: trajectory,
moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, conicTo: conicTo, arcTo: arcTo] };
class.MaskDashedStroke[context: context, path: path,
patternLen: patternLen, pattern: pattern, offset: offset, length: length];
};
MaskPixel: PUBLIC PROC[context: Context, pa: PixelArray] ~ {
class: Class ~ context.class;
class.MaskPixel[context: context, pa: pa];
};
MaskBits: PUBLIC PROC[context: Context, base: LONG POINTER, wordsPerLine: NAT,
sMin, fMin, sSize, fSize: NAT, tx, ty: INTEGER] ~ {
class: Class ~ context.class;
class.MaskBits[context: context, base: base, wordsPerLine: wordsPerLine,
sMin: sMin, fMin: fMin, sSize: sSize, fSize: fSize, tx: tx, ty: ty];
};
DrawBits: PUBLIC PROC[context: Context, base: LONG POINTER, wordsPerLine: NAT,
sMin, fMin, sSize, fSize: NAT, tx, ty: INTEGER] ~ {
class: Class ~ context.class;
drawBitsAction: PROC ~ {
class.SetColor[context: context, color: white];
class.MaskRectangleI[context: context, x: tx, y: ty, w: fSize, h: -sSize];
class.SetColor[context: context, color: black];
class.MaskBits[context: context, base: base, wordsPerLine: wordsPerLine,
sMin: sMin, fMin: fMin, sSize: sSize, fSize: fSize, tx: tx, ty: ty];
};
IF class.DrawBits # NIL THEN class.DrawBits[context: context, base: base, wordsPerLine: wordsPerLine, sMin: sMin, fMin: fMin, sSize: sSize, fSize: fSize, tx: tx, ty: ty]
ELSE DoSave[context, drawBitsAction];
};
Clip: PUBLIC PROC[context: Context, path: PathProc, parity, exclude: BOOLFALSE] ~ {
class: Class ~ context.class;
class.Clip[context: context, path: path, oddWrap: parity, exclude: exclude];
};
ClipOutline: PUBLIC PROC[context: Context, outline: Outline, parity, exclude: BOOLFALSE] ~ {
class: Class ~ context.class;
path: PathProc ~ { ImagerPath.MapOutline[outline: outline,
moveTo: moveTo, lineTo: lineTo, curveTo: curveTo, conicTo: conicTo, arcTo: arcTo] };
class.Clip[context: context, path: path, oddWrap: parity, exclude: exclude];
};
ClipRectangle: PUBLIC PROC[context: Context, r: Rectangle, exclude: BOOLFALSE] ~ {
class: Class ~ context.class;
class.ClipRectangle[context: context, r: r, exclude: exclude];
};
ClipRectangleI: PUBLIC PROC[context: Context, x, y, w, h: INTEGER, exclude: BOOLFALSE] ~ {
class: Class ~ context.class;
class.ClipRectangleI[context: context, x: x, y: y, w: w, h: h, exclude: exclude];
};
SetInt: PUBLIC PROC[context: Context, key: IntKey, val: INT] ~ {
class: Class ~ context.class;
class.SetInt[context, key, val];
};
SetReal: PUBLIC PROC[context: Context, key: RealKey, val: REAL] ~ {
class: Class ~ context.class;
class.SetReal[context, key, val];
};
SetT: PUBLIC PROC[context: Context, m: Transformation] ~ {
class: Class ~ context.class;
class.SetT[context, m];
};
SetClipper: PUBLIC PROC[context: Context, clipper: Clipper] ~ {
class: Class ~ context.class;
class.SetClipper[context, clipper];
};
GetInt: PUBLIC PROC[context: Context, key: IntKey] RETURNS[INT] ~ {
class: Class ~ context.class;
RETURN[class.GetInt[context, key]];
};
GetReal: PUBLIC PROC[context: Context, key: RealKey] RETURNS[REAL] ~ {
class: Class ~ context.class;
RETURN[class.GetReal[context, key]];
};
GetT: PUBLIC PROC[context: Context] RETURNS[Transformation] ~ {
class: Class ~ context.class;
RETURN[class.GetT[context]];
};
GetFont: PUBLIC PROC[context: Context] RETURNS[Font] ~ {
class: Class ~ context.class;
RETURN[class.GetFont[context]];
};
GetColor: PUBLIC PROC[context: Context] RETURNS[Color] ~ {
class: Class ~ context.class;
RETURN[class.GetColor[context]];
};
GetClipper: PUBLIC PROC[context: Context] RETURNS[Clipper] ~ {
class: Class ~ context.class;
RETURN[class.GetClipper[context]];
};
GetCP: PUBLIC PROC[context: Context, rounded: BOOLFALSE] RETURNS[VEC] ~ {
class: Class ~ context.class;
RETURN[class.GetCP[context: context, rounded: rounded]];
};
GetBounds: PUBLIC PROC[context: Context] RETURNS[Rectangle] ~ {
class: Class ~ context.class;
IF class.GetBoundingRectangle = NIL THEN ERROR Error[[$unimplemented, "GetBounds not implemented for this context"]];
RETURN[class.GetBoundingRectangle[context: context]];
};
DoIfVisible: PUBLIC PROC [context: Context, r: Rectangle, action: PROC] ~ {
class: Class ~ context.class;
IF class.GetBoundingRectangle = NIL THEN action[]
ELSE {
bb: Box ~ BoxFromRect[class.GetBoundingRectangle[context: context]];
cb: Box ~ BoxFromRect[r];
ib: Box ~ IntersectBox[bb, cb];
IF ib.xmin < ib.xmax AND ib.ymin < ib.ymax THEN action[];
};
};
invert: PUBLIC ConstantColor ← ImagerColorPrivate.ColorFromStipple[
word: WORD.LAST, function: invert];
MakeStipple: PUBLIC PROC[stipple: WORDWORD.LAST, xor: BOOLFALSE]
RETURNS[ConstantColor] ~ {
IF xor AND stipple=WORD.LAST THEN RETURN[invert];
RETURN[ImagerColorPrivate.ColorFromStipple[
word: stipple, function: (IF xor THEN invert ELSE replace)]];
};
Bitmap: TYPE ~ ImagerBackdoor.Bitmap;
NewBitmap: PUBLIC PROC [width, height: NAT] RETURNS [Bitmap] ~ {
wordsPerLine: NAT ~ (width+15)/16;
words: INT ~ LONG[wordsPerLine]*height;
vm: CountedVM.Handle ~ CountedVM.SimpleAllocate[words];
RETURN[NEW[ImagerBackdoor.BitmapRep ← [ref: vm, base: vm.pointer,
wordsPerLine: wordsPerLine, width: width, height: height]]];
};
BitmapContext: PUBLIC PROC [bitmap: Bitmap] RETURNS [Context] ~ {
refRep: REF ImagerPixelMap.PixelMapRep ~ NEW[ImagerPixelMap.PixelMapRep ← [
ref: bitmap.ref, pointer: bitmap.base, words: LONG[bitmap.wordsPerLine]*bitmap.height,
lgBitsPerPixel: 0, rast: bitmap.wordsPerLine, lines: bitmap.height
]];
frame: ImagerPixelMap.PixelMap ~ [
sOrigin: 0, fOrigin: 0, sMin: 0, fMin: 0,
sSize: bitmap.height, fSize: bitmap.width, refRep: refRep
];
RETURN[ImagerRaster.Create[ImagerRaster.NewBitmapDevice[frame], TRUE]];
};
Exported to ImmutablePropList
This property list mechanism regards a PropList as an immutable value. We don't use the procedures from Atom since 1) they might smash an existing PropList, and 2) they hold a global monitor in AtomImpl.
PropList: TYPE ~ Atom.PropList;
Put: PUBLIC PROC[propList: PropList, key: REF, val: REF] RETURNS[PropList] ~ {
RETURN[CONS[NEW[Atom.DottedPairNode ← [key: key, val: val]], propList]];
};
Get: PUBLIC PROC[propList: PropList, key: REF] RETURNS[val: REF] ~ {
FOR list: PropList ← propList, list.rest UNTIL list=NIL DO
IF list.first.key=key THEN RETURN[list.first.val];
ENDLOOP;
RETURN[NIL];
};
Rem: PUBLIC PROC[propList: PropList, key: REF] RETURNS[PropList] ~ {
RETURN[Put[propList, key, NIL]];
};
Exported to ImagerBox
BoxFromRect: PUBLIC PROC [r: Rectangle] RETURNS [b: Box] ~ {
Pt: PROC [x, y: REAL] ~ INLINE {
IF x > b.xmax THEN b.xmax ← x ELSE IF x < b.xmin THEN b.xmin ← x;
IF y > b.ymax THEN b.ymax ← y ELSE IF y < b.ymin THEN b.ymin ← y;
};
b ← [r.x, r.y, r.x, r.y];
Pt[r.x+r.w, r.y+r.h];
};
RectFromBox: PUBLIC PROC [b: Box] RETURNS [Rectangle] ~ {
IF b.xmin > b.xmax THEN {t: REAL ← b.xmin; b.xmin ← b.xmax; b.xmax ← t};
IF b.ymin > b.ymax THEN {t: REAL ← b.ymin; b.ymin ← b.ymax; b.ymax ← t};
RETURN [[x: b.xmin, y: b.ymin, w: b.xmax-b.xmin, h: b.ymax-b.ymin]];
};
BoxFromExtents: PUBLIC PROC [e: ImagerFont.Extents] RETURNS [b: Box] ~ {
Pt: PROC [x, y: REAL] ~ INLINE {
IF x > b.xmax THEN b.xmax ← x ELSE IF x < b.xmin THEN b.xmin ← x;
IF y > b.ymax THEN b.ymax ← y ELSE IF y < b.ymin THEN b.ymin ← y;
};
b ← [e.rightExtent, e.ascent, e.rightExtent, e.ascent];
Pt[-e.leftExtent, -e.descent];
};
ExtentsFromBox: PUBLIC PROC [b: Box] RETURNS [ImagerFont.Extents] ~ {
IF b.xmin > b.xmax THEN {t: REAL ← b.xmin; b.xmin ← b.xmax; b.xmax ← t};
IF b.ymin > b.ymax THEN {t: REAL ← b.ymin; b.ymin ← b.ymax; b.ymax ← t};
RETURN [[leftExtent: -b.xmin, descent: -b.ymin, rightExtent: b.xmax, ascent: b.ymax]];
};
IntersectBox: PUBLIC PROC [a: Box, b: Box] RETURNS [c: Box] ~ {
IF a.xmin > a.xmax THEN {t: REAL ← a.xmin; a.xmin ← a.xmax; a.xmax ← t};
IF a.ymin > a.ymax THEN {t: REAL ← a.ymin; a.ymin ← a.ymax; a.ymax ← t};
IF b.xmin > b.xmax THEN {t: REAL ← b.xmin; b.xmin ← b.xmax; b.xmax ← t};
IF b.ymin > b.ymax THEN {t: REAL ← b.ymin; b.ymin ← b.ymax; b.ymax ← t};
c ← [xmin: MAX[a.xmin, b.xmin], ymin: MAX[a.ymin, b.ymin], xmax: MIN[a.xmax, b.xmax], ymax: MIN[a.ymax, b.ymax]];
IF c.xmin>=c.xmax OR c.ymin>=c.ymax THEN c ← [0, 0, 0, 0];
};
BoundingBox: PUBLIC PROC [a: Box, b: Box] RETURNS [c: Box] ~ {
IF a.xmin > a.xmax THEN {t: REAL ← a.xmin; a.xmin ← a.xmax; a.xmax ← t};
IF a.ymin > a.ymax THEN {t: REAL ← a.ymin; a.ymin ← a.ymax; a.ymax ← t};
IF b.xmin > b.xmax THEN {t: REAL ← b.xmin; b.xmin ← b.xmax; b.xmax ← t};
IF b.ymin > b.ymax THEN {t: REAL ← b.ymin; b.ymin ← b.ymax; b.ymax ← t};
c ← [xmin: MIN[a.xmin, b.xmin], ymin: MIN[a.ymin, b.ymin], xmax: MAX[a.xmax, b.xmax], ymax: MAX[a.ymax, b.ymax]];
};
BoundPoint: PUBLIC PROC [a: Box, b: VEC] RETURNS [Box] ~ {
IF a.xmin > a.xmax THEN {t: REAL ← a.xmin; a.xmin ← a.xmax; a.xmax ← t};
IF a.ymin > a.ymax THEN {t: REAL ← a.ymin; a.ymin ← a.ymax; a.ymax ← t};
RETURN [[xmin: MIN[a.xmin, b.x], ymin: MIN[a.ymin, b.y], xmax: MAX[a.xmax, b.x], ymax: MAX[a.ymax, b.y]]];
};
END.