DIRECTORY CodeTimer, Commander, CommanderOps, Convert, Feedback, FileNames, GGFont, GGModelTypes, GGParseIn, GGParseOut, Imager, ImagerFont, ImagerSys, ImagerTransformation, IO, PFS, Real, Rope, SymTab; GGFontImpl: CEDAR PROGRAM IMPORTS CodeTimer, Commander, CommanderOps, Convert, Feedback, FileNames, GGParseIn, GGParseOut, Imager, ImagerFont, ImagerSys, ImagerTransformation, IO, PFS, Real, Rope, SymTab EXPORTS GGFont = BEGIN Font: TYPE = ImagerFont.Font; FontData: TYPE = GGModelTypes.FontData; FontDataRec: TYPE = GGModelTypes.FontDataRec; ROPE: TYPE = Rope.ROPE; ParseError: PUBLIC ERROR[explanation: ROPE] = CODE; boldList: LIST OF ROPE _ LIST["-B", "-BI", "-IB"]; italicList: LIST OF ROPE _ LIST["-I", "-BI", "-IB"]; fontTable, alternateFontTable: SymTab.Ref; -- created by Init FlushFontCache: PUBLIC PROC = { SymTab.Erase[fontTable]; SymTab.Erase[alternateFontTable]; }; GGFontCache: Commander.CommandProc = { argv: CommanderOps.ArgumentVector _ CommanderOps.Parse[cmd]; IF argv.argc <= 1 THEN GOTO Failed ELSE { IF Rope.Equal[argv[1], "on", FALSE] THEN fontCacheOn _ TRUE ELSE IF Rope.Equal[argv[1], "off", FALSE] THEN fontCacheOn _ FALSE ELSE GOTO Failed; }; EXITS Failed => cmd.err.PutF["usage: GGFontCache enables or disables Gargoyle's font cache\n"]; }; AlternateFont: PUBLIC PROC [data: FontData, font: ImagerFont.Font, op: ATOM] RETURNS [alternate: ImagerFont.Font] = { IF font=NIL THEN RETURN[NIL]; IF op#$visible THEN RETURN[font]; IF Rope.Find[data.prefix, "pressfont", 0, FALSE]#-1 OR Rope.Find[data.prefix, "xc", 0, FALSE]#-1 THEN { epsilon: REAL = 0.01; ft: ImagerTransformation.FactoredTransformation; CodeTimer.StartInt[$AlternateFontHard, $Gargoyle]; ft _ ImagerTransformation.Factor[data.transform]; IF ABS[ABS[ft.s.x] - ABS[ft.s.y]] < epsilon THEN { alternate _ NearestTiogaFont[data.userFSF, ABS[ft.s.x], font]; } ELSE alternate _ font; CodeTimer.StopInt[$AlternateFontHard, $Gargoyle]; } ELSE alternate _ font; }; FontEntry: TYPE = REF FontEntryObj; FontEntryObj: TYPE = RECORD [ font: Font, scaledList: LIST OF ScaledFontEntry ]; fontCacheOn: BOOL _ TRUE; FindScaledFont: PROC [name: ROPE, scale: CARD] RETURNS [scaledFont: Font _ NIL] = { found: BOOL _ FALSE; val: REF; s: REAL; font: Font; IF scale = 0 THEN scale _ 1; s _ scale; IF fontCacheOn THEN { fE: FontEntry; [found, val] _ SymTab.Fetch[fontTable, name]; IF found THEN fE _ NARROW[val] ELSE { font _ ImagerFont.Find[name, noSubstitute ! PFS.Error, Imager.Error, Imager.Warning, ImagerSys.FileError => {font _ NIL; CONTINUE}]; fE _ NEW[FontEntryObj _ [font: font, scaledList: NIL]]; [] _ SymTab.Store[fontTable, name, fE]; }; IF fE.font = NIL THEN RETURN[NIL]; FOR list: LIST OF ScaledFontEntry _ fE.scaledList, list.rest UNTIL list = NIL DO IF scale = list.first.scale THEN RETURN[list.first.font]; ENDLOOP; scaledFont _ ImagerFont.Scale[fE.font, 1.0/s]; fE.scaledList _ CONS[[scale: scale, font: scaledFont], fE.scaledList]; } ELSE { font _ ImagerFont.Find[name, noSubstitute ! PFS.Error, Imager.Error, Imager.Warning, ImagerSys.FileError => {font _ NIL; CONTINUE}]; IF font = NIL THEN RETURN[NIL]; scaledFont _ ImagerFont.Scale[font, 1.0/s]; }; }; ScaledFontRef: TYPE = REF ScaledFontEntry; ScaledFontEntry: TYPE = RECORD [ scale: CARD, font: Font ]; NearestTiogaFont: PROC [userFSF: ROPE, scaleReal: REAL, default: ImagerFont.Font] RETURNS [alternate: ImagerFont.Font] = { fE: ScaledFontRef; TryName: PROC [name: ROPE, scale: CARD] RETURNS [alt: ImagerFont.Font _ NIL] = { scaleRope: ROPE; dashIndex: INT _ Rope.Find[name, "-"]; IF scale = 0 THEN RETURN; scaleRope _ Convert.RopeFromCard[from: scale, base: 10, showRadix: FALSE]; altName _ IF dashIndex=-1 THEN Rope.Cat["xerox/tiogafonts/", name, scaleRope] ELSE Rope.Cat["xerox/tiogafonts/", Rope.Replace[name, dashIndex, Rope.MaxLen, scaleRope]]; alt _ FindScaledFont[altName, scale]; }; scale: CARD; altName: ROPE; scale _ Real.Round[scaleReal]; IF fontCacheOn THEN { found: BOOL _ FALSE; val: REF; fontName: ROPE _ Rope.Concat[userFSF, Convert.RopeFromCard[scale]]; [found, val] _ SymTab.Fetch[alternateFontTable, fontName]; IF found THEN { fE _ NARROW[val]; RETURN[fE.font]; -- this is the fast case } ELSE { fE _ NEW[ScaledFontEntry _ [scale: scale, font: NIL]]; -- fill in font when we GOTO Found; [] _ SymTab.Store[alternateFontTable, fontName, fE]; }; }; BEGIN alternate _ TryName[userFSF, scale]; IF alternate # NIL THEN GOTO Found; alternate _ TryName[userFSF, scale+1]; IF alternate # NIL THEN GOTO Found; IF scale > 0 THEN { alternate _ TryName[userFSF, scale-1]; IF alternate # NIL THEN GOTO Found; }; SELECT scale FROM IN [4..8] => alternate _ TryName[userFSF, 10]; IN [9..10] => alternate _ TryName[userFSF, 12]; IN [14..15] => alternate _ TryName[userFSF, 12]; 16 => alternate _ TryName[userFSF, 18]; 20 => alternate _ TryName[userFSF, 18]; ENDCASE; IF alternate # NIL THEN GOTO Found; IF scale >= 18 THEN { alternate _ default; GOTO Found; }; alternate _ TryName["Helvetica", scale]; IF alternate # NIL THEN GOTO Found; alternate _ TryName["Helvetica", scale+1]; IF alternate # NIL THEN GOTO Found; IF scale > 0 THEN { alternate _ TryName["Helvetica", scale-1]; IF alternate # NIL THEN GOTO Found; }; IF scale = 4 THEN alternate _ TryName["Helvetica", 6] ELSE IF scale = 20 THEN alternate _ TryName["Helvetica", 18]; IF alternate # NIL THEN GOTO Found; IF scale IN [2..17] THEN { Feedback.PutFByName[$Gargoyle, oneLiner, $Error, "Couldn't find alternate font for %g at size %g", [rope[userFSF]], [integer[scale]]]; }; alternate _ default; GOTO Found; EXITS Found => IF fontCacheOn THEN fE.font _ alternate; END; }; CreateFontData: PUBLIC PROC RETURNS [data: FontData] = { data _ NEW[FontDataRec _ []]; data.substituteOK _ TRUE; -- bad hack here. Avoids a bogus font }; CopyFontData: PUBLIC PROC [data: FontData, oldCopy: FontData _ NIL] RETURNS [newCopy: FontData] = { newCopy _ IF oldCopy#NIL THEN oldCopy ELSE CreateFontData[]; IF data#NIL THEN newCopy^ _ data^; IF newCopy.transform#NIL THEN newCopy.transform _ ImagerTransformation.Copy[newCopy.transform]; }; InitFontData: PUBLIC PROC [data: FontData] RETURNS [newData: FontData] = { newData _ data; IF newData#NIL THEN newData^ _ []; -- fill in from definition defaults }; ParseFontData: PUBLIC PROC [data: FontData _ NIL, inStream: IO.STREAM, literalP, prefixP, familyP, faceP, transformP, scaleP, storedSizeP, designSizeP: BOOL _ FALSE] RETURNS [newData: FontData] = { Inner: PROC = { DisallowedEnding: PROC [s: Rope.ROPE] RETURNS [BOOL] = { RETURN[FALSE]; -- who knows what an ending contains these days. }; IF literalP THEN { scratchData.literal _ IO.GetTokenRope[inStream, IO.IDProc].token; -- "xerox/myFonts/FooBarFont" scratchData.prefix _ FileNames.Directory[scratchData.literal]; -- "xerox/myFonts/" scratchData.literalFSF _ FileNames.Tail[scratchData.literal, '/]; -- "FooBarFont" } ELSE { lit: ROPE _ IO.GetTokenRope[inStream, IO.IDProc].token; -- "xerox/xc1-2-2/Modern-BI" IF prefixP THEN { scratchData.prefix _ FileNames.Directory[lit]; -- "xerox/xc1-2-2/" lit _ FileNames.Tail[lit, '/]; -- "Modern-BI" }; IF familyP THEN { IF DisallowedEnding[lit] THEN ParseError["Literal font name not allowed here"]; scratchData.userFSF _ lit; -- "Modern-BI" scratchData.family _ Before[lit, '-]; -- "Modern }; IF faceP THEN { -- means figure out the faces from the userFSF faceRope: ROPE; faceS: IO.STREAM _ IO.RIS[After[scratchData.userFSF, '-]]; -- "-BI" faceRope _ IO.GetTokenRope[faceS, IO.IDProc ! IO.EndOfStream => CONTINUE;].token; -- -BI or SP in other cases FOR boldRope: LIST OF ROPE _ boldList, boldRope.rest UNTIL boldRope=NIL DO IF scratchData.bold THEN EXIT; scratchData.bold _ Rope.Find[faceRope, boldRope.first, 0, FALSE]#-1; ENDLOOP; FOR italicRope: LIST OF ROPE _ italicList, italicRope.rest UNTIL italicRope=NIL DO IF scratchData.italic THEN EXIT; scratchData.italic _ Rope.Find[faceRope, italicRope.first, 0, FALSE]#-1; ENDLOOP; scratchData.faceKnown _ TRUE; }; scratchData.comfortable _ TRUE; }; IF transformP THEN scratchData.transform _ GGParseIn.ReadFactoredTransformationVEC[inStream]; IF scaleP THEN scratchData.scale _ Convert.RealFromRope[IO.GetTokenRope[inStream, IO.IDProc].token]; -- "12 or 20.123 or ..." IF storedSizeP THEN scratchData.storedSize _ Convert.RealFromRope[IO.GetTokenRope[inStream, IO.IDProc].token]; -- "12 or 20.123 or ..." IF designSizeP THEN scratchData.designSize _ Convert.RealFromRope[IO.GetTokenRope[inStream, IO.IDProc].token]; -- "12 or 20.123 or ..." }; -- Inner errorRope: Rope.ROPE; scratchData: FontData _ CreateFontData[]; BEGIN newData _ IF data=NIL THEN CreateFontData[] ELSE data; -- prepare newData scratchData^ _ newData^; -- operate on scratch copy in case failure happens while parsing Inner[ ! IO.Error => {errorRope _ "FontName IO Error"; GOTO Error}; IO.EndOfStream => {errorRope _ "FontName EndOfStream"; GOTO Error}; Convert.Error => {errorRope _ "FontName Convert Error"; GOTO Error}; GGParseIn.SyntaxError => {errorRope _ "FontName SyntaxError"; GOTO Error}; ]; IF literalP THEN UserDataFromFontData[scratchData] ELSE LiteralDataFromFontData[scratchData]; newData^ _ scratchData^; EXITS Error => ParseError[Rope.Concat[errorRope, ": See GGFontSampler.tioga for syntax"]]; END; }; FontDataFromNamelessFont: PUBLIC PROC [font: ImagerFont.Font] RETURNS [newData: FontData] = { newFont: ImagerFont.Font _ NEW[ImagerFont.FontRep _ [ charToClient: ImagerTransformation.Scale[1.0], typeface: font.typeface]]; newData _ CreateFontData[]; newData.storedSize _ 1.0; newData.namelessFont _ newFont; }; DigitProc: IO.BreakProc = { SELECT char FROM IO.LF, IO.CR, IO.TAB, IO.SP => RETURN [break]; '0, '1, '2, '3, '4, '5, '6, '7, '8, '9 => RETURN [break]; ENDCASE => RETURN [other]; }; NonDigitProc: IO.BreakProc = { SELECT char FROM '0, '1, '2, '3, '4, '5, '6, '7, '8, '9 => RETURN [other]; ENDCASE => RETURN [break]; }; LiteralDataFromFontData: PUBLIC PROC [data: FontData] = { Inner: PROC = { HasEndDigits: PROC RETURNS [yep: BOOL _ FALSE] = { ENABLE IO.Error, IO.EndOfStream, Convert.Error => { yep _ FALSE; CONTINUE; }; nameStream: IO.STREAM _ IO.RIS[scratchData.family]; -- Helvetica or cmbbi66 [] _ IO.GetTokenRope[nameStream, DigitProc]; -- toss the leading alpha characters yep _ Convert.IntFromRope[IO.GetTokenRope[nameStream, NonDigitProc].token]>0; -- get any digit characters. Assume font names indicate positive values. }; pressPrefix: Rope.ROPE _ "xerox/pressfonts/"; fisPrefix: Rope.ROPE _ "xerox/xc1-3-3/fis/"; printPrefix: Rope.ROPE _ "xerox/xc1-2-2/"; screenPrefix: Rope.ROPE _ "xerox/tiogafonts/"; faceRope: Rope.ROPE; SELECT TRUE FROM (Rope.Equal[scratchData.prefix, pressPrefix, FALSE] OR Rope.Equal[scratchData.prefix, fisPrefix, FALSE]) AND scratchData.faceKnown => { faceRope _ SELECT TRUE FROM scratchData.bold AND scratchData.italic => "-bir", scratchData.bold => "-brr", scratchData.italic => "-mir", ENDCASE => IF HasEndDigits[] THEN "" ELSE "-mrr"; }; Rope.Equal[scratchData.prefix, printPrefix, FALSE] AND scratchData.faceKnown => { faceRope _ SELECT TRUE FROM scratchData.bold AND scratchData.italic => "-bold-italic", scratchData.bold => "-bold", scratchData.italic => "-italic", ENDCASE => ""; }; Rope.Equal[scratchData.prefix, screenPrefix, FALSE] => { -- derive storedSize from the font name storedSize: REAL _ 1.5; nameStream: IO.STREAM _ IO.RIS[scratchData.userFSF]; -- Tioga10-BI or TERMINAL [] _ IO.GetTokenRope[nameStream, DigitProc]; -- get the leading alpha characters storedSize _ Convert.RealFromRope[IO.GetTokenRope[nameStream, NonDigitProc].token]; -- get any digit characters IF REAL[Real.Fix[storedSize]] # storedSize THEN ParseError["StoredSize must be an integer for screen fonts"]; scratchData.storedSize _ storedSize; -- so things come out the right size faceRope _ SELECT TRUE FROM scratchData.bold AND scratchData.italic => "BI", scratchData.bold => "B", scratchData.italic => "I", ENDCASE => ""; }; ENDCASE => NULL; scratchData.literalFSF _ Rope.Concat[scratchData.family, IF HasMultiple[scratchData.family, '-] THEN NIL ELSE faceRope]; scratchData.literal _ Rope.Concat[scratchData.prefix, scratchData.literalFSF]; }; scratchData: FontData _ CreateFontData[]; errorRope: Rope.ROPE; BEGIN IF data=NIL THEN ParseError["NIL Font Data cannot be parsed"]; scratchData^ _ data^; -- operate on scratch copy in case failure happens while parsing Inner[ ! IO.Error => {errorRope _ "FontName IO Error"; GOTO Error}; IO.EndOfStream => {errorRope _ "FontName EndOfStream"; GOTO Error}; Convert.Error => {errorRope _ "FontName Convert Error"; GOTO Error}; GGParseIn.SyntaxError => {errorRope _ "FontName SyntaxError"; GOTO Error}; ]; data^ _ scratchData^; EXITS Error => ParseError[Rope.Concat[errorRope, ": (example: Helvetica-BI 18 for SetPressFont)"]]; END; }; UserDataFromFontData: PUBLIC PROC [data: FontData] = { Inner: PROC = { userFace, literalFace: Rope.ROPE; pressPrefix: Rope.ROPE _ "xerox/pressfonts/"; printPrefix: Rope.ROPE _ "xerox/xc1-2-2/"; screenPrefix: Rope.ROPE _ "xerox/tiogafonts/"; cmrFamily: Rope.ROPE _ "CMR"; dashBold: Rope.ROPE _ "-bold"; dashItalic: Rope.ROPE _ "-italic"; IF data.literal=NIL OR data.literalFSF=NIL THEN ERROR; data.prefix _ FileNames.Directory[data.literal]; -- xerox/... SELECT TRUE FROM Rope.Equal[data.prefix, pressPrefix, FALSE] => { data.family _ Before[data.literalFSF, '-]; -- Helvetica or CMR literalFace _ FileNames.Tail[data.literalFSF, '-]; -- bir or NIL data.bold _ Rope.Equal[literalFace, "bir", FALSE] OR Rope.Equal[literalFace, "brr", FALSE]; data.italic _ Rope.Equal[literalFace, "bir", FALSE] OR Rope.Equal[literalFace, "mir", FALSE]; data.faceKnown _ TRUE; data.comfortable _ TRUE; userFace _ SELECT TRUE FROM Rope.Equal[literalFace, "bir", FALSE] => "-BI", Rope.Equal[literalFace, "brr", FALSE] => "-B", Rope.Equal[literalFace, "mir", FALSE] => "-I", Rope.Equal[literalFace, "mrr", FALSE] => "", ENDCASE => ""; data.userFSF _ Rope.Concat[data.family, userFace]; }; Rope.Equal[data.prefix, printPrefix, FALSE] => { data.family _ Before[data.literalFSF, '-]; -- Modern or urw-itcgarramond-bold-ps data.bold _ Rope.Find[data.literalFSF, dashBold, 0, FALSE]#-1; -- has -bold data.italic _ Rope.Find[data.literalFSF, dashItalic, 0, FALSE]#-1; -- has -italic data.faceKnown _ TRUE; data.comfortable _ TRUE; userFace _ SELECT TRUE FROM data.bold AND data.italic => "-BI", data.bold => "-B", data.italic => "-I", ENDCASE => ""; data.userFSF _ Rope.Concat[data.family, userFace]; }; Rope.Equal[data.prefix, screenPrefix, FALSE] => { --Tioga10BI or TERMINAL alphaRope, faceRope, storedSizeRope: Rope.ROPE; storedSize: REAL _ 1.5; --, non integer default used below nameStream: IO.STREAM _ IO.RIS[data.literalFSF]; -- Tioga10BI or TERMINAL alphaRope _ IO.GetTokenRope[nameStream, DigitProc].token; -- get the leading alpha characters storedSizeRope _ IO.GetTokenRope[nameStream, NonDigitProc ! IO.EndOfStream, IO.Error => CONTINUE;].token; -- get any digit characters faceRope _ GGParseIn.ReadWWord[nameStream]; -- like BI or NIL storedSize _ Convert.RealFromRope[storedSizeRope ! Convert.Error => CONTINUE;]; -- get any digit characters IF REAL[Real.Fix[storedSize]] # storedSize THEN ParseError["StoredSize must be an integer for screen fonts"]; data.family _ Rope.Concat[alphaRope, storedSizeRope]; -- concat alpha and numeric parts data.scale _ data.storedSize _ storedSize; -- so things come out the right size. Note that this overides the user input during SetFontLiteral. The rule we use is that if you use a TiogaFont with a size in the name, like Tioga10, we derive the storedSize and scale from the name. IF faceRope#NIL THEN faceRope _ Rope.Concat["-", faceRope]; data.userFSF _ Rope.Concat[data.family, faceRope]; data.faceKnown _ TRUE; data.comfortable _ TRUE; FOR boldRope: LIST OF ROPE _ boldList, boldRope.rest UNTIL boldRope=NIL DO IF data.bold THEN EXIT; data.bold _ Rope.Find[faceRope, boldRope.first, 0, FALSE]#-1; ENDLOOP; FOR italicRope: LIST OF ROPE _ italicList, italicRope.rest UNTIL italicRope=NIL DO IF data.italic THEN EXIT; data.italic _ Rope.Find[faceRope, italicRope.first, 0, FALSE]#-1; ENDLOOP; }; ENDCASE => NULL; }; errorRope: Rope.ROPE; BEGIN Inner[ ! IO.Error => {errorRope _ "IO.Error during font parse"; GOTO Error}; IO.EndOfStream => {errorRope _ "IO.EndOfStream during font parse"; GOTO Error}; Convert.Error => {errorRope _ "Convert.Error during font parse"; GOTO Error}; GGParseIn.SyntaxError => {errorRope _ "GGParseIn.SyntaxError during font parse"; GOTO Error}; ]; EXITS Error => ParseError[errorRope]; END; }; HasMultiple: PROC [s: Rope.ROPE, char: CHAR] RETURNS [BOOL] = { IF s=NIL THEN RETURN[FALSE] ELSE { found: BOOL _ FALSE; count: INT _ 0; pos: INT _ 0; len: INT _ s.Length[]; DO IF s.Fetch[pos] = char THEN IF found THEN RETURN[TRUE] ELSE found _ TRUE; pos _ pos + 1; IF pos = len THEN RETURN[FALSE]; ENDLOOP; }; }; Before: PROC [s: Rope.ROPE, char: CHAR] RETURNS [r: Rope.ROPE] = { IF s=NIL THEN RETURN[NIL] ELSE { pos: INT _ 0; len: INT _ s.Length[]; found: BOOL _ FALSE; DO IF s.Fetch[pos] = char THEN { -- found an instance of char in s IF found THEN RETURN[s] ELSE { found _ TRUE; r _ s.Substr[0, pos]; }; }; pos _ pos + 1; IF pos = len THEN RETURN[IF found THEN r ELSE s]; ENDLOOP; }; }; After: PROC [s: Rope.ROPE, char: CHAR] RETURNS [r: Rope.ROPE] = { IF s=NIL THEN RETURN[NIL] ELSE { pos: INT _ 0; len: INT _ s.Length[]; found: BOOL _ FALSE; DO IF s.Fetch[pos] = char THEN { -- found an instance of char in s IF found THEN RETURN[s] ELSE { found _ TRUE; r _ s.Substr[start: pos, len: Rope.MaxLen]; }; }; pos _ pos + 1; IF pos = len THEN RETURN[IF found THEN r ELSE s]; ENDLOOP; }; }; FontAsDetailedRope: PUBLIC PROC [font: FontData] RETURNS [detailed: Rope.ROPE] = { }; FontPutDetailedStream: PUBLIC PROC [font: FontData, stream: IO.STREAM] = { }; FontAsLiteralRope: PUBLIC PROC [font: FontData] RETURNS [literal: Rope.ROPE] = { stream: IO.STREAM; stream _ IO.ROS[]; FontPutLiteralStream[font, stream]; literal _ IO.RopeFromROS[stream]; }; FontPutLiteralStream: PUBLIC PROC [font: FontData, stream: IO.STREAM] = { transformStream: IO.STREAM _ IO.ROS[]; transformRope: Rope.ROPE; GGParseOut.WriteFactoredTransformationVEC[transformStream, font.transform]; transformRope _ IO.RopeFromROS[transformStream]; IO.PutF[stream, "%g %g %g %g %g", [rope[font.literal]], [rope[transformRope]], [real[font.storedSize]], [real[font.designSize]], [rope[IF font.substituted THEN "SUBSTITUTED" ELSE ""]] ]; }; OldParseFontData: PUBLIC PROC [inStream: IO.STREAM, prefixP, familyP, faceP, transformP, sizeP: BOOL _ FALSE] RETURNS [fail: BOOL, prefix, family, face: Rope.ROPE, transform: ImagerTransformation.Transformation, size: REAL _ 0.0] = { ENABLE IO.Error, IO.EndOfStream, Convert.Error, GGParseIn.SyntaxError => { fail _ TRUE; CONTINUE; }; ReadWord: PROC [f: IO.STREAM] RETURNS [word: Rope.ROPE] = { WordBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = CHECKED { SELECT char FROM IO.LF, IO.CR, IO.TAB, IO.SP, ',, '], ') => RETURN [break]; ENDCASE => RETURN [other]; }; [word, ----] _ IO.GetTokenRope[f, WordBreakProc !IO.EndOfStream => {word _ NIL; CONTINUE}]; }; nameStream: IO.STREAM; fail _ FALSE; IF prefixP THEN prefix _ IO.GetTokenRope[inStream, IO.IDProc].token; -- "xerox/myfonts/" nameStream _ IO.RIS[IO.GetTokenRope[inStream, IO.IDProc].token]; -- "fontOne-BI" IF familyP THEN family _ IO.GetTokenRope[nameStream, IO.TokenProc].token; -- "fontOne" IF faceP THEN face _ ReadWord[nameStream]; -- "-BI" (or SP) IF transformP THEN transform _ GGParseIn.ReadFactoredTransformation[inStream]; IF sizeP THEN size _ Convert.RealFromRope[IO.GetTokenRope[inStream, IO.IDProc].token]; -- "12" }; Init: PROC = { fontTable _ SymTab.Create[case: FALSE]; -- cache results of ImagerFont.Find alternateFontTable _ SymTab.Create[case: FALSE]; -- cache results of the alternate font mapping Commander.Register["GGFontCache", GGFontCache, "GGFontCache enables or disables Gargoyle's font cache"]; }; Init[]; END. dGGFontImpl.mesa Copyright Σ 1987, 1989, 1992 by Xerox Corporation. All rights reserved. Bier, March 19, 1992 11:34 am PST Pier, June 17, 1992 5:16 pm PDT Doug Wyatt, December 19, 1989 12:04:59 pm PST endList: LIST OF ROPE _ LIST["mrr", "mir", "brr", "bir", "mor", "bor", "bold", "italic"]; The Font Cache Computing Alternate (Usually Bitmap) Fonts Takes an existing font and fontData and returns an alternate. Only implemented op is $visible. Returns font if no alternate is possible. Remember that the alternate font has to work with the transformation in data.transform. If we have a PressFont or an XC (Print) font, with a suitable data.userFSF, we concoct a TiogaFont name and see if we can Find it. Otherwise, we punt. Creating a FontData Filling a FontData with valuesdefault values, from textual descriptions, from a nameless font, from an alternate font. Utilities for Parsing ! ParseError[explanation] if something goes wrong. Takes a FontData (if NIL, will create a new one), a stream, and BOOLEANS which denote what tokens to parse out of the stream and put in the newData. If literalP is TRUE, then prefixP, familyP, faceP are ignored and the parser only attempts to find a literal string and parses it no further. IF it is not literal, then if familyP then a userFSF string is parsed, and if faceP then the parser tries to extract face information from the userFSF. Fills in as many of the newData fields as possible. tail: Rope.ROPE _ FileNames.Tail[s, '-]; FOR endRope: LIST OF ROPE _ endList, endRope.rest UNTIL endRope=NIL DO IF Rope.Find[tail, endRope.first, 0, FALSE]#-1 THEN RETURN[TRUE]; ENDLOOP; for example, /imagerfonts/xerox/xc1-2-2/mt-monotypebodoni-bold is now a legal name. Not to mention overbold. faceS: IO.STREAM _ IO.RIS[scratchData.userFSF]; -- "Modern-BI" [] _ IO.GetTokenRope[faceS, IO.TokenProc]; -- read and discard family name "Modern" IF transformP THEN scratchData.transform _ GGParseIn.ReadFactoredTransformation[inStream]; IF literalP THEN UserDataFromFontData[scratchData] ELSE LiteralDataFromFontData[scratchData]; this line of code moved to outer proceedure for debugging if you get here, you successfully parsed. Return good data. scratchData: FontData _ CreateFontData[]; BIG MISTAKE Completing a FontData from some of its parts. ! ParseError[explanation] if something goes wrong. Constructs a literal font name from the (non NIL) values in the FontData and fills in the literal field in FontData. This routine has the hairy specific knowledge of the formats of font names. So far: prefix face fontName suffix xerox/xc1-2-2/ -B -bold xerox/xc1-2-2/ -I -italic xerox/xc1-2-2/ -BI -bold-italic xerox/xc1-2-2/ -IB -bold-italic xerox/xc1-2-2/ none none xerox/pressfonts/ -B -brr xerox/pressfonts/ -I -mir xerox/pressfonts/ -BI -bir xerox/pressfonts/ -IB -bir xerox/pressfonts/ none -mrr (unless CMR font) xerox/tiogafonts/ -B Fix[size]B xerox/tiogafonts/ -I Fix[size]I xerox/tiogafonts/ -BI Fix[size]BI xerox/tiogafonts/ -IB Fix[size]BI xerox/tiogafonts/ none Fix[size] For PressFonts Only; digits on the end indicate a "stored size" but ImagerFont produces a unit font with no face characters like -mrr; e.g. cmr60, cmbbi66, ... Note: this won't work for italic fonts named -bor, but both -bir and -bor extensions are found in the xerox/xc1-3-3/fis directory, so we would actually have to look at the files to disambiguate. Yuk. For TiogaFonts, scratchData.family includes storedSize, like Tioga10 if you get here, you successfully parsed. Return good data. ! ParseError[explanation] if something goes wrong. Parses the literal font string in FontData, filling in the other values in FontData as possible. xerox/pressfonts/Helvetica-bir or xerox/pressfonts/CMR63 xerox/xc1-2-2/Modern-bold-italic xerox/xc1-2-2/urw-itcgaramond-bold-italic-ps may look garbaged because print font names have become complex HasMultiple returns TRUE if more than one instance of char is found in s Before returns the part of a rope before the first instance of char. Before returns the entire rope if char is not found OR if multiple instances of char are found IF s.Fetch[pos] = char THEN RETURN[s.Substr[0, pos]]; After returns the part of a rope including and after the first instance of char. After returns the entire rope if char is not found OR if multiple instances of char are found Describing a Font Textually For Compatibility Used to read in a rope which is data. WordBreakProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = CHECKED { SELECT char FROM IO.TAB => RETURN [break]; IO.CR =>RETURN [break]; IO.SP => RETURN [break]; ', => RETURN [break]; '] => RETURN [break]; ') => RETURN [break]; ENDCASE => RETURN [other]; }; Κ:•NewlineDelimiter – "cedar" style˜J™šœH™HIcode™!Jšœ™J™-J™—šΟk ˜ Jšœ€œ˜ΐ—J˜šΟn œœ˜Jšœœ˜±Kšœ ˜—˜Kšœœ˜Kšœ œ˜'Kšœ œ˜-Kšœœœ˜K˜—š ž œœœœœ˜3K˜—Kš œ œœœœ˜2Kš œ œœœœ˜4Kš œ œœœœ=™YK˜K™Kšœ+Οc˜=šžœœœ˜Kšœ˜Kšœ!˜!K˜K˜—šž œ˜&Kšœ<˜K˜—Kšœ˜Kšœ1˜1K˜—Kšœ˜J˜J˜—Jšœ œœ˜#šœœœ˜Jšœ ˜ Jšœ œœ˜#J˜J˜J˜—Jšœ œœ˜š žœœœ œœœ˜SKšœœœ˜Kšœœ˜ Kšœœ˜Kšœ ˜ K˜Kšœ œ ˜Kšœ ˜ K˜šœ œ˜Kšœ˜Kšœ  œ˜-Kšœœœ˜šœ˜Kšœ,œEœœ˜„Kšœœ)œ˜7Kšœ'˜'K˜—Kš œ œœœœ˜"š œœœ,œœ˜PJšœœΠbkœ˜9Jšœ˜—Kšœ.˜.Kšœœ2˜FK˜—šœ˜Kšœ,œEœœ˜„Kš œœœœœ˜Kšœ+˜+K˜—J˜J˜—Jšœœœ˜*šœœœ˜ Jšœœ˜ Jšœ ˜ J˜J˜—š žœœ œ œœ!˜zKšœ˜š žœœœ œœœ˜PKšœ ˜Kšœ œ˜&K˜Kšœ œœ˜KšœCœ˜Jšœ œ ˜Kšœ/˜3KšœV˜Z—Kšœ%˜%K˜—Kšœœ˜ Kšœ ˜Kšœ˜K˜šœ œ˜Kšœœœ˜Kšœœ˜ Kšœ œ5˜CKšœ:˜:šœœ˜Kšœœ˜Kš‘ #˜)K˜—šœ˜Kšœœ(œŸ#˜ZKšœ4˜4K˜—K˜—š˜Jšœ$˜$Jšœ œœœ˜#Jšœ&˜&Jšœ œœœ˜#šœ œ˜Jšœ&˜&Jšœ œœœ˜#J˜—šœ˜Jšœ,˜.Jšœ-˜/Jšœ.˜0Jšœ'˜'Jšœ'˜'Jšœ˜—Jšœ œœœ˜#šœ œ˜Jšœ˜Jšœ˜ J˜—Jšœ(˜(Jšœ œœœ˜#Jšœ*˜*Jšœ œœœ˜#šœ œ˜Jšœ*˜*Jšœ œœœ˜#J˜—Jšœ œ$˜5Jšœœ œ&˜=Jšœ œœœ˜#šœœ œ˜Jšœ†˜†J˜—Jšœ˜Jšœ˜ š˜Jšœ œ œ˜1—Jšœ˜—J˜—K˜™K˜—šžœœœœ˜8Kšœœ˜KšœœŸ%˜?K˜K˜—š ž œœœ&œœ˜cKš œ œ œœ œ˜[s1: ROPE, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE]š œ œœœœ œ™FKš œ#œœœœ™AKšœ™—šœœŸΠbc-˜?Kš m™m—K˜K˜—šœ œ˜KšœœœŸ˜_K–[s: ROPE, char: CHAR]šœ?Ÿ˜RK–[s: ROPE, char: CHAR]šœBŸ˜QKšœ˜—šœ˜KšœœœœŸ˜Tšœ œ˜Kšœ/Ÿ˜BKšœŸ˜-K˜—šœ œ˜Kšœœ2˜OKšœŸ˜)Kšœ&Ÿ ˜0Kšœ˜—šœœŸ.˜>Kšœ œ˜Kš œœœœœŸ™?Kš œœœœœ"Ÿ˜DKšœœœ Ÿ(™SKš œ œœ œœ Ÿ˜n–>[s1: ROPE, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE]š œ œœœœ œ˜JKšœœœ˜Kšœ:œ˜DKšœ˜—–>[s1: ROPE, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE]š œ œœœœ œ˜RKšœœœ˜ Kšœ>œ˜HKšœ˜—Kšœœ˜K˜—Kšœœ˜K˜—K– [f: STREAM]šœ œH™ZK– [f: STREAM]šœ œK˜]K– [r: ROPE]š œœ*œœŸ˜}K– [r: ROPE]š œ œ/œœŸ˜‡K– [r: ROPE]š œ œ/œœŸ˜‡šœ œ#œ&™]Kš 9™9—KšœŸ˜ —K˜Kšœœ˜Kšœ)˜)š˜Kš œ œœœœŸ˜IKšœŸ@˜Zšœ œΟtœœ˜CKšœ£ œœ˜CKšœ £œœ˜EKšœ'£œœ˜JKšœ˜K˜—Kšœ œ#œ&˜]˜Kš ;™;—K˜š˜KšœT˜T—Kšœ˜—K˜K˜—šžœœœœ˜]šœœ˜5Kšœ.˜.Kšœ˜—Kšœ˜Kšœ˜Kšœ˜K˜K˜—K™šœ7™7K˜—šž œœ˜procšœ˜Lšœœœœœœœœœ ˜.Lšœ*œ ˜9Lšœœ ˜—K˜K˜—šž œœ˜šœ˜Lšœ*œ ˜9Lšœœ ˜—K˜—K˜šœ-™-K˜—šžœœœ˜9K™2Kšœ-œD™tšœK™KKšœ ™%K™Kšœ™Kšœ™Kšœœ ™ Kšœœ ™ Kšœ™K™Kšœ™Kšœ™Kšœœ™Kšœœ™Kšœ%œ™.K™Kšœ ™ Kšœ ™ Kšœœ ™"Kšœœ ™"Kšœ!™!K™—šžœœ˜š ž œœœœœ˜2Kšœ ™ š‘œœœ!˜4Kšœœ˜ Kšœ˜ Kšœ˜—Kš œ œœœœŸ˜KKšœœ&Ÿ$˜QKšœœ2ŸH˜–K˜—Kšœœ˜-Kšœœ˜,Kšœœ˜*Kšœœ˜.Kšœœ˜šœœ˜š œ-œœ+œœ˜‡KšœΘ™Θšœ œœ˜Kšœœ˜2Kšœ˜Kšœ˜K–9[base: ROPE, start: INT _ 0, len: INT _ 2147483647]šœœœœ˜1—Kšœ˜—šœ,œœ˜Qšœ œœ˜Kšœœ&˜:Kšœ˜Kšœ ˜ Kšœ˜—K˜Kšœ˜—šœ-œŸ'˜`K™DKšœ œ˜Kš œ œœœœŸ˜NKšœœ&Ÿ#˜PKšœ"œ0Ÿ˜oKšœœ$œ>˜mKšœ&Ÿ$˜Jšœ œœ˜Kšœœ˜0Kšœ˜Kšœ˜Kšœ˜—Kšœ˜—Kšœœ˜K˜—Kš œ9œ%œœœ ˜xKšœN˜NK˜K˜—Kšœ)˜)Kšœœ˜š˜Kšœœœ.˜>KšœŸ@˜Wšœ œ£œœ˜CKšœ£ œœ˜CKšœ £œœ˜EKšœ'£œœ˜JKšœ˜Kš ;™;—K˜š˜Kšœ]˜]—Kšœ˜—K˜K˜—šžœœœ˜6K™2Kšœ`™`šžœœ˜Kšœœ˜!Kšœœ˜-Kšœœ˜*Kšœœ˜.Kšœœ ˜Kšœœ ˜Kšœœ ˜"K˜K–[path: ROPE]š œœœœœœ˜6Kšœ2Ÿ ˜>šœœ˜šœ%œ˜0Kšœ3™8Kšœ+Ÿ˜>Kšœ3Ÿ ˜@Kšœ+œœ œ˜[Kšœ-œœ œ˜]Kšœœ˜Kšœœ˜šœ œœ˜Kšœœ ˜/Kšœœ ˜.Kšœœ ˜.Kšœœ˜,Kšœ˜—Kšœ2˜2K˜—šœ%œ˜0Kšœ ™ Kšœ,™,Kšœ+Ÿ’"˜PKšœ4œŸ ˜KKšœ8œŸ˜QKšœœ˜Kšœœ˜šœ œœ˜Kšœ œ˜#Kšœ˜Kšœ˜Kšœ˜—šœ2˜2Kš >™>—K˜—šœ&œŸ˜IKšœ*œ˜/Kšœ œŸ"˜:Kš œ œœœœŸ˜IKšœ œ,Ÿ#˜]Kš œœ)œœ œ Ÿ˜…Kšœ,Ÿ˜=KšœDœŸ˜kKšœœ$œ>˜mKšœ6Ÿ!˜WKšœ,Ÿμ˜˜Kšœ œœ'˜;Kšœ2˜2Kšœœ˜Kšœœ˜–>[s1: ROPE, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE]š œ œœœœ œ˜JKšœ œœ˜Kšœ3œ˜=Kšœ˜—–>[s1: ROPE, s2: ROPE, pos1: INT _ 0, case: BOOL _ TRUE]š œ œœœœ œ˜RKšœ œœ˜Kšœ7œ˜AKšœ˜—K˜—Kšœœ˜—K˜K˜—Kšœœ˜š˜šœ œ£œœ˜LKšœ£œ £œœ˜OKšœ £œœ˜NKšœ<£œœ˜]Kšœ˜—š˜Kšœ˜—Kšœ˜—K˜K˜—š ž œœ œœœœ˜?KšœH™HKš œœœœœ˜šœ˜Kšœœœ˜Kšœœ˜Kšœœ˜ Kšœœ˜š˜Kšœœœœœœœ œ˜IK˜Kšœ œœœ˜ Kšœ˜—K˜—K˜K˜—š žœœ œœœ œ˜BK™DK™^Kš œœœœœ˜šœ˜Kšœœ˜ Kšœœ˜Kšœœœ˜š˜Kšœœœ™5šœœŸ!˜?šœœœœ˜Kšœœ˜#K˜—K˜—K˜Kš œ œœœœœ˜1Kšœ˜—K˜—K˜K˜—š žœœ œœœ œ˜AKšžœK™PKšžœX™]Kš œœœœœ˜šœ˜Kšœœ˜ Kšœœ˜Kšœœœ˜š˜šœœŸ!˜?šœœœœ˜Kšœœ œ˜9K˜—K˜—K˜Kš œ œœœœœ˜1Kšœ˜—K˜—K˜K˜—K™™K™—š žœœœœœ˜RK˜K˜—š žœœœœœ˜JK˜K˜—š žœœœœœ˜PKšœœœ˜Kšœ œœ˜Kšœ#˜#Kšœ!˜!K˜K˜—š žœœœœœ˜IK–ldStream: STREAM _ NIL]š œœœœœ˜&Kšœœ˜KšœK˜KKšœœ˜0Kšœ…œœœ˜ΊK˜—K™™J˜—šžœœœ œœ.œœœœœ8œ ˜ιšœœœ7˜JKšœœ˜ Kšœ˜ Kšœ˜—š žœœœœœ œ˜;Lšœ%™%šž œœœœœœœ™Hšœ™Lšœœœ ™Lšœœœ ™Lšœœœ ™Lšœœ ™Lšœœ ™Lšœœ ™Lšœœ ™—Lšœ™—šž œœœœœœœ˜Hšœ˜Lš œœœœœœ ˜:Lšœœ ˜—Lšœ˜—šœŸœœ˜/Lšœœœœ˜+—Lšœ˜L˜—Kšœ œœ˜Kšœœ˜ Kš œ œ œœŸ˜XKš œ œœœœŸ˜PKš œ œ œœŸ ˜VKšœœŸ˜;K– [f: STREAM]šœ œ<˜NK– [r: ROPE]š œœœœŸ˜^Jšœ˜—K˜šžœœ˜Kšœ œŸ#˜KKšœ)œŸ.˜_K˜sK˜K˜—K˜K˜Kšœ˜J˜J˜J˜—…—Mΰ~~