<<>> <> <> <> <> <<>> DIRECTORY Atom, Char, Convert, Imager, ImagerColor, ImagerFont, NodeStyle, NodeStyleFont, Real, RefText, Rope, SimpleFeedback; NodeStyle2Impl: CEDAR MONITOR IMPORTS Atom, Char, Convert, Imager, ImagerColor, ImagerFont, NodeStyle, Real, RefText, Rope, SimpleFeedback EXPORTS NodeStyle, NodeStyleFont ~ BEGIN OPEN NodeStyle; <<>> ROPE: TYPE ~ Rope.ROPE; Font: TYPE ~ ImagerFont.Font; <> PrefixKind: TYPE ~ RECORD [ pattern: ROPE, sizeInName: BOOL, preScaled: BOOL, -- Having pre-scaled fonts was probably a mistake, but we are sort of stuck, for now. faceEncoding: FaceEncoding ]; FaceEncoding: TYPE ~ {boldItalic, bir, bi}; prefixKinds: LIST OF PrefixKind ¬ LIST[ [pattern: "xerox/tiogafonts/", sizeInName: TRUE, preScaled: TRUE, faceEncoding: bi], [pattern: "xerox/pressfonts/", sizeInName: FALSE, preScaled: FALSE, faceEncoding: bir], [pattern: "xerox/altofonts/", sizeInName: TRUE, preScaled: TRUE, faceEncoding: bi], [pattern: "xerox/xc*/tioga-", sizeInName: TRUE, preScaled: FALSE, faceEncoding: boldItalic], [pattern: "xerox/xc*/", sizeInName: FALSE, preScaled: FALSE, faceEncoding: boldItalic] ]; boldItalicSuffix: ARRAY FontFace OF ROPE ~ [ Regular: "", Bold: "-bold", Italic: "-italic", BoldItalic: "-bold-italic" ]; birSuffix: ARRAY FontFace OF ROPE ~ [ Regular: "-MRR", Bold: "-BRR", Italic: "-MIR", BoldItalic: "-BIR" ]; biSuffix: ARRAY FontFace OF ROPE ~ [ Regular: "", Bold: "B", Italic: "I", BoldItalic: "BI" ]; faceIndex: ARRAY FontFace OF [0..4) ~ [ Regular: 0, Bold: 1, Italic: 2, BoldItalic: 3 ]; AppendFontName: PROC [text: REF TEXT, prefix: ATOM, family: ATOM, face: FontFace, size: REAL, alphabets: FontAlphabets] RETURNS [new: REF TEXT, sizeInName: BOOL ¬ FALSE, preScaled: BOOL ¬ FALSE] ~ { fam: ROPE ~ Atom.GetPName[family]; IF Rope.Find[fam, "/"] >= 0 THEN RETURN[RefText.AppendRope[text, fam]] ELSE { prePName: ROPE ~ IF prefix#NIL THEN Atom.GetPName[prefix] ELSE NIL; pre: ROPE ~ IF Rope.Size[prePName]>0 THEN prePName ELSE "xerox/tiogafonts/"; famSize: INT ~ Rope.Size[fam]; pos: ARRAY [0..4] OF INT ¬ ALL[famSize]; text ¬ RefText.AppendRope[text, pre]; FOR i: [0..4] IN [0..4] DO pos1: INT ~ IF i=0 THEN 0 ELSE pos[i-1]+1; s2: ROPE ~ SELECT i FROM 0 => "(", 4 => ")", ENDCASE => "|"; IF NOT (pos[i] ¬ Rope.Index[s1: fam, pos1: pos1, s2: s2]) { text ¬ RefText.AppendRope[text, boldItalicSuffix[face]]; IF sizeInName THEN { text ¬ RefText.AppendChar[text, '-]; text ¬ Convert.AppendInt[text, Real.Round[size]]; }; }; bir => { IF sizeInName THEN ERROR; text ¬ RefText.AppendRope[text, birSuffix[face]]; }; bi => { IF sizeInName THEN text ¬ Convert.AppendInt[text, Real.Round[size]]; text ¬ RefText.AppendRope[text, biSuffix[face]]; }; ENDCASE => ERROR; }; new ¬ text; }; }; FontNameFromStyleParams: PUBLIC PROC [prefix: ATOM, family: ATOM, face: FontFace, size: REAL, alphabets: FontAlphabets] RETURNS [name: ROPE, scale: REAL] ~ { scratch: REF TEXT ~ RefText.ObtainScratch[100]; text: REF TEXT ¬ scratch; sizeInName, preScaled: BOOL ¬ FALSE; [text, sizeInName, preScaled] ¬ AppendFontName[text, prefix, family, face, size, alphabets]; name ¬ Rope.FromRefText[text]; IF preScaled THEN scale ¬ 1.0 ELSE scale ¬ size; RefText.ReleaseScratch[scratch]; }; nTrys: NAT ~ 5; tryDelta: ARRAY [0..nTrys) OF REAL ¬ [0, -0.999, 0.999, -1.998, 1.998]; families: LIST OF LIST OF ATOM ¬ LIST[ LIST[$Tioga, $Laurel, $TimesRoman], LIST[$TimesRoman, $Classic], LIST[$Helvetica, $Modern, $TimesRoman], LIST[$Modern, $Helvetica], LIST[$Classic, $TimesRoman, $Modern], LIST[$Gacha, $Helvetica] ]; SubstituteFamilies: PROC [family: ATOM] RETURNS [LIST OF ATOM] ~ { fam: ROPE ~ Atom.GetPName[family]; FOR f: LIST OF LIST OF ATOM ¬ families, f.rest UNTIL f=NIL DO k: ATOM ¬ f.first.first; IF family = k OR Rope.Equal[fam, Atom.GetPName[k], FALSE] THEN RETURN [f.first]; ENDLOOP; RETURN [NIL]; }; FontReplacementProc: PROC [prefix: ATOM, family: ATOM, face: FontFace, size: REAL, alphabets: FontAlphabets] RETURNS [font: Font] ¬ NIL; <> <<>> horribleHackForTioga10: BOOL ¬ TRUE; defaultPrintFont: Font ¬ NIL; candidates: LIST OF ROPE ¬ LIST[ "xerox/xc1-2-2/modern", "xerox/pressfonts/helvetica-mrr" ]; <<>> GetDefaultFont: PROC RETURNS [Font] ~ { FOR each: LIST OF ROPE ¬ candidates, each.rest WHILE defaultPrintFont = NIL DO <
> defaultPrintFont ¬ ImagerFont.Find[each.first, substituteQuietly ! Imager.Error => CONTINUE]; ENDLOOP; RETURN [defaultPrintFont] }; GetFont: PUBLIC PROC [style: Style] RETURNS [Font] ~ { RETURN FontFromStyleParams[ prefix: NodeStyle.GetName[style, fontPrefix], family: NodeStyle.GetName[style, fontFamily], face: NodeStyle.GetFontFace[style], size: NodeStyle.GetReal[style, fontSize], alphabets: NodeStyle.GetFontAlphabets[style] ]; }; GetSpaceWidth: PUBLIC PROC [style: NodeStyle.Ref] RETURNS [REAL] ~ { font: Font ~ GetFont[style]; RETURN[ImagerFont.Escapement[font, Char.Widen[' ]].x]; }; FontFromStyleParams: PUBLIC PROC [prefix: ATOM, family: ATOM, face: FontFace, size: REAL, alphabets: FontAlphabets] RETURNS [font: Font ¬ NIL] ~ { didSubstitution: BOOL ¬ FALSE; font ¬ CheckStyleFontCache[prefix, family, face, size, alphabets]; IF font = NIL THEN { IF FontReplacementProc # NIL THEN { font ¬ FontReplacementProc[prefix, family, face, size, alphabets]; }; IF font = NIL THEN { scratch: REF TEXT ~ RefText.ObtainScratch[100]; text: REF TEXT ¬ scratch; sizeInName, preScaled: BOOL ¬ FALSE; trialFace: FontFace ¬ face; WHILE font = NIL DO <> families: LIST OF ATOM ¬ NIL; trialFamily: ATOM ¬ family; firstFamily: ATOM ¬ family; IF horribleHackForTioga10 AND (firstFamily=$tioga OR firstFamily=$Tioga) AND (size NOT IN [9.5..10.5]) THEN { trialFamily ¬ firstFamily ¬ $TimesRoman; }; WHILE font = NIL AND trialFamily # NIL DO <> FOR try: NAT IN [0..nTrys) WHILE font = NIL DO <> trialSize: REAL ¬ size + tryDelta[try]; text.length ¬ 0; [text, sizeInName, preScaled] ¬ AppendFontName[text, prefix, trialFamily, trialFace, trialSize, alphabets]; font ¬ ImagerFont.Find[Rope.FromRefText[text], noSubstitute ! Imager.Error => CONTINUE]; IF font = NIL THEN didSubstitution ¬ TRUE; IF NOT sizeInName THEN EXIT; ENDLOOP; IF font = NIL THEN { IF families = NIL THEN families ¬ SubstituteFamilies[firstFamily]; IF families # NIL THEN { families ¬ families.rest; }; trialFamily ¬ IF families=NIL THEN NIL ELSE families.first; }; ENDLOOP; IF trialFace = Regular THEN EXIT; trialFace ¬ IF trialFace = BoldItalic THEN Bold ELSE IF trialFace = Bold AND face = BoldItalic THEN Italic ELSE Regular; ENDLOOP; IF font = NIL THEN { <> <> { font ¬ GetDefaultFont[]; preScaled ¬ FALSE }; }; IF NOT preScaled THEN { font ¬ ImagerFont.Scale[font, size] }; RefText.ReleaseScratch[scratch]; }; EnterStyleFontCache[[prefix, family, face, size, alphabets, font]]; }; IF didSubstitution THEN { text: REF TEXT ¬ RefText.ObtainScratch[100]; text ¬ RefText.AppendRope[text, "Substituting font "]; text ¬ RefText.AppendRope[text, ImagerFont.Name[font]]; text ¬ RefText.AppendRope[text, " for "]; text ¬ AppendFontName[text, prefix, family, face, size, alphabets].new; SimpleFeedback.Append[$Tioga, oneLiner, $Warning, Rope.FromRefText[text] ]; RefText.ReleaseScratch[text]; }; }; <