ImagerFontImpl.mesa
Copyright Ó 1984, 1985 by Xerox Corporation. All rights reserved.
Doug Wyatt, May 27, 1985 1:49:59 pm PDT
Michael Plass, November 21, 1986 12:34:05 pm PST
DIRECTORY
Checksum USING [ComputeChecksum],
II USING [ConcatT, Context, DoSaveAll, Rectangle],
IIFont USING [BYTE, CorrectionType, Extents, Font, FontRep, XChar, XCharProc, XStringProc],
IITransformation USING [Concat, Copy, Equal, PostScale, Scale, Transformation, TransformationRep, TransformRectangle, TransformVec],
IITypeface USING [FindTypeface, TypefaceRep],
PrincOps USING [zXOR],
Rope USING [ActionType, Map, ROPE],
Vector2 USING [Add, VEC];
IIFontImpl: CEDAR MONITOR
IMPORTS Checksum, II, IITransformation, IITypeface, Rope, Vector2
EXPORTS IIFont, IITypeface
~ BEGIN
BYTE: TYPE ~ IIFont.BYTE;
CorrectionType: TYPE ~ IIFont.CorrectionType;
Extents: TYPE ~ IIFont.Extents;
Font: TYPE ~ IIFont.Font;
FontRep: TYPE ~ IIFont.FontRep;
XChar: TYPE ~ IIFont.XChar;
XCharProc: TYPE ~ IIFont.XCharProc;
XStringProc: TYPE ~ IIFont.XStringProc;
Typeface: TYPE ~ REF TypefaceRep;
TypefaceRep: PUBLIC TYPE ~ IITypeface.TypefaceRep; -- export to IITypeface
Rectangle: TYPE ~ II.Rectangle;
ROPE: TYPE ~ Rope.ROPE;
MapRope: PUBLIC PROC [rope: ROPE,
start: INT ← 0, len: INTINT.LAST, charAction: XCharProc] ~ {
state: {run, escape, escape2, extended, extended2} ← run;
set: BYTE ← 0;
byteAction: PROC [c: CHAR] RETURNS [BOOLFALSE] ~ {
b: BYTE ~ ORD[c];
SELECT state FROM
run => IF b=255 THEN state ← escape ELSE { charAction[[set: set, code: b]] };
escape => IF b=255 THEN state ← escape2 ELSE { set ← b; state ← run };
escape2 => IF b=0 THEN state ← extended ELSE ERROR;
extended => IF b=255 THEN state ← escape ELSE { set ← b; state ← extended2 };
extended2 => { charAction[[set: set, code: b]]; state ← extended };
ENDCASE;
};
[] ← Rope.Map[base: rope, start: start, len: len, action: byteAction];
};
MapText: PUBLIC PROC [text: REF READONLY TEXT,
start: NAT ← 0, len: NATNAT.LAST, charAction: XCharProc] ~ {
rem: NAT ~ text.length-start; -- bounds check
state: {run, escape, escape2, extended, extended2} ← run;
set: BYTE ← 0;
FOR i: NAT IN[0..MIN[len, rem]) DO
b: BYTE ~ ORD[text[start+i]];
SELECT state FROM
run => IF b=255 THEN state ← escape ELSE { charAction[[set: set, code: b]] };
escape => IF b=255 THEN state ← escape2 ELSE { set ← b; state ← run };
escape2 => IF b=0 THEN state ← extended ELSE ERROR;
extended => IF b=255 THEN state ← escape ELSE { set ← b; state ← extended2 };
extended2 => { charAction[[set: set, code: b]]; state ← extended };
ENDCASE;
ENDLOOP;
};
VEC: TYPE ~ Vector2.VEC;
Transformation: TYPE ~ IITransformation.Transformation;
TransformationRep: TYPE ~ IITransformation.TransformationRep;
identityTransformation: Transformation ~ IITransformation.Scale[1];
hashTableSize: NAT ~ 53;
HashIndex: TYPE ~ [0..hashTableSize);
HashTable: TYPE ~ REF HashTableRep;
HashTableRep: TYPE ~ ARRAY HashIndex OF NodeList;
NodeList: TYPE ~ LIST OF Node;
Node: TYPE ~ RECORD [hash: CARDINAL, font: Font];
hashTable: HashTable ~ NEW[HashTableRep ← ALL[NIL]];
entries: INT ← 0;
collisions: INT ← 0;
misses: INT ← 0;
Munch: PROC [LONG CARDINAL] RETURNS [CARDINAL]
~ TRUSTED MACHINE CODE { PrincOps.zXOR };
Hash: PROC [typeface: Typeface, m: Transformation] RETURNS [CARDINAL] ~ TRUSTED INLINE {
RETURN[Checksum.ComputeChecksum[cs: Munch[LOOPHOLE[typeface]],
nWords: SIZE[TransformationRep], p: LOOPHOLE[m]]];
};
MakeFont: PUBLIC ENTRY PROC [typeface: Typeface, m: Transformation] RETURNS [Font] ~ {
N.B. Exported to IITypeface
ENABLE UNWIND => NULL;
hash: CARDINAL ~ Hash[typeface, m];
hashIndex: HashIndex ~ hash MOD hashTableSize;
head: NodeList ~ hashTable[hashIndex];
FOR each: NodeList ← head, each.rest UNTIL each=NIL DO
node: Node ~ each.first;
IF node.hash = hash AND node.font.typeface = typeface AND IITransformation.Equal[node.font.charToClient, m] THEN RETURN[node.font] ELSE misses ← misses+1;
ENDLOOP;
{ -- not found, so make a new Font
font: Font ~ NEW[FontRep ← [charToClient: IITransformation.Copy[m], typeface: typeface]];
hashTable[hashIndex] ← CONS[[hash: hash, font: font], head];
entries ← entries+1;
IF head#NIL THEN collisions ← collisions+1;
RETURN[font];
};
};
RectangleFromExtents: PROC [e: Extents] RETURNS [Rectangle] ~ INLINE {
RETURN[[x: -e.leftExtent, y: -e.descent, w: e.leftExtent+e.rightExtent, h: e.descent+e.ascent]];
};
ExtentsFromRectangle: PROC [r: Rectangle] RETURNS [Extents] ~ INLINE {
RETURN[[leftExtent: -r.x, rightExtent: r.x+r.w, descent: -r.y, ascent: r.y+r.h]];
};
TransformExtents: PROC [m: Transformation, e: Extents] RETURNS [Extents] ~ {
RETURN[ExtentsFromRectangle[m.TransformRectangle[RectangleFromExtents[e]]]]
};
Find: PUBLIC PROC [name: ROPE] RETURNS [Font] ~ {
typeface: Typeface ~ IITypeface.FindTypeface[name]; -- may raise II.Error
RETURN[MakeFont[typeface, identityTransformation]];
};
Modify: PUBLIC PROC [font: Font, m: Transformation] RETURNS [Font] ~ {
RETURN[MakeFont[font.typeface, font.charToClient.Concat[m]]];
};
Scale: PUBLIC PROC [font: Font, s: REAL] RETURNS [Font] ~ {
RETURN[MakeFont[font.typeface, font.charToClient.PostScale[s]]];
};
FindScaled: PUBLIC PROC [name: ROPE, s: REAL] RETURNS [Font] ~ {
RETURN[Scale[Find[name], s]];
};
Contains: PUBLIC PROC [font: Font, char: XChar] RETURNS [BOOL] ~ {
typeface: Typeface ~ font.typeface;
IF char.set=0 AND typeface.info#NIL THEN RETURN[typeface.info[char.code].exists]
ELSE RETURN[typeface.class.Contains[typeface, char]];
};
NextChar: PUBLIC PROC [font: Font, char: XChar] RETURNS [next: XChar] ~ {
typeface: Typeface ~ font.typeface;
RETURN[typeface.class.NextChar[typeface, char]];
};
Escapement: PUBLIC PROC [font: Font, char: XChar] RETURNS [VEC] ~ {
typeface: Typeface ~ font.typeface;
escapement: VEC ~ typeface.class.Escapement[typeface, char];
RETURN[font.charToClient.TransformVec[escapement]];
};
Amplified: PUBLIC PROC [font: Font, char: XChar] RETURNS [BOOL] ~ {
typeface: Typeface ~ font.typeface;
IF char.set=0 AND typeface.info#NIL THEN RETURN[typeface.info[char.code].amplified]
ELSE RETURN[typeface.class.Amplified[typeface, char]];
};
Correction: PUBLIC PROC [font: Font, char: XChar] RETURNS [CorrectionType] ~ {
typeface: Typeface ~ font.typeface;
IF char.set=0 AND typeface.info#NIL THEN RETURN[typeface.info[char.code].correction]
ELSE RETURN[typeface.class.Correction[typeface, char]];
};
BoundingBox: PUBLIC PROC [font: Font, char: XChar] RETURNS [Extents] ~ {
typeface: Typeface ~ font.typeface;
charExtents: Extents ~ typeface.class.BoundingBox[typeface, char];
RETURN[TransformExtents[font.charToClient, charExtents]];
};
FontBoundingBox: PUBLIC PROC [font: Font] RETURNS [Extents] ~ {
typeface: Typeface ~ font.typeface;
fontExtents: Extents ~ typeface.class.FontBoundingBox[typeface];
RETURN[TransformExtents[font.charToClient, fontExtents]];
};
Name: PUBLIC PROC [font: Font] RETURNS [ROPE] ~ {
typeface: Typeface ~ font.typeface;
RETURN [typeface.name];
};
Kern: PUBLIC PROC [font: Font, char, successor: XChar] RETURNS [VEC] ~ {
typeface: Typeface ~ font.typeface;
RETURN[typeface.class.Kern[typeface, char, successor]];
};
NextKern: PUBLIC PROC [font: Font, char, successor: XChar] RETURNS [XChar] ~ {
typeface: Typeface ~ font.typeface;
RETURN[typeface.class.NextKern[typeface, char, successor]];
};
Ligature: PUBLIC PROC [font: Font, char, successor: XChar] RETURNS [XChar] ~ {
typeface: Typeface ~ font.typeface;
RETURN[typeface.class.Ligature[typeface, char, successor]];
};
NextLigature: PUBLIC PROC [font: Font, char, successor: XChar] RETURNS [XChar] ~ {
typeface: Typeface ~ font.typeface;
RETURN[typeface.class.NextLigature[typeface, char, successor]];
};
MaskChar: PUBLIC PROC [font: Font, char: XChar, context: II.Context] ~ {
N.B. Exported to IITypeface
typeface: Typeface ~ font.typeface;
action: PROC ~ {
II.ConcatT[context, font.charToClient];
typeface.class.Mask[typeface, char, context];
};
II.DoSaveAll[context, action];
};
StringEscapement: PUBLIC PROC [font: Font, string: XStringProc] RETURNS [VEC] ~ {
sum: VEC ← [0, 0]; -- accumulated in character coordinates
typeface: Typeface ~ font.typeface;
charAction: XCharProc ~ {
escapement: VEC ~ typeface.class.Escapement[typeface, char];
sum ← Vector2.Add[sum, escapement];
};
string[charAction];
RETURN[font.charToClient.TransformVec[sum]];
};
RopeEscapement: PUBLIC PROC [font: Font, rope: ROPE,
start: INT ← 0, len: INTINT.LAST] RETURNS [VEC] ~ {
string: XStringProc ~ { MapRope[rope, start, len, charAction] };
RETURN[StringEscapement[font, string]];
};
TextEscapement: PUBLIC PROC [font: Font, text: REF READONLY TEXT,
start: NAT ← 0, len: NATNAT.LAST] RETURNS [VEC] ~ {
string: XStringProc ~ { MapText[text, start, len, charAction] };
RETURN[StringEscapement[font, string]];
};
StringBoundingBox: PUBLIC PROC [font: Font, string: XStringProc] RETURNS [Extents] ~ {
typeface: Typeface ~ font.typeface;
sxmin, symin, sxmax, symax: REAL ← 0;
position: VEC ← [0, 0];
count: INT ← 0;
charAction: XCharProc ~ {
charExtents: Extents ~ typeface.class.BoundingBox[typeface, char];
charEscapement: VEC ~ typeface.class.Escapement[typeface, char];
cxmin: REAL ~ position.x-charExtents.leftExtent;
cxmax: REAL ~ position.x+charExtents.rightExtent;
cymin: REAL ~ position.y-charExtents.descent;
cymax: REAL ~ position.y+charExtents.ascent;
IF count=0
THEN { sxmin ← cxmin; sxmax ← cxmax; symin ← cymin; symax ← cymax }
ELSE {
IF cxmin < sxmin THEN sxmin ← cxmin;
IF cxmax > sxmax THEN sxmax ← cxmax;
IF cymin < symin THEN symin ← cymin;
IF cymax > symax THEN symax ← cymax;
};
position ← Vector2.Add[position, charEscapement];
count ← count+1;
};
string[charAction];
RETURN[TransformExtents[font.charToClient, [leftExtent: -sxmin, rightExtent: sxmax, descent: -symin, ascent: symax]]];
};
RopeBoundingBox: PUBLIC PROC [font: Font, rope: ROPE,
start: INT ← 0, len: INTINT.LAST] RETURNS [Extents] ~ {
string: XStringProc ~ { MapRope[rope, start, len, charAction] };
RETURN[StringBoundingBox[font, string]];
};
TextBoundingBox: PUBLIC PROC [font: Font, text: REF READONLY TEXT,
start: NAT ← 0, len: NATNAT.LAST] RETURNS [Extents] ~ {
string: XStringProc ~ { MapText[text, start, len, charAction] };
RETURN[StringBoundingBox[font, string]];
};
END.