DIRECTORY Atom USING [GetPropFromList, PutPropOnList], Imager USING [ConcatT, Context, DoSaveAll], ImagerFont USING [BYTE, CorrectionType, Extents, Font, FontImplRep, FontRep, XChar, XCharProc, XStringProc], ImagerFontPrivate USING [FontAtom, FontImpl, FontImplRep, MakeFontAtom, WidthTable, WidthTableRep], ImagerTransformation USING [Concat, PostScale, Rectangle, Scale, Transform, Transformation, TransformRectangle, TransformVec], ImagerTypeface USING [Find, Typeface], PrincOps USING [zXOR], Rope USING [ActionType, Map, ROPE], Vector2 USING [Add, VEC]; ImagerFontImpl: CEDAR MONITOR IMPORTS Atom, Imager, ImagerFontPrivate, ImagerTransformation, ImagerTypeface, Rope, Vector2 EXPORTS ImagerFont, ImagerFontPrivate ~ BEGIN OPEN ImagerFont, ImagerFontPrivate; Typeface: TYPE ~ ImagerTypeface.Typeface; ROPE: TYPE ~ Rope.ROPE; MapRope: PUBLIC PROC[rope: ROPE, start: INT _ 0, len: INT _ INT.LAST, charAction: XCharProc] ~ { state: {run, escape, escape2, extended, extended2} _ run; set: BYTE _ 0; byteAction: PROC[c: CHAR] RETURNS[BOOL _ FALSE] ~ { 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: NAT _ NAT.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; }; FontImpl: TYPE ~ ImagerFontPrivate.FontImpl; FontImplRep: PUBLIC TYPE ~ ImagerFontPrivate.FontImplRep; -- export to ImagerFont VEC: TYPE ~ Vector2.VEC; Rectangle: TYPE ~ ImagerTransformation.Rectangle; Transformation: TYPE ~ ImagerTransformation.Transformation; identityTransformation: Transformation ~ ImagerTransformation.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 ~ REF NodeRep; NodeRep: TYPE ~ RECORD[fontAtom: FontAtom, 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[f: FontAtom] RETURNS[CARDINAL] ~ INLINE { RETURN[Munch[LOOPHOLE[f]]] }; GetFont: ENTRY PROC[typeface: Typeface, m: Transformation] RETURNS [Font] ~ { ENABLE UNWIND => NULL; f: FontAtom ~ ImagerFontPrivate.MakeFontAtom[typeface, m]; hash: CARDINAL ~ Hash[f]; hashIndex: HashIndex ~ hash MOD hashTableSize; head: NodeList ~ hashTable[hashIndex]; FOR list: NodeList _ head, list.rest UNTIL list=NIL DO node: Node ~ list.first; IF node.fontAtom=f THEN RETURN[node.font] ELSE misses _ misses+1; ENDLOOP; { -- not found, so make a new Font font: Font ~ CreateFont[typeface, m]; node: Node ~ NEW[NodeRep _ [fontAtom: f, font: font]]; hashTable[hashIndex] _ CONS[node, head]; entries _ entries+1; IF head#NIL THEN collisions _ collisions+1; RETURN[font]; }; }; CreateFont: PROC[typeface: Typeface, m: Transformation] RETURNS [Font] ~ { impl: FontImpl ~ NEW[FontImplRep _ [typeface: typeface]]; font: Font ~ NEW[FontRep _ [name: typeface.name, charToClient: m, impl: impl]]; BuildTables[font]; RETURN[font]; }; BuildTables: PROC[font: Font] ~ { m: Transformation ~ font.charToClient; impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; widthX, widthY: WidthTable _ NIL; impl.fontBoundingBox _ TransformExtents[m, typeface.class.FontBoundingBox[typeface]]; FOR code: BYTE IN BYTE DO width: VEC ~ m.Transform[typeface.class.Width[typeface, [set: 0, code: code]]]; IF width.x#0 THEN { IF widthX=NIL THEN widthX _ NEW[WidthTableRep _ ALL[0]]; widthX[code] _ width.x; }; IF width.y#0 THEN { IF widthY=NIL THEN widthY _ NEW[WidthTableRep _ ALL[0]]; widthY[code] _ width.y; }; ENDLOOP; impl.widthX _ widthX; impl.widthY _ widthY; }; RectangleFromExtents: PROC[e: Extents] RETURNS[Rectangle] ~ { RETURN[[x: -e.leftExtent, y: -e.descent, w: e.leftExtent+e.rightExtent, h: e.descent+e.ascent]]; }; ExtentsFromRectangle: PROC[r: Rectangle] RETURNS[Extents] ~ { 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 ~ ImagerTypeface.Find[name]; -- may raise Imager.Error RETURN[GetFont[typeface, identityTransformation]]; }; Modify: PUBLIC PROC[font: Font, m: Transformation] RETURNS[Font] ~ { impl: FontImpl ~ font.impl; RETURN[GetFont[impl.typeface, font.charToClient.Concat[m]]]; }; Scale: PUBLIC PROC[font: Font, s: REAL] RETURNS[Font] ~ { impl: FontImpl ~ font.impl; RETURN[GetFont[impl.typeface, font.charToClient.PostScale[s]]]; }; Contains: PUBLIC PROC[font: Font, char: XChar] RETURNS[BOOL] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; IF char.set=0 THEN RETURN[typeface.info[char.code].exists] ELSE RETURN[typeface.class.Contains[typeface, char]]; }; NextChar: PUBLIC PROC[font: Font, char: XChar] RETURNS[next: XChar] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; RETURN[typeface.class.NextChar[typeface, char]]; }; Width: PUBLIC PROC[font: Font, char: XChar] RETURNS[VEC] ~ { impl: FontImpl ~ font.impl; IF char.set=0 THEN { widthX: WidthTable ~ impl.widthX; widthY: WidthTable ~ impl.widthY; RETURN[[ x: IF widthX=NIL THEN 0 ELSE widthX[char.code], y: IF widthY=NIL THEN 0 ELSE widthY[char.code] ]]; } ELSE { typeface: Typeface ~ impl.typeface; width: VEC ~ typeface.class.Width[typeface, char]; RETURN[font.charToClient.TransformVec[width]]; }; }; Amplified: PUBLIC PROC[font: Font, char: XChar] RETURNS[BOOL] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; IF char.set=0 THEN RETURN[typeface.info[char.code].amplified] ELSE RETURN[typeface.class.Amplified[typeface, char]]; }; Correction: PUBLIC PROC[font: Font, char: XChar] RETURNS[CorrectionType] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; IF char.set=0 THEN RETURN[typeface.info[char.code].correction] ELSE RETURN[typeface.class.Correction[typeface, char]]; }; BoundingBox: PUBLIC PROC[font: Font, char: XChar] RETURNS[Extents] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; charExtents: Extents ~ typeface.class.BoundingBox[typeface, char]; RETURN[TransformExtents[font.charToClient, charExtents]]; }; FontBoundingBox: PUBLIC PROC[font: Font] RETURNS[Extents] ~ { impl: FontImpl ~ font.impl; RETURN[impl.fontBoundingBox]; }; Kern: PUBLIC PROC[font: Font, char, successor: XChar] RETURNS[VEC] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; RETURN[typeface.class.Kern[typeface, char, successor]]; }; NextKern: PUBLIC PROC[font: Font, char, successor: XChar] RETURNS[XChar] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; RETURN[typeface.class.NextKern[typeface, char, successor]]; }; Ligature: PUBLIC PROC[font: Font, char, successor: XChar] RETURNS[XChar] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; RETURN[typeface.class.Ligature[typeface, char, successor]]; }; NextLigature: PUBLIC PROC[font: Font, char, successor: XChar] RETURNS[XChar] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; RETURN[typeface.class.NextLigature[typeface, char, successor]]; }; MaskChar: PUBLIC PROC[font: Font, char: XChar, context: Imager.Context] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; action: PROC ~ { Imager.ConcatT[context, font.charToClient]; typeface.class.Mask[typeface, char, context]; }; Imager.DoSaveAll[context, action]; }; PutProp: PUBLIC PROC[font: Font, key: REF, val: REF] ~ { font.propList _ Atom.PutPropOnList[propList: font.propList, prop: key, val: val]; }; GetProp: PUBLIC PROC[font: Font, key: REF] RETURNS[value: REF] ~ { RETURN[Atom.GetPropFromList[propList: font.propList, prop: key]]; }; StringWidth: PUBLIC PROC [font: Font, string: XStringProc] RETURNS [VEC] ~ { impl: FontImpl ~ font.impl; widthX: WidthTable ~ impl.widthX; widthY: WidthTable ~ impl.widthY; sum: VEC _ [0, 0]; charAction: XCharProc ~ { IF char.set=0 THEN { IF widthX#NIL THEN sum.x _ sum.x+widthX[char.code]; IF widthY#NIL THEN sum.y _ sum.y+widthY[char.code]; } ELSE { typeface: Typeface ~ impl.typeface; width: VEC ~ font.charToClient.TransformVec[typeface.class.Width[typeface, char]]; sum.x _ sum.x+width.x; sum.y _ sum.y+width.y; }; }; string[charAction]; RETURN[sum]; }; RopeWidth: PUBLIC PROC [font: Font, rope: ROPE, start: INT _ 0, len: INT _ INT.LAST] RETURNS [VEC] ~ { string: XStringProc ~ { MapRope[rope, start, len, charAction] }; RETURN[StringWidth[font, string]]; }; TextWidth: PUBLIC PROC [font: Font, text: REF READONLY TEXT, start: NAT _ 0, len: NAT _ NAT.LAST] RETURNS [VEC] ~ { string: XStringProc ~ { MapText[text, start, len, charAction] }; RETURN[StringWidth[font, string]]; }; StringBoundingBox: PUBLIC PROC [font: Font, string: XStringProc] RETURNS [Extents] ~ { impl: FontImpl ~ font.impl; typeface: Typeface ~ impl.typeface; sxmin, symin, sxmax, symax: REAL _ 0; position: VEC _ [0, 0]; count: INT _ 0; charAction: XCharProc ~ { charExtents: Extents ~ typeface.class.BoundingBox[typeface, char]; charWidth: VEC ~ typeface.class.Width[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 cxminsxmax THEN sxmax _ cxmax; IF cyminsymax THEN symax _ cymax; }; position _ Vector2.Add[position, charWidth]; 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: INT _ INT.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: NAT _ NAT.LAST] RETURNS [Extents] ~ { string: XStringProc ~ { MapText[text, start, len, charAction] }; RETURN[StringBoundingBox[font, string]]; }; END. ˆImagerFontImpl.mesa Copyright c 1984, 1985 by Xerox Corporation. All rights reserved. Doug Wyatt, May 27, 1985 1:49:59 pm PDT Κ κ˜codešœ™Kšœ Οmœ7™BK™'—K™šΟk ˜ Kšœžœ"˜,Kšœžœ˜+Kšœ žœžœV˜lKšœžœL˜cKšœžœd˜~Kšœžœ˜&Kšœ žœ˜Kšœžœžœ˜#Kšœžœžœ˜—K˜KšΠblœžœž˜KšžœU˜\Kšžœ˜%Kšœžœžœ˜+K˜Kšœ žœ˜)Kšžœžœžœ˜K˜šΟnœžœžœžœ žœ žœžœžœ˜aJšœ9˜9Kšœžœ˜š œ žœžœžœžœžœ˜3Kšœžœžœ˜šžœž˜Kšœžœžœžœ%˜MKšœ žœžœžœ˜FKš œ žœžœžœžœ˜3Kšœ žœžœžœ ˜MKšœC˜CKšžœ˜—Kšœ˜—KšœF˜FK˜K˜—š œžœžœžœžœžœ žœ žœžœžœ˜nKšœžœΟc˜-Jšœ9˜9Kšœžœ˜š žœžœžœžœ ž˜"Kšœžœžœ˜šžœž˜Kšœžœžœžœ%˜MKšœ žœžœžœ˜FKš œ žœžœžœžœ˜3Kšœ žœžœžœ ˜MKšœC˜CKšžœ˜—Kšžœ˜—K˜K˜—K˜Kšœ žœ˜,Kšœ žœžœ"‘˜QK˜Kšžœžœ žœ˜Kšœ žœ"˜1Kšœžœ'˜;KšœG˜GK˜Kšœžœ˜Kšœ žœ˜%Kšœ žœžœ˜#Kšœžœžœ žœ ˜1Kšœ žœžœžœ˜Kšœžœžœ ˜Kšœ žœžœ!˜7K˜Kšœžœžœžœ˜4Kšœ žœ˜Kšœ žœ˜Kšœžœ˜K˜š  œžœžœžœžœžœ˜,Kšœžœžœžœ˜)K˜—š œžœžœžœžœžœžœ˜RK˜—š œžœžœ(žœ ˜MKšžœžœžœ˜Kšœ:˜:Kšœžœ ˜Kšœžœ˜.Kšœ&˜&šžœ"žœžœž˜6K˜Kšžœžœžœ žœ˜AKšžœ˜—šœ‘ ˜"Kšœ%˜%Kšœ žœ&˜6Kšœžœ ˜(Kšœ˜Kšžœžœžœ˜+Kšžœ˜ K˜—K˜K˜—š  œžœ(žœ ˜JKšœžœ%˜9Kšœ žœ?˜OKšœ˜Kšžœ˜ K˜K˜—š  œžœ˜!Kšœ&˜&K˜Kšœ#˜#Kšœžœ˜!KšœU˜Uš žœžœžœžœž˜KšœžœE˜Ošžœ žœ˜Kš žœžœžœ žœžœ˜8K˜K˜—šžœ žœ˜Kš žœžœžœ žœžœ˜8Kšœ˜K˜—Kšžœ˜—Kšœ˜K˜K˜K˜—š œžœ žœ˜=KšžœZ˜`K˜K˜—š œžœžœ ˜=KšžœK˜QK˜K˜—š œžœ žœ ˜JKšžœE˜KK˜K˜—š  œžœžœžœžœ ˜/Kšœ0‘˜IKšžœ,˜2K˜K˜—š œžœžœ žœ ˜DK˜Kšžœ6˜Kšžœžœ,˜7K˜K˜—š  œžœžœžœ ˜FK˜K˜#KšœB˜BKšžœ3˜9K˜K˜—š œžœžœ žœ ˜=K˜Kšžœ˜K˜K˜—š  œžœžœ%žœžœ˜FK˜K˜#Kšžœ1˜7K˜K˜—š œžœžœ%žœ ˜LK˜K˜#Kšžœ5˜;K˜K˜—š œžœžœ%žœ ˜LK˜K˜#Kšžœ5˜;K˜K˜—š  œžœžœ%žœ ˜PK˜K˜#Kšžœ9˜?K˜K˜—š œžœžœ6˜KK˜K˜#šœžœ˜Kšœ+˜+Kšœ-˜-K˜—K˜"K˜K˜—K˜š  œžœžœžœžœ˜8KšœQ˜QK˜K˜—š  œžœžœžœžœžœ˜BKšžœ;˜AK˜K˜—K˜š   œžœžœ#žœžœ˜LK˜K˜!Kšœ!˜!Kšœžœ ˜˜šžœ žœ˜Kšžœžœžœ!˜3Kšžœžœžœ!˜3K˜—šžœ˜K˜#KšœžœH˜RK˜-K˜—K˜—Kšœ˜Kšžœ˜ K˜K™—š  œžœžœžœ žœ žœžœžœžœžœ˜gKšœ@˜@Kšžœ˜"K˜K˜—š  œžœžœžœžœžœ žœ žœžœžœžœžœ˜tKšœ@˜@Kšžœ˜"K˜K˜—K˜š œžœžœ#žœ˜VK˜K˜#Jšœžœ˜%Kšœ žœ ˜Kšœžœ˜˜KšœB˜BKšœ žœ(˜6Kšœžœ%˜0Kšœžœ&˜1Kšœžœ"˜-Kšœžœ!˜,šžœ žœ˜K˜K˜K˜K˜K˜—šžœ˜Kšžœ žœ˜"Kšžœ žœ˜"Kšžœ žœ˜"Kšžœ žœ˜"K˜—Kšœ,˜,K˜K˜—Kšœ˜Kšžœq˜wK˜K™—š œžœžœžœ žœ žœžœžœžœ˜qKšœ@˜@Kšžœ"˜(K˜K˜—š œžœžœžœžœžœ žœ žœžœžœžœ˜~Kšœ@˜@Kšžœ"˜(K˜K˜—K˜Kšžœ˜—…—+β9T