FitFontImpl.mesa
Maureen Stone April 4, 1985 1:31:40 pm PST
Copyright (C) 1984 by Xerox Corporation. All rights reserved
DIRECTORY
AMTypes,
SafeStorage USING [EquivalentTypes],
ViewerOps,
ViewerClasses,
Icons,
Menus,
MessageWindow USING [Clear, Append],
Convert USING [RopeFromInt],
ViewRec,
Rope USING [ROPE, Fetch],
Real USING [RoundLI],
Scaled USING [FromReal, zero],
ImagerBasic USING [PixelArray, PixelBuffer, PixelBufferRep],
ImagerBridge USING[SetViewFromGraphicsContext],
UFFileManager USING [KeyOf],
UFPressFontReader USING[Size, Range, Family, Face, Resolution, GetCharInfo, GetCharRaster, CharInfo],
Font USING [Key],
SampledColors USING [bitmap, DrawImage],
Imager,
ImagerTransform USING [InverseTransform, Transform],
FitState USING [Handle, StartSamples, AddSample, ResetData, NewContour, Create, SetClosed],
FitBasic,
FitIO,
Outline,
PiecewiseFit,
LSPiece USING [MetricsRec];
FitFontImpl: CEDAR PROGRAM
IMPORTS AMTypes, ViewerOps, ViewRec, FitState, Menus, SafeStorage, UFFileManager, UFPressFontReader, Imager, ImagerTransform, MessageWindow, Convert, Real, Outline, ImagerBridge, Rope, Scaled, SampledColors, FitIO
= {
ROPE: TYPE=Rope.ROPE;
Data: TYPE = REF Rec;
Rec: TYPE = RECORD [
abort: BOOLEANFALSE,
input: InternalFont, --the input font
outline: Outline.Handle, --handle for outlining a character
edge: RECORD[x0,y0,x1,y1: REAL], --the data for painting in Outline.NewEdge
fitIO: FitIO.Context, --properties for showing samples
viewHeader: ViewHeader, --data viewed by the ViewRec
viewRec: ViewRec.RecordViewer
];
ViewHeader: TYPE = REF ViewHeaderRec;
ViewHeaderRec: TYPE = RECORD [
FontName: ROPE,
SetChar: PROC [ViewerClasses.Viewer],
Character: ROPE,
ShowAC: BOOLEAN ← TRUE,
ShowSamples: BOOLEAN ← FALSE,
ShowCurve: BOOLEAN ← FALSE,
metrics: PiecewiseFit.Metrics
];
InternalFont: TYPE ~ REF InternalFontRep;
InternalFontRep: TYPE ~ RECORD [
family: Rope.ROPENIL,
face: [0..255] ← 0,
bitsPerEmQuad: REAL ← 0,
defaultChar: InternalCharRep,
charRep: ARRAY CHAR OF InternalCharRep
];
InternalCharRep: TYPE ~ RECORD [
fWidth, sWidth: REAL,
pixels: ImagerBasic.PixelArray,
fitState: FitState.Handle
];
CreateViewer: PROC[name: ROPE] = {
new: ViewerClasses.Viewer ← ViewerOps.CreateViewer[flavor: $Fit, info: [
name: (IF name=NIL THEN "No name" ELSE name),
scrollable: FALSE,
data: name --just until InitViewer is called, then becomes a Data
]];
};
ProduceMetrics: ViewRec.ComplexProducer = {
rv: ViewRec.RecordViewer;
referent: AMTypes.TV ← AMTypes.Referent[tv];
rv ← ViewRec.ViewTV[agg: referent, specs: context.bindings, parent: context.for, createOptions: context.createOptions, asElement: context.thisElement, sample: TRUE, viewerInit: [parent: context.main, scrollable: FALSE, iconic: FALSE]];
v ← rv.RVQuaViewer[];
sampleable ← FALSE;
};
RecognizeMetrics: ViewRec.Recognizer = {
IF IKnowYou ← SafeStorage.EquivalentTypes[t, CODE[PiecewiseFit.Metrics]] THEN {handler ← NEW [ViewRec.ComplexHandlerRep ← [producer: ProduceMetrics]]};
};
InitViewer: PROC [self: ViewerClasses.Viewer] = {
data: Data ← NEW[Rec];
name: ROPENARROW[self.data]; --only here is self.data a ROPE
data.input ← IF name#NIL THEN LoadAC[name] ELSE NIL;
data.viewHeader ← NEW[ViewHeaderRec ← [
FontName: NARROW[self.data],
SetChar: SetChar,
Character: "A",
metrics: NEW[LSPiece.MetricsRec]
]];
data.viewRec ← ViewRec.ViewRef[agg: data.viewHeader, specs: ViewRec.BindAllOfATypeFromRefs[rec: data.viewHeader, handle: NEW [ViewerClasses.Viewer ← self]], viewerInit: [name: name]];
data.outline ← NEW[Outline.Rec ← [
startX: 0, startY: 0, endX: 0, endY: 0,
tValue: 1,
get: Get,
newEdge: NewEdge,
client: self
]];
data.fitIO ← NEW[FitIO.ContextRec ← [
imager: Imager.Create[$LFDisplay],
magnify: 5,
position: [5, 5],
feedback: NEW[FitIO.FeedbackRec ← [
color: Imager.black,
sampleSize: 2,
jointSize: 4,
nodeLength: 4,
nodeLineWidth: 0,
lineWidth: 0--for DrawSamples and DrawContour
]],
logActions: FALSE,
log: NIL
]];
Imager.ConcatT[data.fitIO.imager,Imager.pointsToMeters];
self.data ← data;
SetChar[self]; --initialize the data structures for the default character
};
SetChar: PROC[viewer: ViewerClasses.Viewer] = {
data: Data ← NARROW[viewer.data];
sx, sy, ex, ey: REAL;
pa: ImagerBasic.PixelArray;
data.input.defaultChar ← data.input.charRep[Rope.Fetch[data.viewHeader.Character,0]];
pa ← data.input.defaultChar.pixels; --just renaming
build an upright bounding box
[[sx, sy]] ← ImagerTransform.Transform[[0,0],pa.m];
[[ex,ey]] ← ImagerTransform.Transform[[pa.xPixels,pa.yPixels],pa.m];
data.outline.xStart ← Real.RoundLI[MIN[sx,ex]];
data.outline.xPixels ← Real.RoundLI[MAX[sx,ex]]-data.outline.xStart;
data.outline.yStart ← Real.RoundLI[MIN[sy,ey]];
data.outline.yPixels ← Real.RoundLI[MAX[sy,ey]]-data.outline.yStart;
mess around with the positioning to get the whole character on the screen
sx ← data.fitIO.magnify*(5-data.outline.xStart);
sy ← data.fitIO.magnify*(5-data.outline.yStart);
FitIO.PositionData[data.fitIO, [sx,sy]];
data.viewHeader.ShowAC ← TRUE;
ViewerOps.PaintViewer[viewer, client, TRUE, $ShowAC];
};
CreateMenus: PROC RETURNS[Menus.Menu] = {
menus: Menus.Menu ← Menus.CreateMenu[];
Menus.AppendMenuEntry[
menu: menus,
entry: Menus.CreateEntry[
name: "ABORT!",
proc: Abort,
clientData: NIL,
guarded: FALSE,
documentation: "Abort the operation"
]
];
Menus.AppendMenuEntry[
menu: menus,
entry: Menus.CreateEntry[
name: "LoadFont",
proc: LoadFont,
clientData: NIL,
guarded: TRUE,
documentation: "Load the font named in FontName"
]
];
Menus.AppendMenuEntry[
menu: menus,
entry: Menus.CreateEntry[
name: "Fit",
proc: DoFit,
clientData: NIL,
documentation: "Fit the current character"
]
];
Menus.AppendMenuEntry[
menu: menus,
entry: Menus.CreateEntry[
name: "Outline",
proc: DoOutline,
clientData: NIL,
documentation: "Outline the current character"
]
];
RETURN[menus];
};
MenuProc: TYPE = PROC [parent: REF ANY, clientData: REF ANYNIL,
mouseButton: MouseButton ← red, shift, control: BOOLFALSE] ;
Abort: Menus.MenuProc = {
viewer: ViewerClasses.Viewer ← NARROW[parent];
data: Data ← NARROW[viewer.data];
data.abort ← TRUE;
};
LoadFont: Menus.MenuProc = {
viewer: ViewerClasses.Viewer ← NARROW[parent];
data: Data ← NARROW[viewer.data];
data.input ← LoadAC[data.viewHeader.FontName];
SetChar[viewer];
};
DoOutline: Menus.MenuProc = {
viewer: ViewerClasses.Viewer ← NARROW[parent];
data: Data ← NARROW[viewer.data];
nContours: INT;
fitState: FitState.Handle ← data.input.defaultChar.fitState; --rename
data.outline.client ← parent;
data.viewHeader.ShowAC ← FALSE;
ViewerOps.PaintViewer[viewer, client, TRUE, $Clear];
Imager.TranslateT[data.fitIO.imager, data.fitIO.position.x, data.fitIO.position.y];
Imager.ScaleT[data.fitIO.imager, data.fitIO.magnify];
Imager.SetColor[data.fitIO.imager, data.fitIO.feedback.color];
nContours ← Outline.OutlineBlackEdge[data.outline];
MessageWindow.Clear[];
IF nContours = -1 THEN MessageWindow.Append["Aborted outline"]
ELSE {
MessageWindow.Append[Convert.RopeFromInt[nContours, 10, FALSE]];
MessageWindow.Append[" contours in character"];
};
Imager.Reset[data.fitIO.imager];
Imager.ConcatT[data.fitIO.imager,Imager.pointsToMeters];
FitState.ResetData[fitState, contour, TRUE];
FOR cn: INT IN[0..nContours) DO
first: BOOLEANTRUE;
newPt: PROC[x,y: REAL] = {
IF first THEN {first ← FALSE; FitState.StartSamples[fitState, x,y]}
ELSE FitState.AddSample[fitState, x,y];
};
Outline.GetOutline[data.outline.data, newPt, cn];
IF cn#nContours-1 THEN FitState.NewContour[fitState];
ENDLOOP;
FitState.SetClosed[fitState,TRUE];
data.viewHeader.ShowSamples ← TRUE;
};
DoFit: Menus.MenuProc = {
viewer: ViewerClasses.Viewer ← NARROW[parent];
data: Data ← NARROW[viewer.data];
};
paintEdges: BOOLEANTRUE;
NewEdge: PROCEDURE [client: REF, x0,y0,x1,y1: REAL] RETURNS [abort: BOOLEANFALSE] = {
viewer: ViewerClasses.Viewer ← NARROW[client];
data: Data ← NARROW[viewer.data];
data.edge ← [x0,y0,x1,y1];
IF paintEdges THEN ViewerOps.PaintViewer[viewer,client, FALSE, $NewEdge];
RETURN[GetAbort[data]];
};
buffer: ImagerBasic.PixelBuffer ← NEW[ImagerBasic.PixelBufferRep[1]];
Get: PROC[client: REF, x,y: INT] RETURNS[INT] = {
viewer: ViewerClasses.Viewer ← NARROW[client];
data: Data ← NARROW[viewer.data];
s, f: REAL;
pixels: ImagerBasic.PixelArray ← data.input.defaultChar.pixels;
[[s, f]] ← ImagerTransform.InverseTransform[[x, y],pixels.m];
pixels.get[pixels, buffer,1, 0, Scaled.FromReal[s], Scaled.FromReal[f], Scaled.zero, Scaled.zero];
RETURN[buffer[0]];
};
Paint: PROC [self: Viewer, context: Graphics.Context, whatChanged: REF ANY, clear: BOOL]
Paint: ViewerClasses.PaintProc = {
data: Data ← NARROW[self.data];
showAC: PROC = {
Imager.TranslateT[data.fitIO.imager, data.fitIO.position.x, data.fitIO.position.y];
Imager.ScaleT[data.fitIO.imager, data.fitIO.magnify];
SampledColors.DrawImage[
data.fitIO.imager,data.input.defaultChar.pixels,SampledColors.bitmap];
};
showCurve: PROC = {
Imager.TranslateT[data.fitIO.imager, data.fitIO.position.x, data.fitIO.position.y];
FitIO.DrawContour[data.fitIO, data.input.defaultChar.fitState,TRUE];
FitIO.MarkJoints[data.fitIO, data.input.defaultChar.fitState,TRUE];
};
showSamples: PROC = {
FitIO.MarkSamples[data.fitIO, data.input.defaultChar.fitState,TRUE];
FitIO.MarkNodes[data.fitIO, data.input.defaultChar.fitState,TRUE];
};
SELECT whatChanged FROM
$NewEdge => {
Imager.MaskVector[data.fitIO.imager,[data.edge.x0,data.edge.y0],[data.edge.x1,data.edge.y1]];
};
$Clear => {}; --done by call
$ShowAC => Imager.DoSaveAll[data.fitIO.imager, showAC];
$ShowSamples => Imager.DoSaveAll[data.fitIO.imager, showSamples];
$ShowCurve => Imager.DoSaveAll[data.fitIO.imager, showCurve];
NIL => { --paint all
ImagerBridge.SetViewFromGraphicsContext[data.fitIO.imager,context];
IF data.viewHeader.ShowAC THEN Imager.DoSaveAll[data.fitIO.imager, showAC];
IF data.viewHeader.ShowSamples THEN Imager.DoSaveAll[data.fitIO.imager, showSamples];
IF data.viewHeader.ShowCurve THEN Imager.DoSaveAll[data.fitIO.imager, showCurve];
};
ENDCASE;
};
GetAbort: PROC[data: Data] RETURNS[BOOLEAN] = {
IF data.abort THEN {data.abort ← FALSE; RETURN[TRUE]}
ELSE RETURN[FALSE];
};
LoadAC: PROC [fileName: Rope.ROPE] RETURNS [internalFont: InternalFont] ~ TRUSTED {
fileKey: Font.Key ← UFFileManager.KeyOf[fileName];
sizeInMeters: REAL ← UFPressFontReader.Size[[fileKey, 0]];
bc, ec: CHAR;
[bc, ec] ← UFPressFontReader.Range[[fileKey, 0]];
internalFont ← NEW [InternalFontRep];
internalFont.family ← UFPressFontReader.Family[[fileKey, 0]];
internalFont.face ← UFPressFontReader.Face[[fileKey, 0]];
internalFont.bitsPerEmQuad ← sizeInMeters*UFPressFontReader.Resolution[[fileKey, 0]].xRes/0.0254;
FOR char: CHAR IN [bc..ec] DO
info: UFPressFontReader.CharInfo ← UFPressFontReader.GetCharInfo[[fileKey, 0], char];
pixelArray: ImagerBasic.PixelArray ← UFPressFontReader.GetCharRaster[[fileKey, 0], char];
internalFont.charRep[char] ← [
fWidth: info.widthX*internalFont.bitsPerEmQuad,
sWidth: -info.widthY*internalFont.bitsPerEmQuad,
pixels: pixelArray,
fitState: FitState.Create[]
];
ENDLOOP;
};
myClass: ViewerClasses.ViewerClass ← NEW[ViewerClasses.ViewerClassRec ← [
flavor: $Fit,
paint: Paint,
init: InitViewer,
icon: tool,
menu: CreateMenus[]
]];
ViewerOps.RegisterViewerClass[flavor: $Fit, class: myClass];
ViewRec.RegisterRecognizerByType[r: RecognizeMetrics, end: Front, type: CODE[PiecewiseFit.Metrics], reductions: EquivalenceClass];
}.