NewImagerLFImpl.mesa
Last edited by:
Doug Wyatt, October 6, 1983 10:27 am
DIRECTORY
BitBlt USING [AlignedBBTable, BBTableSpace, BITBLT, BitBltTablePtr],
Environment USING [bitsPerWord],
Font USING [FONT],
Imager,
ImagerBasic,
ImagerFontCache,
ImagerFrameBuffer USING [LFDisplay],
ImagerHalftone,
ImagerMasks,
ImagerPixelMaps,
ImagerPrivate,
ImagerScanConverter,
ImagerStroke,
ImagerTransform,
Inline,
Real USING [RoundLI],
Scaled,
TerminalMultiplex USING [SelectTerminal],
UserTerminal USING [GetState, SetState];
ImagerLFImpl: CEDAR MONITOR
IMPORTS BitBlt, Imager, ImagerFrameBuffer, ImagerFontCache, ImagerHalftone, ImagerMasks, ImagerPixelMaps, ImagerPrivate, ImagerScanConverter, ImagerStroke, ImagerTransform, Inline, Real, Scaled, TerminalMultiplex, UserTerminal
SHARES Font
= BEGIN OPEN ImagerBasic;
FONT: TYPE ~ Font.FONT;
Mask: TYPE ~ ImagerMasks.Mask;
PixelMap: TYPE ~ ImagerPixelMaps.PixelMap;
Tile: TYPE ~ ImagerPixelMaps.Tile;
SpecialColor: TYPE ~ REF ColorRep[special];
Name: TYPE = ImagerPrivate.Name;
Context: TYPE = Imager.Context;
Data: TYPE = REF DataRep;
DataRep: TYPE = RECORD[
canvas: PixelMap,
cpx, cpy: REAL ← 0,
correctMX, correctMY: REAL ← 0,
T: Transformation ← NIL,
priorityImportant: INT ← 0,
mediumXSize, mediumYSize: REAL ← 0,
fieldXMin, fieldYMin, fieldXMax, fieldYMax: REAL ← 0,
showVec: REFNIL,
color: Color ← NIL,
noImage: INT ← 0,
strokeWidth: REAL ← 0,
strokeEnd: INT ← 0,
underlineStart: REAL ← 0,
amplifySpace: REAL ← 1.0,
correctPass: INT ← 0,
correctShrink: REAL ← 0.5,
correctTX, correctTY: REAL ← 0,
correctMaskCount: INT ← 0,
correctMaskX, correctMaskY: REAL ← 0,
correctSumX, correctSumY: REAL ← 0,
correctSpaceX, correctSpaceY: REAL ← 0,
correctcpx, correctcpy: REAL ← 0,
correctTargetX, correctTargetY: REAL ← 0
];
DataRep: TYPE ~ RECORD [
currentColor: Color,
clientClipper: Mask, -- in device coords
clientClipperPresent: BOOLEAN,
clientClipperExclude: BOOLEAN,
compositeClipperValid: BOOLEAN,
doSaveCount: [0..1000) ← 0,
compositeClipper: Mask, -- in device coords
viewClipper: Mask, -- in device coords
sOriginView, fOriginView: INTEGER,
sOriginBrick, fOriginBrick: INTEGER,
currentPosition: Pair, -- in device space
transformation: Transformation,
viewToDevice: Transformation,
surfaceToDevice: Transformation,
devicePath: ImagerScanConverter.DevicePath,
lineBuffer: Mask,
tile: Tile,
tileSamples: SampledColor,
phase: INTEGER,
canvas: PixelMap
];
LFBrick: ImagerHalftone.DeviceBrick ← ImagerHalftone.MakeSquareBrick[4, 3, 2, 1, 1, 255];
Init: PROC [context: Context, info: REF] ~ {
data: Data = NEW[DataRep ← []];
TRUSTED {data.canvas ← ImagerFrameBuffer.LFDisplay[]};
data.tile ← ImagerPixelMaps.CreateTile[
pixelMap: ImagerPixelMaps.Create[lgBitsPerPixel: 0, bounds: [0, 0, 16, 16]]];
data.T ← ImagerOps.Scale[1];
data.color ← Imager.black;
context.data ← data;
};
Reset: PROC[context: Context] ~ {
data: Data ← NARROW[context.data];
data.phase ← 0;
data.devicePath ← NIL;
TRUSTED {data.canvas ← ImagerFrameBuffer.LFDisplay[]};
data.transformation ← data.viewToDevice ← data.surfaceToDevice ← ImagerTransform.Concat[[1,0,0,0,1,0,hard], ImagerTransform.Create[0, -1, data.canvas.sSize, 1, 0, 0]];
data.clientClipperPresent ← data.compositeClipperValid ← FALSE;
data.currentPosition ← [0, 0];
data.viewClipper ← ImagerMasks.Box[
[sMin: 0, fMin: 0, sSize: data.canvas.sSize, fSize: data.canvas.fSize]];
[[data.sOriginView, data.fOriginView]] ← [[data.sOriginBrick, data.fOriginBrick]] ← ImagerTransform.IntTransform[[0,0], data.surfaceToDevice];
SetColor[data, Imager.black];
};
IGet: PROC[context: Context, n: Name] RETURNS[REF] = {
data: Data = NARROW[context.data];
FromReal: PROC[x: REF] RETURNS[REAL] = { RETURN[NEW[REAL ← x]] };
FromInt: PROC[x: REF] RETURNS[INT] = { RETURN[NEW[INT ← x]] };
SELECT n FROM
$cpx => RETURN[FromReal[data.cpx]];
$cpy => RETURN[FromReal[data.cpy]];
$correctMX => RETURN[FromReal[data.correctMX]];
$correctMY => RETURN[FromReal[data.correctMY]];
$T: Transformation => RETURN[data.T];
$priorityImportant => RETURN[FromInt[data.priorityImportant]];
$mediumXSize => RETURN[FromReal[data.mediumXSize]];
$mediumYSize => RETURN[FromReal[data.mediumYSize]];
$fieldXMin => RETURN[FromReal[data.fieldXMin]];
$fieldYMin => RETURN[FromReal[data.fieldYMin]];
$fieldXMax => RETURN[FromReal[data.fieldXMax]];
$fieldYMax => RETURN[FromReal[data.fieldYMax]];
$showVec => RETURN[data.showVec];
$color => RETURN[data.color];
$noImage => RETURN[FromInt[data.noImage]];
$strokeWidth => RETURN[FromReal[data.strokeWidth]];
$strokeEnd => RETURN[FromInt[data.strokeEnd]];
$underlineStart => RETURN[FromReal[data.underlineStart]];
$amplifySpace => RETURN[FromReal[data.amplifySpace]];
$correctPass => RETURN[FromInt[data.correctPass]];
$correctShrink => RETURN[FromReal[data.correctShrink]];
$correctTX => RETURN[FromReal[data.correctTX]];
$correctTY => RETURN[FromReal[data.correctTY]];
$clipOutline => ERROR;
ENDCASE => ERROR;
};
ISet: PROC[context: Context, n: Name, x: REF] = {
data: Data = NARROW[context.data];
ToReal: PROC[x: REF] RETURNS[REAL] = { RETURN[
WITH x SELECT FROM x: REF REAL => x^, ENDCASE => ERROR] };
ToInt: PROC[x: REF] RETURNS[INT] = { RETURN[
WITH x SELECT FROM x: REF INT => x^, ENDCASE => ERROR] };
SELECT n FROM
$cpx => data.cpx ← ToReal[x];
$cpy => data.cpy ← ToReal[x];
$correctMX => data.correctMX ← ToReal[x];
$correctMY => data.correctMY ← ToReal[x];
$T: Transformation => data.TNARROW[x];
$priorityImportant => data.priorityImportant ← ToInt[x];
$mediumXSize => data.mediumXSize ← ToReal[x];
$mediumYSize => data.mediumYSize ← ToReal[x];
$fieldXMin => data.fieldXMin ← ToReal[x];
$fieldYMin => data.fieldYMin ← ToReal[x];
$fieldXMax => data.fieldXMax ← ToReal[x];
$fieldYMax => data.fieldYMax ← ToReal[x];
$showVec => data.showVec ← NARROW[x];
$color => data.color ← NARROW[x];
$noImage => data.noImage ← ToInt[x];
$strokeWidth => data.strokeWidth ← ToReal[x];
$strokeEnd => data.strokeEnd ← ToInt[x];
$underlineStart => data.underlineStart ← ToReal[x];
$amplifySpace => data.amplifySpace ← ToReal[x];
$correctPass => data.correctPass ← ToInt[x];
$correctShrink => data.correctShrink ← ToReal[x];
$correctTX => data.correctTX ← ToReal[x];
$correctTY => data.correctTY ← ToReal[x];
$clipOutline => ERROR;
ENDCASE => ERROR;
};
IGetReal: PROC[context: Context, n: Name] RETURNS[REAL] = {
data: Data = NARROW[context.data];
SELECT n FROM
$cpx => RETURN[data.cpx];
$cpy => RETURN[data.cpy];
$correctMX => RETURN[data.correctMX];
$correctMY => RETURN[data.correctMY];
$mediumXSize => RETURN[data.mediumXSize];
$mediumYSize => RETURN[data.mediumYSize];
$fieldXMin => RETURN[data.fieldXMin];
$fieldYMin => RETURN[data.fieldYMin];
$fieldXMax => RETURN[data.fieldXMax];
$fieldYMax => RETURN[data.fieldYMax];
$strokeWidth => RETURN[data.strokeWidth];
$underlineStart => RETURN[data.underlineStart];
$amplifySpace => RETURN[data.amplifySpace];
$correctShrink => RETURN[data.correctShrink];
$correctTX => RETURN[data.correctTX];
$correctTY => RETURN[data.correctTY];
ENDCASE => ERROR;
};
ISetReal: PROC[context: Context, n: Name, x: REAL] = {
data: Data = NARROW[context.data];
SELECT n FROM
$cpx => data.cpx ← x;
$cpy => data.cpy ← x;
$correctMX => data.correctMX ← x;
$correctMY => data.correctMY ← x;
$mediumXSize => data.mediumXSize ← x;
$mediumYSize => data.mediumYSize ← x;
$fieldXMin => data.fieldXMin ← x;
$fieldYMin => data.fieldYMin ← x;
$fieldXMax => data.fieldXMax ← x;
$fieldYMax => data.fieldYMax ← x;
$strokeWidth => data.strokeWidth ← x;
$underlineStart => data.underlineStart ← x;
$amplifySpace => data.amplifySpace ← x;
$correctShrink => data.correctShrink ← x;
$correctTX => data.correctTX ← x;
$correctTY => data.correctTY ← x;
ENDCASE => ERROR;
};
IGetInt: PROC[context: Context, n: Name] RETURNS[INT] = {
data: Data = NARROW[context.data];
SELECT n FROM
$priorityImportant => RETURN[data.priorityImportant];
$noImage => RETURN[data.noImage];
$strokeEnd => RETURN[data.strokeEnd];
$correctPass => RETURN[data.correctPass];
ENDCASE => ERROR;
};
ISetInt: PROC[context: Context, n: Name, x: INT] = {
data: Data = NARROW[context.data];
SELECT n FROM
$priorityImportant => data.priorityImportant ← x;
$noImage => data.noImage ← x;
$strokeEnd => data.strokeEnd ← x;
$correctPass => data.correctPass ← x;
ENDCASE => ERROR;
};
InnerDoSave: PROC[data: Data, body: PROC, all: BOOL] = {
data: Data = NARROW[context.data];
saved: DataRep;
Save: PROC = {
saved ← data^;
};
Restore: PROC = {
IF NOT all THEN {
saved.cpx ← data.cpx; saved.cpy ← data.cpy;
saved.correctMX ← data.correctMX; saved.correctMY ← data.correctMY;
};
data^ ← saved;
};
Save[]; body[!UNWIND => Restore[]]; Restore[];
};
DoSave: PROC[context: Context, body: PROC] = {
data: Data = NARROW[context.data];
InnerDoSave[data, body, FALSE];
};
DoSaveAll: PROC[context: Context, body: PROC] = {
data: Data = NARROW[context.data];
InnerDoSave[data, body, TRUE];
};
ConcatT: PROC [context: Context, m: Transformation] = {
data: Data = NARROW[context.data];
data.T ← ImagerOps.Concat[m, data.T];
};
TranslateT: PROC [context: Context, x, y: REAL] ~ {
ConcatT[context, ImagerOps.Translate[x, y]];
};
RotateT: PROC [context: Context, degrees: REAL] ~ {
ConcatT[context, ImagerOps.Rotate[degrees]];
};
ScaleT: PROC [context: Context, s: REAL] ~ {
ConcatT[context, ImagerOps.Scale[s]];
};
Scale2T: PROC [context: Context, sx, sy: REAL] ~ {
ConcatT[context, ImagerOps.Scale2[sx, sy]];
};
Move: PROC[context: Context] = {
data: Data = NARROW[context.data];
data.T ← ImagerOps.TranslateTo[data.T, [data.cpx, data.cpy]];
};
Trans: PROC[context: Context] = {
data: Data = NARROW[context.data];
data.T ← ImagerOps.TranslateTo[data.T, DRound[data.cpx, data.cpy]];
};
SetXY: PROC[context: Context, p: Pair] = {
data: Data = NARROW[context.data];
[data.cpx, data.cpy] ← ImagerOps.Transform[data.T, p];
};
IntegerSetXY: PROC[context: Context, x, y: INTEGER] = {
SetXY[context, [x, y]];
};
SetXYRel: PROC [context: Context, v: Pair] = {
data: Data = NARROW[context.data];
delta: Pair = ImagerOps.TransformVec[data.T, v];
data.cpx ← data.cpx + delta.x;
data.cpy ← data.cpy + delta.y;
};
IntegerSetXYRel: PROC [context: Context, x, y: INTEGER] = {
SetXYRel[context, [x, y]];
};
GetCP: PROC[context: Context] RETURNS[Pair] = {
data: Data = NARROW[context.data];
RETURN[ImagerOps.InverseTransform[data.T, [data.cpx, data.cpy]]];
};
GetCPRounded: PROC[context: Context] RETURNS[Pair] = {
data: Data = NARROW[context.data];
RETURN[ImagerOps.InverseTransform[data.T, DRound[[data.cpx, data.cpy]]]];
};
inkTile: Tile ← ImagerPixelMaps.TileFromConstant[pixelValue: 1, lgBitsPerPixel: 0];
ApplyMask: PROC[data: Data, mask: Mask] = {
clippedMask: Mask = mask.And[CompositeClipper[data]];
IF clippedMask.sSize = 0 THEN RETURN;
SELECT data.color FROM
Imager.black => ImagerMasks.MaskTile[
data.canvas, clippedMask, inkTile];
Imager.white => ImagerMasks.MaskTile[
data.canvas, clippedMask, inkTile, [and, complement]];
Imager.XOR => ImagerMasks.MaskTile[
data.canvas, clippedMask, inkTile, [xor, null]];
ENDCASE => WITH data.color SELECT FROM
sampledColor: SampledColor => {
transform: Transformation ← ImagerTransform.Concat[sampledColor.m, data.viewToDevice];
ImagerHalftone.Halftone[data.canvas, clippedMask, sampledColor.pa, transform, LFBrick];
ERROR;
};
ENDCASE => { -- constant (other than black or white) or stipple
ImagerMasks.MaskTile[data.canvas, clippedMask, data.tile];
};
};
MaskFill: PROC[context: Context, pathMap: PathMapType, pathData: REF] = {
data: Data = NARROW[context.data];
ApplyMask[data, MaskFromPath[data, pathMap, pathData]];
};
MakeTileSamples: PROC[xSize, ySize: NAT] RETURNS[tileSamples: SampledColor] ~ {
tileSamples ← NEW[ColorRep[sampled]];
tileSamples.transparent ← FALSE;
tileSamples.pa ← NEW[PixelArrayRep];
tileSamples.m ← ImagerTransform.Rotate[0];
tileSamples.colorMap ← $Intensity8bpp;
tileSamples.pa.xPixels ← xSize;
tileSamples.pa.yPixels ← ySize;
tileSamples.pa.maxSampleValue ← 255;
tileSamples.pa.samplesPerPixel ← 1;
tileSamples.pa.get ← ConstantGet;
tileSamples.pa.data ← NEW[NAT ← 0];
};
SetTileSamples: PROC[tileSamples: SampledColor, intensity: [0..255]] ~ {
WITH tileSamples.pa.data SELECT FROM
n: REF NAT => n^ ← intensity;
ENDCASE => ERROR;
};
ConstantGet: PROC[self: PixelArray, buffer: PixelBuffer, nSamples: NAT, layer: INT, xStart, yStart: Scaled.Value, xDelta, yDelta: Scaled.Value] ~ {
WITH self.data SELECT FROM
n: REF NAT => {
value: NAT ← n^;
FOR i: NAT IN [0..nSamples) DO buffer[i] ← value ENDLOOP;
};
ENDCASE => ERROR;
};
Clipper: TYPE = REF ClipperRep;
ClipperRep: TYPE ~ RECORD [
exclude: BOOLEAN,
mask: Mask
];
GetClipper: PROC[context: Context] RETURNS[Clipper] ~ {
data: Data = NARROW[context.data];
IF data.clientClipperPresent THEN {
clipper: Clipper = NEW[ClipperRep];
clipper.exclude ← data.clientClipperExclude;
clipper.mask ← data.clientClipper.InlineShift[-data.sOriginView, -data.fOriginView];
ccCount ← ccCount + 1;
RETURN [clipper]
}
ELSE RETURN [NIL]
};
SetClipper: PROC[context: Context, clipper: Clipper] ~ {
data: Data = NARROW[context.data];
IF clipper = NIL THEN {
data.clientClipperPresent ← FALSE;
data.clientClipper.refRep ← NIL;
ccCount ← ccCount + 1;
}
ELSE {
data.clientClipperPresent ← TRUE;
data.clientClipperExclude ← clipper.exclude;
data.clientClipper ← clipper.mask.Shift[data.sOriginView, data.fOriginView];
ccCount ← ccCount + 1;
};
data.compositeClipperValid ← FALSE;
};
MaskFromPath: PROC [data: Data, pathMap: PathMapType, pathData: REF]
RETURNS [mask: Mask] = {
GenPath: ImagerScanConverter.PathProc
move: PROC [s, f: REAL],
line: PROC [s, f: REAL],
curve: PROC [s1, f1, s2, f2, s3, f3: REAL]
= {
m: Transformation ← data.transformation;
Xform: PROC [p: Pair] RETURNS [Pair] ~ {RETURN[[
Transforms (x, y) to (s, f) — note s comes first for ScanConvert!
m.a * p.x + m.b * p.y + m.c,
m.d * p.x + m.e * p.y + m.f
]]};
Xmove: PROC [p: Pair] ~ { q: Pair = Xform[p]; move[q.x, q.y] };
Xline: PROC [p: Pair] ~ { q: Pair = Xform[p]; line[q.x, q.y] };
Xcurve: PROC [p1, p2, p3: Pair] ~ {
q1: Pair = Xform[p1]; q2: Pair = Xform[p2]; q3: Pair = Xform[p3];
curve[q1.x, q1.y, q2.x, q2.y, q3.x, q3.y] };
pathMap[pathData, Xmove, Xline, Xcurve, NIL];
};
Runs: PROC[
run: PROC[sMin, fMin: INTEGER, fSize: NAT],
repeat: PROC[timesToRepeatScanline: NAT]] = {
data.devicePath.ConvertToRuns[runProc: run];
};
data.devicePath ← ImagerScanConverter.CreatePath[pathProc: GenPath, scratch: data.devicePath];
mask ← ImagerMasks.Create[Runs];
};
MaskFromStroke: PROC [data: Data, pathMap: PathMapType, pathData: REF,
strokeWidth: REAL, strokeEnd: StrokeEnd, closed: BOOL]
RETURNS [mask: Mask] = {
Runs: PROC[
run: PROC[sMin, fMin: INTEGER, fSize: NAT],
repeat: PROC[timesToRepeatScanline: NAT]] = {
data.devicePath.ConvertToRuns[runProc: run];
};
data.devicePath ← ImagerStroke.DevicePathFromStroke[
pathClosure: [pathMap, pathData],
clientToDevice: data.transformation,
width: strokeWidth,
strokeEnd: strokeEnd,
closed: FALSE,
scratch: data.devicePath
];
mask ← ImagerMasks.Create[Runs];
};
MaskFromRectangle: PROC [data: Data, area: Rectangle] RETURNS [mask: Mask] ~ {
GenPath: ImagerScanConverter.PathProc
move: PROC [s, f: REAL],
line: PROC [s, f: REAL],
curve: PROC [s1, f1, s2, f2, s3, f3: REAL]
= {
m: Transformation ← data.transformation;
Xform: PROC [p: Pair] RETURNS [Pair] ~ {RETURN[[
Transforms (x, y) to (s, f) — note s comes first for ScanConvert!
m.a * p.x + m.b * p.y + m.c,
m.d * p.x + m.e * p.y + m.f
]]};
{ q: Pair = Xform[[area.x, area.y]]; move[q.x, q.y] };
{ q: Pair = Xform[[area.x + area.w, area.y]]; line[q.x, q.y] };
{ q: Pair = Xform[[area.x + area.w, area.y + area.h]]; line[q.x, q.y] };
{ q: Pair = Xform[[area.x, area.y + area.h]]; line[q.x, q.y] };
};
Runs: PROC[
run: PROC[sMin, fMin: INTEGER, fSize: NAT],
repeat: PROC[timesToRepeatScanline: NAT]] = {
data.devicePath.ConvertToRuns[runProc: run];
};
IF data.transformation.type # hard THEN {
p1: Pair ← ImagerTransform.Transform[[area.x, area.y], data.transformation];
p2: Pair ← ImagerTransform.Transform[[area.x+area.w, area.y+area.h], data.transformation];
sMin: INTEGER ← Real.RoundLI[MAX[MIN[p1.x, p2.x], -LAST[INTEGER]/2]];
sMax: INTEGER ← Real.RoundLI[MIN[MAX[p1.x, p2.x], LAST[INTEGER]/2]];
fMin: INTEGER ← Real.RoundLI[MAX[MIN[p1.y, p2.y], -LAST[INTEGER]/2]];
fMax: INTEGER ← Real.RoundLI[MIN[MAX[p1.y, p2.y], LAST[INTEGER]/2]];
RETURN [ImagerMasks.InlineBox[
[sMin: sMin, fMin: fMin, sSize: sMax-sMin, fSize: fMax-fMin]]];
};
data.devicePath ← ImagerScanConverter.CreatePath[pathProc: GenPath, scratch: data.devicePath];
mask ← ImagerMasks.Create[Runs];
};
ScaledFromReal: PROC [real: REAL] RETURNS [Scaled.Value] ~ TRUSTED {
Because of an apparent bug in Real.FScale.
i: INT ← Real.RoundLI[real * 65536.0];
RETURN[LOOPHOLE[i]]
};
MaskFromPixelArray: PROC[data: Data, pixelArray: PixelArray] RETURNS[Mask] = {
destArea: Mask ← MaskFromRectangle[data, [0, 0, pixelArray.xPixels, pixelArray.yPixels]];
Runs: PROC[
run: PROC[sMin, fMin: INTEGER, fSize: NAT],
repeat: PROC[timesToRepeatScanline: NAT]] = {
buffer: PixelBuffer ← NEW[PixelBufferRep[destArea.fSize+1]];
DoRun: PROC[sMin, fMin: INTEGER, fSize: CARDINAL] = {
nextPixel: Pair ← ImagerTransform.InverseTransformVec[[0, 1], data.transformation];
start: Pair ← ImagerTransform.InverseTransform[[0.5+sMin, 0.5+fMin], data.transformation];
xStart: Scaled.Value ← ScaledFromReal[start.x];
yStart: Scaled.Value ← ScaledFromReal[start.y];
xDeltaPixel: Scaled.Value ← ScaledFromReal[nextPixel.x];
yDeltaPixel: Scaled.Value ← ScaledFromReal[nextPixel.y];
runStart: NAT ← 0;
fRel: NAT ← 0;
pixelArray.get[pixelArray, buffer, fSize, 0, xStart, yStart, xDeltaPixel, yDeltaPixel];
WHILE fRel < fSize DO
buffer[fSize] ← 0;
WHILE buffer[fRel] # 0 DO fRel ← fRel + 1 ENDLOOP;
IF fRel > runStart THEN {run[sMin, fMin + fRel, fRel - runStart]};
buffer[fSize] ← 1;
WHILE buffer[fRel] = 0 DO fRel ← fRel + 1 ENDLOOP;
runStart ← fRel;
ENDLOOP;
};
destArea.MapRuns[DoRun];
};
RETURN [ImagerMasks.Create[Runs]];
};
CompositeClipper: PROC [data: Data] RETURNS [Mask] ~ {
IF NOT data.compositeClipperValid THEN {
IF data.clientClipperPresent THEN {
IF data.clientClipperExclude THEN data.compositeClipper ← data.viewClipper.Difference[data.clientClipper]
ELSE data.compositeClipper ← data.viewClipper.And[data.clientClipper];
}
ELSE data.compositeClipper ← data.viewClipper;
data.compositeClipperValid ← TRUE;
};
RETURN [data.compositeClipper]
};
ccCount: INT ← 0;
ClipMask: PROC [data: Data, mask: Mask, exclude: BOOLEANFALSE] ~ {
data.compositeClipperValid ← FALSE;
IF NOT data.clientClipperPresent THEN {
data.clientClipperPresent ← TRUE;
data.clientClipperExclude ← exclude;
data.clientClipper ← mask;
ccCount ← ccCount + 1;
}
ELSE IF exclude THEN {
IF data.clientClipperExclude THEN {
data.clientClipper ← data.clientClipper.Or[mask];
ccCount ← ccCount + 1;
}
ELSE {
data.clientClipper ← data.clientClipper.Difference[mask];
ccCount ← ccCount + 1;
};
}
ELSE {
IF data.clientClipperExclude THEN {
data.clientClipper ← mask.Difference[data.clientClipper];
ccCount ← ccCount + 1;
data.clientClipperExclude ← FALSE;
}
ELSE {
data.clientClipper ← data.clientClipper.And[mask];
ccCount ← ccCount + 1;
};
};
};
ClipOutline: PROC [context: Context, pathMap: PathMapType, pathData: REF] = {
data: Data ← NARROW[context.data];
ClipMask[data, MaskFromPath[data, pathMap, pathData]];
};
ClipRectangle: PROC [context: Context, x, y, w, h: REAL] ~ {
data: Data = NARROW[context.data];
ClipMask[data, MaskFromRectangle[data, [x, y, w, h]]];
};
TestRectangle: PROC [context: Context, area: Rectangle] RETURNS [Visibility] ~ {
data: Data ← NARROW[context.data];
mask: Mask ← MaskFromRectangle[data, area];
RETURN [mask.IsVisible[CompositeClipper[data]]];
};
IntegerClipRectangle: PROC[context: Context, x, y, w, h: INTEGER] ~ {
ClipRectangle[context, x, y, w, h];
};
IntegerExcludeRectangle: PROC[context: Context, x, y, w, h: INTEGER] ~ {
data: Data = NARROW[context.data];
ClipMask[data, MaskFromRectangle[data, [x, y, w, h]], TRUE];
};
TestIntRectangle: PROC [context: Context, area: IntRectangle] RETURNS [Visibility] ~ {
RETURN [TestRectangle[context, [area.x, area.y, area.w, area.h]]];
};
DoWithoutClipping: PROC [context: Context, bounds: IntRectangle, callBack: PROC[Context]] ~ {
callBack[context];
};
SetColor: PROC[data: Data, color: Color] ~ {
IF color = data.currentColor THEN RETURN;
data.currentColor ← color;
IF color = Imager.black OR color = Imager.white THEN RETURN;
WITH color SELECT FROM
constantColor: ConstantColor => {
intensity: INT ← constantColor.Y;
intensity ← (intensity + 127)/(LAST[CARDINAL]/255);
SetTileSamples[data.tileSamples, intensity];
ImagerHalftone.Halftone[
dest: [sOrigin: data.tile.sOrigin, fOrigin: data.tile.fOrigin, sMin: 0, fMin: 0, sSize: data.tile.sSize, fSize: data.tile.fSize, refRep: data.tile.refRep],
mask: ImagerMasks.Box[[0, 0, 16, 16]],
source: data.tileSamples.pa,
transformation: ImagerTransform.Rotate[0],
deviceBrick: LFBrick
];
};
specialColor: SpecialColor => {
WITH specialColor.ref SELECT FROM
stipple: REF CARDINAL =>
data.tile ← ImagerPixelMaps.TileFromStipple[stipple: stipple^, scratch: data.tile.refRep];
atom: ATOM => {
SELECT atom FROM
$XOR => NULL;
ENDCASE => data.currentColor ← Imager.black;
};
ENDCASE => ERROR;
};
sampledColor: SampledColor => NULL;
ENDCASE => data.currentColor ← Imager.black;
};
MaskStroke: PROC[context: Context, pathMap: PathMapType, pathData: REF,
strokeWidth: REAL, strokeEnd: StrokeEnd] = {
data: Data = NARROW[context.data];
mask: ImagerMasks.Mask ← MaskFromStroke[data, pathMap, pathData, strokeWidth, strokeEnd, FALSE];
ApplyMask[data, mask];
};
MaskStrokeClosed: PROC[context: Context, pathMap: PathMapType, pathData: REF,
strokeWidth: REAL] = {
data: Data = NARROW[context.data];
mask: ImagerMasks.Mask ← MaskFromStroke[data, pathMap, pathData, strokeWidth, nil, TRUE];
ApplyMask[data, mask];
};
MaskVector: PROC[context: Context, x1, y1, x2, y2: REAL] = {
ERROR;
};
IntegerMaskVector: PROC[context: Context, x1, y1, x2, y2: INTEGER] = {
MaskVector[context, x1, y1, x2, y2];
};
MaskPixel: PROC [context: Context, pa: PixelArray] ~ {
data: Data ← NARROW[context.data];
mask: Mask ← MaskFromPixelArray[data, pa];
ApplyMask[data, mask];
};
scratchPixelArray: PixelArray ← NEW[PixelArrayRep];
scratchBitmapDesc: REF ImagerPixelMaps.PixelMapRep ← NEW[ImagerPixelMaps.PixelMapRep];
MaskBits: ENTRY PROC [context: Context, base: LONG POINTER, raster: CARDINAL, tile: IntRectangle, area: IntRectangle] ~ {
ENABLE UNWIND => NULL;
data: Data ← NARROW[context.data];
color: Color ← data.currentColor;
IF data.transformation.type = rot90 AND tile.w = 16 AND raster = 1 AND tile.h <= 16 AND (color = Imager.black OR color = Imager.XOR) THEN {
sMin, fMin, sSize, fSize: INTEGER;
sMinTile, fMinTile, sSizeTile, fSizeTile: INTEGER;
[[sMin, fMin, sSize, fSize]] ← ImagerTransform.TransformIntRectangle[area, data.transformation];
[[sMinTile, fMinTile, sSizeTile, fSizeTile]] ← ImagerTransform.TransformIntRectangle[tile, data.transformation];
scratchBitmapDesc.pointer ← base;
scratchBitmapDesc.rast ← raster;
scratchBitmapDesc.lines ← sSizeTile;
ImagerMasks.MaskTile[data.canvas,
CompositeClipper[data].And[[sMin, fMin, sSize, fSize, NIL]],
[sMinTile, fMinTile, sSizeTile, fSizeTile, 0, scratchBitmapDesc],
IF color = Imager.black THEN [or, null] ELSE [xor, null]];
}
ELSE {
IF firstBadMaskBits THEN {firstBadMaskBits ← FALSE; ERROR}
-- sorry, not yet.
};
};
firstBadMaskBits: BOOLEANTRUE;
MaskSegment: PROC [context: Context, p: Pair] ~ {
Not implemented yet
};
MaskIntSegment: PROC [context: Context, p: IntPair] ~ {
Not implemented yet
};
MaskRectangle: PROC[context: Context, x, y, w, h: REAL] = {
data: Data ← NARROW[context.data];
mask: Mask ← MaskFromRectangle[data, [x, y, w, h]];
ApplyMask[data, mask];
};
IntegerMaskRectangle: PROC[context: Context, x, y, w, h: INTEGER] = {
data: Data ← NARROW[context.data];
mask: Mask ← MaskFromRectangle[data, [x, y, w, h]];
ApplyMask[data, mask];
};
StartUnderline: PROC[context: Context] = {
ERROR;
};
MaskUnderline: PROC[context: Context, dy, h: REAL] = {
ERROR;
};
IntegerMaskUnderline: PROC[context: Context, dy, h: INTEGER] = {
MaskUnderline[context, dy, h];
};
rasterToRunGroupStorageRatio: INT ← 1;
CharLoadInfo: TYPE = RECORD[sWidth, fWidth: Scaled.Value, mask: Mask, loadRepSize: INT];
MaskAndRunCount: TYPE ~ RECORD [mask: Mask, nRuns: INT];
GetCharMask: PROC [font: FONT, transformation: Transformation, char: CHAR]
RETURNS [ans: MaskAndRunCount] ~ {
nRuns: INT ← 0;
Runs: PROC[
run: PROC[sMin, fMin: INTEGER, fSize: NAT],
repeat: PROC[timesToRepeatScanline: NAT]] ~ {
Run: PROC [sMin, fMin: INTEGER, fSize: NAT] ~ {
run[sMin: sMin, fMin: fMin, fSize: fSize];
nRuns ← nRuns + 1;
};
font.fontGraphicsClass.maskProc[font, transformation, char, Run];
};
nRuns ← 0;
ans.mask ← ImagerMasks.Create[Runs];
ans.nRuns ← nRuns;
};
FontCompositeTransform: PROC [data: Data, font: FONT] RETURNS [t: Transformation] ~ {
t ← data.transformation;
t.c ← t.f ← 0;
t ← ImagerTransform.Concat[font.actualTransformation, t];
};
fontCache: ImagerFontCache.FontCache ← ImagerFontCache.Create[];
FontData: TYPE = REF FontDataRep;
FontDataRep: TYPE = RECORD[
];
LoadCharData: PROC[self: ImagerFontCache.FontObject, charCode: CARDINAL]
RETURNS [charData: REF, memoryCost: INT] = {
font: FONT = NARROW[self.fontAnyData];
char: CHAR = 0C+charCode; -- does this bounds check properly?
transform: Transformation = ImagerTransform.Create[self.r0, self.r1, self.r2, self.r3, self.r4, self.r5]; -- character (to client) to device
clientTransform: Transformation = ImagerTransform.Concat[
ImagerTransform.Invert[font.actualTransformation], transform];
loadInfo: REF CharLoadInfo ← NEW[CharLoadInfo];
maskN: MaskAndRunCount ← GetCharMask[font, transform, char];
runGroupSize: INT ← maskN.nRuns * 2 + 2;
rasterSize: INT ← maskN.mask.sSize * INT[(maskN.mask.fSize+15)/16] + 2;
width: Pair ← ImagerTransform.TransformVec[font.fontGraphicsClass.widthVectorProc[font, char], clientTransform];
loadInfo.mask ← maskN.mask;
SELECT TRUE FROM
maskN.mask.sSize = 0 OR maskN.mask.fSize = 0 => {loadInfo.loadRepSize ← 0};
maskN.mask.fSize > 32*Environment.bitsPerWord OR
runGroupSize*rasterToRunGroupStorageRatio < rasterSize => {loadInfo.loadRepSize ← runGroupSize};
ENDCASE => {loadInfo.loadRepSize ← rasterSize; loadInfo.mask ← loadInfo.mask.Bitmap};
loadInfo.sWidth ← Scaled.FromReal[width.x];
loadInfo.fWidth ← Scaled.FromReal[width.y];
RETURN[loadInfo, 0];
};
ShowChar: PROC [context: Context, char: CHAR, font: FONT] ~ {
data: Data = NARROW[context.data];
transform: Transformation ← FontCompositeTransform[data, font];
fontCode: ImagerFontCache.FontCode ← ImagerFontCache.GetFontCode[[
CharDataProc: LoadCharData,
r0: transform.a, r1: transform.b, r2: transform.c, r3: transform.d, r4: transform.e, r5: transform.f,
fontScalarData: 0, -- unused
fontAnyData: font]];
sCurrent: Scaled.Value ← ScaledFromReal[data.currentPosition.x];
fCurrent: Scaled.Value ← ScaledFromReal[data.currentPosition.y];
loadInfo: REF CharLoadInfo = NARROW[
ImagerFontCache.GetCharData[fontCache, fontCode, char-0C]];
sCP: INTEGER ← sCurrent.Round;
fCP: INTEGER ← fCurrent.Round;
ApplyMask[data, loadInfo.mask.Shift[sCP, fCP]];
sCurrent ← sCurrent.PLUS[loadInfo.sWidth];
fCurrent ← fCurrent.PLUS[loadInfo.fWidth];
data.currentPosition ← [x: sCurrent.Float, y: fCurrent.Float];
};
ShowCharacters: PROC [
context: Context,
characters: REF, -- may be a ROPE or a REF TEXT
font: FONT,
start: INT ← 0,
length: INTLAST[INT]
] ~ {
data: Data = NARROW[context.data];
transform: Transformation ← FontCompositeTransform[data, font];
fontCode: ImagerFontCache.FontCode ← ImagerFontCache.GetFontCode[[
CharDataProc: LoadCharData,
r0: transform.a, r1: transform.b, r2: transform.c, r3: transform.d, r4: transform.e, r5: transform.f,
fontScalarData: 0, -- unused
fontAnyData: font]];
sCurrent: Scaled.Value ← ScaledFromReal[data.currentPosition.x];
fCurrent: Scaled.Value ← ScaledFromReal[data.currentPosition.y];
DoChar: PROC[charCode: CARDINAL, charData: REF] = {
loadInfo: REF CharLoadInfo = NARROW[charData];
sCP: INTEGER ← sCurrent.Round;
fCP: INTEGER ← fCurrent.Round;
ApplyMask[data, loadInfo.mask.Shift[sCP, fCP]];
sCurrent ← sCurrent.PLUS[loadInfo.sWidth];
fCurrent ← fCurrent.PLUS[loadInfo.fWidth];
};
ImagerFontCache.GetStringData[DoChar, fontCache, fontCode, characters, start, length];
data.currentPosition ← [x: sCurrent.Float, y: fCurrent.Float];
};
CorrectMask: PROC[context: Context] = {
ERROR;
};
CorrectSpace: PROC[context: Context, v: Pair] = {
ERROR;
};
SetCorrectMeasure: PROC[context: Context, v: Pair] = {
ERROR;
};
SetCorrectTolerance: PROC[context: Context, v: Pair] = {
ERROR;
};
Space: PROC[context: Context, x: REAL] = {
ERROR;
};
IntegerSpace: PROC[context: Context, x: INTEGER] = {
ERROR;
};
Correct: PROC[context: Context, body: PROC] = {
ERROR;
};
TransferBuffer: PROC [context, source: Context] ~ {
data: Data ← NARROW[context.data];
WITH source.data SELECT FROM
sourceData: Data => {
ImagerMasks.MaskSampled[data.canvas, CompositeClipper[data], sourceData.canvas.InlineShift[data.sOriginView-sourceData.sOriginView, data.fOriginView-sourceData.fOriginView]];
};
ENDCASE => ERROR Imager.IncompatibleContexts;
};
SetColorInvert: PROC [context: Context] ~ {
data: Data ← NARROW[context.data];
data.currentColor ← $XOR;
};
firstBadDrawBitmap: BOOLEANTRUE;
DrawBitmap: ENTRY PROC [context: Context, base: LONG POINTER, raster: CARDINAL, area: IntRectangle] ~ {
ENABLE UNWIND => NULL;
data: Data ← NARROW[context.data];
IF data.transformation.type = rot90 THEN {
sMin, fMin, sSize, fSize: INTEGER;
[[sMin, fMin, sSize, fSize]] ← ImagerTransform.TransformIntRectangle[area, data.transformation];
scratchBitmapDesc.pointer ← base;
scratchBitmapDesc.rast ← raster;
scratchBitmapDesc.lines ← sSize;
ImagerMasks.MaskTile[data.canvas,
ImagerMasks.Box[[sMin, fMin, sSize, fSize]].And[CompositeClipper[data]],
[sMin, fMin, sSize, fSize, 0, scratchBitmapDesc]];
}
ELSE {
IF firstBadDrawBitmap THEN {firstBadDrawBitmap ← FALSE; ERROR}
Sorry, not yet.
};
};
SpecialOp: PROC [context: Context, op: ATOM, data: REF] RETURNS [implemented: BOOLEAN] ~ {
clipperData: Data ← NARROW[context.data];
implemented ← TRUE;
SELECT op FROM
$OtherScreen => {
swapped: BOOLEAN;
TRUSTED {swapped ← TerminalMultiplex.SelectTerminal[swap]};
TRUSTED {IF UserTerminal.GetState[] = disconnected THEN [] ← UserTerminal.SetState[on]};
TRUSTED {clipperData.canvas ← ImagerFrameBuffer.LFDisplay[]};
TRUSTED {swapped ← TerminalMultiplex.SelectTerminal[swap]};
implemented ← swapped
};
ENDCASE => implemented ← FALSE;
};
MaskFromSurfaceRectangle: PROC [data: Data, box: IntRectangle] RETURNS [Mask] ~ {
deviceBox: IntRectangle ← ImagerTransform.TransformIntRectangle[box, data.surfaceToDevice];
RETURN [ImagerMasks.InlineBox[[deviceBox.x, deviceBox.y, deviceBox.w, deviceBox.h]]];
};
SetView: PROC [context: Context, box: IntRectangle, halftoneOrigin: IntPair ← [0, 0]] ~ {
data: Data ← NARROW[context.data];
mask: Mask ← MaskFromSurfaceRectangle[data, box];
deviceOrigin: IntPair ← ImagerTransform.IntTransform[[box.x, box.y], data.surfaceToDevice];
sOriginView: INTEGER ← deviceOrigin.x;
fOriginView: INTEGER ← deviceOrigin.y;
sShift: INTEGER ← sOriginView-data.sOriginView;
fShift: INTEGER ← fOriginView-data.fOriginView;
newHalftoneOrigin: IntPair ← ImagerTransform.IntTransform[halftoneOrigin, data.surfaceToDevice];
IF data.doSaveCount # 0 THEN ERROR; -- Can't change a view with DoSave in progress.
IF data.viewClipper = mask AND sShift = 0 AND fShift = 0 AND newHalftoneOrigin = [data.sOriginBrick, data.fOriginBrick] THEN RETURN;
data.compositeClipperValid ← FALSE;
data.compositeClipper.refRep ← NIL;
IF data.clientClipperPresent THEN {
data.clientClipper ← data.clientClipper.Shift[sShift, fShift];
ccCount ← ccCount + 1;
};
data.viewClipper ← mask;
data.currentPosition.x ← data.currentPosition.x + sShift;
data.currentPosition.y ← data.currentPosition.y + fShift;
data.transformation.c ← data.transformation.c + sShift;
data.transformation.f ← data.transformation.f + fShift;
data.viewToDevice.c ← data.viewToDevice.c + sShift;
data.viewToDevice.f ← data.viewToDevice.f + fShift;
data.sOriginView ← sOriginView;
data.fOriginView ← fOriginView;
[data.sOriginBrick, data.fOriginBrick] ← newHalftoneOrigin;
};
ClipView: PROC [context: Context, box: IntRectangle, exclude: BOOLEAN] ~ {
data: Data ← NARROW[context.data];
mask: Mask ← MaskFromSurfaceRectangle[data, box];
data.compositeClipperValid ← FALSE;
data.compositeClipper.refRep ← NIL;
data.viewClipper ←
IF exclude THEN data.viewClipper.Difference[mask]
ELSE data.viewClipper.And[mask];
};
GetSurfaceBounds: PROC [context: Context] RETURNS [IntRectangle] ~ {
data: Data ← NARROW[context.data];
deviceToSurface: Transformation ← ImagerTransform.Invert[data.surfaceToDevice];
RETURN [ImagerTransform.TransformIntRectangle[[data.canvas.sMin, data.canvas.fMin, data.canvas.sSize, data.canvas.fSize], deviceToSurface]]
};
GetViewBounds: PROC [context: Context] RETURNS [IntRectangle] ~ {
data: Data ← NARROW[context.data];
deviceToSurface: Transformation ← ImagerTransform.Invert[data.surfaceToDevice];
RETURN [ImagerTransform.TransformIntRectangle[[data.viewClipper.sMin, data.viewClipper.fMin, data.viewClipper.sSize, data.viewClipper.fSize], deviceToSurface]]
};
MoveSurfaceRectangle: PROC [context: Context, source: IntRectangle, dest: IntPair] RETURNS [BOOLEAN] ~ {
data: Data ← NARROW[context.data];
bitmap: REF ImagerPixelMaps.PixelMapRep ← data.canvas.refRep;
sSizeCanvas, fSizeCanvas: NAT;
sTranslate, fTranslate: INTEGER;
sMinSource, fMinSource, sMinDest, fMinDest: INTEGER;
sSize, fSize: INTEGER;
sSizeCanvas ← MIN[data.canvas.sSize, bitmap.lines];
fSizeCanvas ← MIN[data.canvas.fSize, bitmap.rast*Environment.bitsPerWord];
[[sTranslate, fTranslate]] ← ImagerTransform.TransformIntVec[[dest.x-source.x, dest.y-source.y], data.surfaceToDevice];
[[sMinSource, fMinSource, sSize, fSize]] ← ImagerTransform.TransformIntRectangle[source, data.surfaceToDevice];
sMinSource ← sMinSource - data.canvas.sMin;
fMinSource ← fMinSource - data.canvas.fMin;
sMinDest ← sMinSource + sTranslate;
fMinDest ← fMinSource + fTranslate;
IF sMinDest < 0 THEN {
d: INTEGER ← - sMinDest;
sSize ← sSize - d;
sMinSource ← sMinSource + d;
sMinDest ← sMinDest + d;
};
IF sMinSource < 0 THEN {
d: INTEGER ← - sMinSource;
sSize ← sSize - d;
sMinSource ← sMinSource + d;
sMinDest ← sMinDest + d;
};
IF fMinDest < 0 THEN {
d: INTEGER ← - fMinDest;
fSize ← fSize - d;
fMinSource ← fMinSource + d;
fMinDest ← fMinDest + d;
};
IF fMinSource < 0 THEN {
d: INTEGER ← - fMinSource;
fSize ← fSize - d;
fMinSource ← fMinSource + d;
fMinDest ← fMinDest + d;
};
IF sMinDest + sSize > sSizeCanvas THEN {
sSize ← sSizeCanvas - sMinDest
};
IF sMinSource + sSize > sSizeCanvas THEN {
sSize ← sSizeCanvas - sMinSource
};
IF fMinDest + fSize > fSizeCanvas THEN {
fSize ← fSizeCanvas - fMinDest
};
IF fMinSource + fSize > data.canvas.fMin + fSizeCanvas THEN {
fSize ← fSizeCanvas - fMinSource
};
IF sSize > 0 AND fSize > 0 THEN TRUSTED {
Blt[bitmap.pointer, bitmap.rast, sMinSource, fMinSource, sMinDest, fMinDest, sSize, fSize]
};
RETURN [TRUE];
};
Blt: UNSAFE PROC [dbase: LONG POINTER, drast, sMinSource, fMinSource, sMinDest, fMinDest, sSize, fSize: NAT] ~ UNCHECKED INLINE {
bpl: INTEGER ← drast * Environment.bitsPerWord;
bbspace: BitBlt.BBTableSpace;
bb: BitBlt.BitBltTablePtr ← BitBlt.AlignedBBTable[@bbspace];
bb^ ← [dst: [word: NIL, bit: 0], dstBpl: 0,
src: [word: NIL, bit: 0], srcDesc: [srcBpl[0]], width: 0, height: 0,
flags: [direction: forward, disjoint: TRUE, disjointItems: TRUE, gray: FALSE, srcFunc: null, dstFunc: null]];
IF (fMinSource+fSize)>fMinDest AND (fMinDest+fSize)>fMinSource AND (sMinSource+sSize)>sMinDest AND (sMinDest+sSize)>sMinSource THEN {
bb.flags.disjoint ← FALSE; -- the rectangles overlap
IF sMinDest=sMinSource THEN bb.flags.disjointItems ← FALSE; -- so do the items
IF sMinDest>sMinSource OR (sMinDest=sMinSource AND fMinDest>fMinSource) THEN { -- reverse direction
bb.flags.direction ← backward; bpl ← -bpl;
sMinSource ← sMinSource + (sSize-1); sMinDest ← sMinDest + (sSize-1);
};
};
bb.dst.word ← dbase + Inline.LongMult[sMinDest, drast] + fMinDest/16; bb.dst.bit ← fMinDest MOD 16;
bb.src.word ← dbase + Inline.LongMult[sMinSource, drast] + fMinSource/16; bb.src.bit ← fMinSource MOD 16;
bb.dstBpl ← bb.srcDesc.srcBpl ← bpl;
bb.width ← fSize; bb.height ← sSize;
BitBlt.BITBLT[bb];
};
LFDisplayClass: ImagerPrivate.Class ← NEW [ImagerPrivate.ClassRep ← [
deviceType: $LFDisplay,
Init: Init,
IGet: IGet,
ISet: ISet,
IGetReal: IGetReal,
ISetReal: ISetReal,
IGetInt: IGetInt,
ISetInt: ISetInt,
DoSave: DoSave,
DoSaveAll: DoSaveAll,
ConcatT: ConcatT,
TranslateT: TranslateT,
RotateT: RotateT,
ScaleT: ScaleT,
Scale2T: Scale2T,
Move: Move,
Trans: Trans,
SetXY: SetXY,
IntegerSetXY: IntegerSetXY,
SetXYRel: SetXYRel,
IntegerSetXYRel: IntegerSetXYRel,
GetCP: GetCP,
GetCPRounded: GetCPRounded,
MaskFill: MaskFill,
MaskStroke: MaskStroke,
MaskStrokeClosed: MaskStrokeClosed,
MaskVector: MaskVector,
IntegerMaskVector: IntegerMaskVector,
MaskRectangle: MaskRectangle,
IntegerMaskRectangle: IntegerMaskRectangle,
StartUnderline: StartUnderline,
MaskUnderline: MaskUnderline,
IntegerMaskUnderline: IntegerMaskUnderline,
MaskPixel: MaskPixel,
ClipOutline: ClipOutline,
ClipRectangle: ClipRectangle,
IntegerClipRectangle: IntegerClipRectangle,
ShowChar: ShowChar,
ShowCharacters: ShowCharacters,
CorrectMask: CorrectMask,
CorrectSpace: CorrectSpace,
SetCorrectMeasure: SetCorrectMeasure,
SetCorrectTolerance: SetCorrectTolerance,
Space: Space,
IntegerSpace: IntegerSpace,
Correct: Correct,
Reset: Reset,
SetView: SetView,
ClipView: ClipView,
DrawBitmap: DrawBitmap,
MaskBits: MaskBits,
MoveSurfaceRectangle: MoveSurfaceRectangle,
IntegerExcludeRectangle: IntegerExcludeRectangle
]];
ImagerPrivate.RegisterDevice[LFDisplayClass];
END.