DIRECTORY Ascii USING [BS, CR, FF, LF, SP, TAB], Atom USING [MakeAtom, MakeAtomFromRefText], Basics USING [BITXOR, BoundsCheck, LongNumber, RawBytes, UnsafeBlock], ImagerBox USING [Box], ImagerPath USING [CurveToProc, LineToProc, MoveToProc], ImagerTransformation USING [Create, Transformation], IO USING [GetChar, STREAM], Real USING [PairToReal, PlusInfinity, RealException], RefTab USING [Create, EachPairAction, Fetch, GetSize, Pairs, Ref, Store], RefText USING [ObtainScratch, ReleaseScratch, ReserveChars], Rope USING [FromRefText, ROPE], SafeStorage USING [GetUntracedZone], Type1Font, Vector2 USING [VEC]; Type1FontImpl: CEDAR PROGRAM IMPORTS Atom, Basics, ImagerTransformation, IO, Real, RefTab, RefText, Rope, SafeStorage EXPORTS Type1Font = BEGIN OPEN Type1Font; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; VEC: TYPE = Vector2.VEC; Class: TYPE = { newLine, -- CR, LF, FF space, -- SP, TAB openParen, -- '( closeParen, -- ') openBracket, -- '[ closeBracket, -- '] openAngle, -- '< closeAngle, -- '> openBrace, -- '{ closeBrace, -- '} slash, -- '/ percent, -- '% dot, -- '. hash, -- '# sign, -- '+, '- digitOctal, -- IN ['0..'7] digitOther, -- IN ['0..'9] (other than digitOctal) letterE, -- 'E, 'e letterHex, -- IN ['A..'F], IN ['a..'f] (other than letterE) letterOther, -- IN ['A..'Z], IN ['a..'z] (other than letterE, letterHex) backslash, -- '\ other -- everything else }; WhiteSpace: TYPE = Class [newLine..space]; Special: TYPE = Class [openParen..percent]; Regular: TYPE = Class [dot..other]; DecimalDigit: TYPE = Class [digitOctal..digitOther]; -- ['0..'9] HexDigit: TYPE = Class [digitOctal..letterHex]; -- ['0..'9], ['A..'F], ['a..'f] RadixDigit: TYPE = Class [digitOctal..letterOther]; -- ['0..'9], ['A..'Z], ['a..'z] ClassArray: TYPE = PACKED ARRAY CHAR OF Class; Digit: TYPE = [0..36); DigitArray: TYPE = PACKED ARRAY CHAR OF Digit; EscapeArray: TYPE = PACKED ARRAY CHAR OF CHAR; State: TYPE = { empty, -- only whitespace so far sign, -- + | - int0, -- digit | int0 digit a valid integer (without sign) int1, -- sign digit | int1 digit a valid integer (with sign) real0, -- . | sign . real1, -- ( int0 | int1 ) . | real0 digit | real1 digit a valid real (without exponent) real2, -- ( int0 | int1 | real1 ) ( e | E ) real3, -- real2 ( + | - ) real4, -- ( real2 | real3 ) digit | real4 digit a valid real (with exponent) radix0, -- int0 # radix1, -- radix0 rdigit | radix1 rdigit a valid radix number name, -- char | name char a name nameLit, -- / | nameLit char a literal name string, -- ( ... esc0, -- ( ... \ esc1, -- ( ... \d esc2, -- ( ... \dd hex0, -- < ... even number of digits hex1, -- < ... odd number of digits comment, -- % ... special, -- { | } | [ | ] error -- syntax error }; Action: TYPE = { skip, -- ignore char append, -- append char to text buffer putBack, -- return char to input source and stop parenOpen, -- increment paren count and include char in string literal parenClose, -- if paren count=0, stop; else decrement paren count and include char escapeChar, -- translate escape char following '\ escapeDigit, -- include another octal digit in escape sequence hexDigit1, -- char is first hex digit hexDigit2, -- char is second hex digit, append byte hexFill -- use zero for missing second digit, append byte, and stop }; TransitionResult: TYPE = PACKED RECORD [ state: State, action: Action, stop: BOOL ฌ FALSE ]; TransitionTable: TYPE = ARRAY State OF REF TransitionArray ฌ ALL[NIL]; TransitionArray: TYPE = PACKED ARRAY Class OF TransitionResult; RClass: TYPE = { digit, -- IN ['0..'9] sign, -- '+, '- dot, -- '. letterE, -- 'E, 'e other -- everything else }; RClassArray: TYPE = PACKED ARRAY CHAR OF RClass; RState: TYPE = { empty, -- beginning msign, -- + | - int, -- ( empty | msign | int ) digit integer part dot, -- ( empty | msign ) . idot, -- int . frac, -- ( dot | idot | frac ) digit fraction part epref, -- ( int | idot | frac ) ( e | E ) esign, -- epref ( + | - ) exp, -- ( epref | esign | exp ) digit exponent part error }; RTransitionTable: TYPE = ARRAY RState OF REF RTransitionArray ฌ ALL[NIL]; RTransitionArray: TYPE = PACKED ARRAY RClass OF RState; classFromChar: REF ClassArray = InitClassArray[]; digit: REF DigitArray = InitDigitArray[]; escape: REF EscapeArray = InitEscapeArray[]; transition: REF TransitionTable = InitTransitionTable[]; rclassFromChar: REF RClassArray = RClassInit[]; rtransition: REF RTransitionTable = RTransitionInit[]; InvalidFont: PUBLIC ERROR ~ CODE; InitClassArray: PROC RETURNS [array: REF ClassArray ฌ NIL] = { array ฌ NEW[ClassArray]; FOR char: CHAR IN CHAR DO array[char] ฌ SELECT char FROM Ascii.CR, Ascii.LF, Ascii.FF => newLine, Ascii.SP, Ascii.TAB => space, '( => openParen, ') => closeParen, '[ => openBracket, '] => closeBracket, '< => openAngle, '> => closeAngle, '{ => openBrace, '} => closeBrace, '/ => slash, '% => percent, '. => dot, '# => hash, '+, '- => sign, IN ['0..'7] => digitOctal, IN ['0..'9] => digitOther, 'E, 'e => letterE, IN ['A..'F], IN ['a..'f] => letterHex, IN ['A..'Z], IN ['a..'z] => letterOther, '\\ => backslash, ENDCASE => other; ENDLOOP; }; InitDigitArray: PROC RETURNS [array: REF DigitArray ฌ NIL] = { array ฌ NEW[DigitArray]; FOR char: CHAR IN CHAR DO array[char] ฌ SELECT char FROM IN ['0..'9] => char - '0, IN ['A..'Z] => 10 + (char - 'A), IN ['a..'z] => 10 + (char - 'a), ENDCASE => 0; ENDLOOP; }; InitEscapeArray: PROC RETURNS [array: REF EscapeArray ฌ NIL] = { array ฌ NEW[EscapeArray]; FOR char: CHAR IN CHAR DO array[char] ฌ SELECT char FROM 'n => Ascii.LF, 'r => Ascii.CR, 't => Ascii.TAB, 'b => Ascii.BS, 'f => Ascii.FF, IN ['0..'7] => VAL[digit[char]], ENDCASE => char; ENDLOOP; }; Transition: PROC [state: State, class: Class] RETURNS [TransitionResult] = { SELECT state FROM empty => { IF class IN WhiteSpace THEN RETURN[[action: skip, state: empty]]; IF class IN Special THEN SELECT class FROM percent => RETURN[[action: skip, state: comment]]; slash => RETURN[[action: skip, state: nameLit]]; openParen => RETURN[[action: skip, state: string]]; openAngle => RETURN[[action: skip, state: hex0]]; ENDCASE => RETURN[[action: append, state: special, stop: TRUE]]; }; IN [sign..nameLit] => { IF class IN WhiteSpace THEN RETURN[[action: skip, state: state, stop: TRUE]]; IF class IN Special THEN RETURN[[action: putBack, state: state, stop: TRUE]]; }; IN [hex0..hex1] => { IF class IN WhiteSpace THEN RETURN[[action: skip, state: state]]; }; ENDCASE; SELECT state FROM empty => SELECT class FROM sign => RETURN[[action: append, state: sign]]; dot => RETURN[[action: append, state: real0]]; IN DecimalDigit => RETURN[[action: append, state: int0]]; ENDCASE => RETURN[[action: append, state: name]]; sign => SELECT class FROM dot => RETURN[[action: append, state: real0]]; IN DecimalDigit => RETURN[[action: append, state: int1]]; ENDCASE => RETURN[[action: append, state: name]]; int0 => SELECT class FROM dot => RETURN[[action: append, state: real1]]; letterE => RETURN[[action: append, state: real2]]; hash => RETURN[[action: append, state: radix0]]; IN DecimalDigit => RETURN[[action: append, state: int0]]; ENDCASE => RETURN[[action: append, state: name]]; int1 => SELECT class FROM dot => RETURN[[action: append, state: real1]]; letterE => RETURN[[action: append, state: real2]]; IN DecimalDigit => RETURN[[action: append, state: int1]]; ENDCASE => RETURN[[action: append, state: name]]; real0 => SELECT class FROM IN DecimalDigit => RETURN[[action: append, state: real1]]; ENDCASE => RETURN[[action: append, state: name]]; real1 => SELECT class FROM letterE => RETURN[[action: append, state: real2]]; IN DecimalDigit => RETURN[[action: append, state: real1]]; ENDCASE => RETURN[[action: append, state: name]]; real2 => SELECT class FROM sign => RETURN[[action: append, state: real3]]; IN DecimalDigit => RETURN[[action: append, state: real4]]; ENDCASE => RETURN[[action: append, state: name]]; real3 => SELECT class FROM IN DecimalDigit => RETURN[[action: append, state: real4]]; ENDCASE => RETURN[[action: append, state: name]]; real4 => SELECT class FROM IN DecimalDigit => RETURN[[action: append, state: real4]]; ENDCASE => RETURN[[action: append, state: name]]; radix0 => SELECT class FROM IN RadixDigit => RETURN[[action: append, state: radix1]]; ENDCASE => RETURN[[action: append, state: name]]; radix1 => SELECT class FROM IN RadixDigit => RETURN[[action: append, state: radix1]]; ENDCASE => RETURN[[action: append, state: name]]; name => RETURN[[action: append, state: name]]; nameLit => RETURN[[action: append, state: nameLit]]; string => SELECT class FROM openParen => RETURN[[action: parenOpen, state: string]]; closeParen => RETURN[[action: parenClose, state: string]]; backslash => RETURN[[action: skip, state: esc0]]; ENDCASE => RETURN[[action: append, state: string]]; esc0 => SELECT class FROM newLine => RETURN[[action: skip, state: string]]; digitOctal => RETURN[[action: escapeChar, state: esc1]]; ENDCASE => RETURN[[action: escapeChar, state: string]]; esc1 => SELECT class FROM closeParen => RETURN[[action: parenClose, state: string]]; digitOctal => RETURN[[action: escapeDigit, state: esc2]]; ENDCASE => RETURN[[action: append, state: string]]; esc2 => SELECT class FROM closeParen => RETURN[[action: parenClose, state: string]]; digitOctal => RETURN[[action: escapeDigit, state: string]]; ENDCASE => RETURN[[action: append, state: string]]; hex0 => SELECT class FROM closeAngle => RETURN[[action: skip, state: hex0, stop: TRUE]]; IN HexDigit => RETURN[[action: hexDigit1, state: hex1]]; ENDCASE => RETURN[[action: skip, state: error, stop: TRUE]]; hex1 => SELECT class FROM closeAngle => RETURN[[action: skip, state: hex1, stop: TRUE]]; IN HexDigit => RETURN[[action: hexDigit2, state: hex0]]; ENDCASE => RETURN[[action: skip, state: error, stop: TRUE]]; comment => SELECT class FROM newLine => RETURN[[action: skip, state: empty]]; ENDCASE => RETURN[[action: skip, state: comment]]; ENDCASE => RETURN[[action: skip, state: error, stop: TRUE]]; }; InitTransitionTable: PROC RETURNS [table: REF TransitionTable ฌ NIL] = { table ฌ NEW[TransitionTable]; FOR state: State IN State DO array: REF TransitionArray = NEW[TransitionArray]; FOR class: Class IN Class DO array[class] ฌ Transition[state, class]; ENDLOOP; table[state] ฌ array; ENDLOOP; }; RClassInit: PROC RETURNS [array: REF RClassArray ฌ NIL] = { array ฌ NEW[RClassArray]; FOR char: CHAR IN CHAR DO array[char] ฌ SELECT char FROM IN ['0..'9] => digit, '+, '- => sign, '. => dot, 'E, 'e => letterE, ENDCASE => other; ENDLOOP; }; RTransition: PROC [state: RState, class: RClass] RETURNS [RState] = { RETURN[ SELECT state FROM empty => SELECT class FROM digit => int, sign => msign, dot => dot, ENDCASE => error, msign => SELECT class FROM digit => int, dot => dot, ENDCASE => error, int => SELECT class FROM digit => int, dot => idot, letterE => epref, ENDCASE => error, dot => SELECT class FROM digit => frac, ENDCASE => error, idot, frac => SELECT class FROM digit => frac, letterE => epref, ENDCASE => error, epref => SELECT class FROM digit => exp, sign => esign, ENDCASE => error, esign => SELECT class FROM digit => exp, ENDCASE => error, exp => SELECT class FROM digit => exp, ENDCASE => error, ENDCASE => error ]; }; RTransitionInit: PROC RETURNS [table: REF RTransitionTable ฌ NIL] = { table ฌ NEW[RTransitionTable]; FOR state: RState IN RState DO array: REF RTransitionArray = NEW[RTransitionArray]; FOR class: RClass IN RClass DO array[class] ฌ RTransition[state, class]; ENDLOOP; table[state] ฌ array; ENDLOOP; }; GetHexDigit: PROC [stream: STREAM] RETURNS [Digit] ~ { DO c: CHAR ~ IO.GetChar[stream]; IF classFromChar[c] IN HexDigit THEN RETURN[digit[c]]; ENDLOOP; }; GetChar: PUBLIC PROC [s: Source] RETURNS [CHAR] ~ { IF s.putBack THEN { s.putBack ฌ FALSE; RETURN[s.putBackChar] }; SELECT s.cipher FROM plain => RETURN[IO.GetChar[s.stream]]; binary => RETURN[Decrypt1[s.key, IO.GetChar[s.stream]]]; hex => { d0: Digit ~ GetHexDigit[s.stream]; d1: Digit ~ GetHexDigit[s.stream]; RETURN[Decrypt1[s.key, VAL[d0*16+d1]]]; }; ENDCASE => ERROR; }; PutBack: PUBLIC PROC [s: Source, c: CHAR] ~ { IF s.putBack THEN ERROR; s.putBack ฌ TRUE; s.putBackChar ฌ c; }; GetToken: PUBLIC PROC [s: Source] RETURNS [Token] = { text: REF TEXT ฌ s.buffer; maxlength: NAT ฌ text.maxLength; length: NAT ฌ 0; -- text length state: State ฌ empty; parens: CARDINAL ฌ 0; -- level of unbalanced parentheses within a string DO -- for each character char: CHAR ~ GetChar[s]; class: Class ~ classFromChar[char]; result: TransitionResult ~ transition[state][class]; achar: CHAR ฌ char; -- character to append to text state ฌ result.state; { SELECT result.action FROM skip => GOTO Skip; append => NULL; putBack => { PutBack[s, char]; GOTO Skip }; parenOpen => parens ฌ parens+1; parenClose => IF parens>0 THEN parens ฌ parens-1 ELSE EXIT; escapeChar => achar ฌ escape[char]; escapeDigit => achar ฌ VAL[ORD[text[length ฌ length-1]]*8+digit[char]]; hexDigit1 => achar ฌ VAL[digit[char]*16]; hexDigit2 => achar ฌ VAL[ORD[text[length ฌ length-1]]+digit[char]]; ENDCASE => ERROR InvalidFont; IF NOT length NULL; }; IF result.stop THEN EXIT; ENDLOOP; text.length ฌ length; SELECT state FROM empty, comment => RETURN [[null, NIL]]; int0, int1 => RETURN [[int, text, TRUE]]; real1, real4 => RETURN [[real, text, TRUE]]; radix1 => RETURN [[radix, text, TRUE]]; string, hex0, hex1 => RETURN [[string, text, TRUE]]; nameLit => RETURN [[name, text, TRUE]]; special => RETURN [[special, text]]; error => ERROR InvalidFont; ENDCASE => RETURN [[name, text]]; }; CardFromText: PROC [text: REF TEXT, start: NAT ฌ 0, radix: NAT ฌ 10] RETURNS [CARD] = { limit: CARD ~ CARD.LAST / radix; val: CARD ฌ 0; IF radix NOT IN [2..36] THEN GOTO Bogus; FOR i: NAT IN [start..text.length) DO char: CHAR = text[i]; d: Digit = digit[char]; IF NOT d < radix THEN GOTO Bogus; IF val > limit THEN GOTO Bogus ELSE val ฌ val * radix; IF d > (CARD.LAST - val) THEN GOTO Bogus ELSE val ฌ val + d; ENDLOOP; RETURN [val]; EXITS Bogus => ERROR InvalidFont; }; IntFromText: PROC [text: REF TEXT] RETURNS [INT] = { SELECT text[0] FROM '+ => RETURN[CardFromText[text, 1]]; '- => RETURN[-CardFromText[text, 1]]; ENDCASE => RETURN[CardFromText[text, 0]]; }; RadixFromText: PROC [text: REF TEXT] RETURNS [INT] = { radix: NAT ฌ 0; FOR i: NAT IN[0..text.length) DO char: CHAR ~ text[i]; SELECT char FROM IN['0..'9] => { radix ฌ radix * 10 + digit[char]; IF radix>36 THEN EXIT }; '# => RETURN[LOOPHOLE[CardFromText[text: text, start: i+1, radix: radix], INT]]; ENDCASE => EXIT; ENDLOOP; ERROR InvalidFont; }; RealFromText: PROC [text: REF TEXT] RETURNS [REAL] = { state: RState ฌ empty; fr: INT ฌ 0; -- mantissa exp, adj: INTEGER ฌ 0; -- exponent and adjustment mNeg, eNeg: BOOL ฌ FALSE; mDigits, eDigits: NAT ฌ 0; -- significant digits real: REAL; FOR i: NAT IN [0..text.length) DO char: CHAR = text[i]; state ฌ rtransition[state][rclassFromChar[char]]; SELECT state FROM msign => mNeg ฌ (char = '-); int, frac => { d: [0..10) = char - '0; IF state = frac THEN adj ฌ adj - 1; IF mDigits = 0 AND d = 0 THEN NULL -- leading zero ELSE IF mDigits < 9 THEN {fr ฌ fr * 10 + d; mDigits ฌ mDigits + 1} ELSE {adj ฌ adj + 1; IF mDigits = 9 AND d > 5 THEN fr ฌ fr + 1; }; -- round if 10th digit >5 }; esign => eNeg ฌ (char = '-); exp => { d: [0..10) = char - '0; IF eDigits = 0 AND d = 0 THEN NULL -- leading zero ELSE IF eDigits < 3 THEN {exp ฌ exp * 10 + d; eDigits ฌ eDigits + 1}; }; error => GOTO Fail; ENDCASE; ENDLOOP; SELECT state FROM int, idot, frac, exp => NULL; -- ok ENDCASE => GOTO Fail; IF mNeg THEN fr ฌ -fr; IF eNeg THEN exp ฌ -exp; real ฌ Real.PairToReal[fr: fr, exp10: exp + adj ! Real.RealException => SELECT TRUE FROM flags[overflow] => GOTO Big; flags[underflow] => GOTO Little; ENDCASE => GOTO Fail ]; RETURN[real]; EXITS Big => RETURN[Real.PlusInfinity]; Little => RETURN[0.0]; Fail => ERROR InvalidFont; }; GetKeyword: PUBLIC PROC [s: Source] RETURNS [ATOM] ~ { nest: NAT ฌ 0; DO token: Token ~ GetToken[s]; IF token.type=special THEN SELECT token.text[0] FROM '{, '[ => { nest ฌ nest+1; LOOP }; '}, '] => IF nest>0 THEN { nest ฌ nest-1; LOOP }; ENDCASE; IF nest=0 THEN SELECT token.type FROM name => RETURN[Atom.MakeAtomFromRefText[token.text]]; ENDCASE => RETURN[NIL]; ENDLOOP; }; SkipToKeyword: PROC [s: Source, keyword: ATOM] ~ { DO IF GetKeyword[s]=keyword THEN EXIT ENDLOOP; }; GetIntBeforeKeyword: PROC [s: Source, key: ATOM] RETURNS [val: INT ฌ 0] ~ { nest: NAT ฌ 0; DO token: Token ~ GetToken[s]; IF token.type=special THEN SELECT token.text[0] FROM '{, '[ => { nest ฌ nest+1; LOOP }; '}, '] => IF nest>0 THEN { nest ฌ nest-1; LOOP }; ENDCASE; IF nest=0 THEN SELECT token.type FROM int, radix => val ฌ IntFromToken[token]; name => IF Atom.MakeAtomFromRefText[token.text]=key THEN RETURN; ENDCASE; ENDLOOP; }; GetIntAfterKeyword: PROC [s: Source, key: ATOM] RETURNS [INT] ~ { SkipToKeyword[s, key]; RETURN[GetInt[s]]; }; GetString: PROC [s: Source] RETURNS [ROPE] ~ { token: Token ~ GetToken[s]; SELECT token.type FROM string => RETURN[Rope.FromRefText[token.text]]; ENDCASE => ERROR InvalidFont; }; GetName: PROC [s: Source] RETURNS [ATOM] ~ { token: Token ~ GetToken[s]; SELECT token.type FROM name => RETURN[Atom.MakeAtomFromRefText[token.text]]; ENDCASE => ERROR InvalidFont; }; IntFromToken: PROC [token: Token] RETURNS [INT] ~ { SELECT token.type FROM int => RETURN[IntFromText[token.text]]; radix => RETURN[RadixFromText[token.text]]; ENDCASE => ERROR InvalidFont; }; GetInt: PROC [s: Source] RETURNS [INT] ~ { RETURN[IntFromToken[GetToken[s]]]; }; RealFromToken: PROC [token: Token] RETURNS [REAL] ~ { SELECT token.type FROM int => RETURN[IntFromText[token.text]]; radix => RETURN[RadixFromText[token.text]]; real => RETURN[RealFromText[token.text]]; ENDCASE => ERROR InvalidFont; }; GetReal: PROC [s: Source] RETURNS [REAL] ~ { RETURN[RealFromToken[GetToken[s]]]; }; GetBool: PROC [s: Source] RETURNS [BOOL] ~ { SELECT GetName[s] FROM $true => RETURN[TRUE]; $false => RETURN[FALSE]; ENDCASE => ERROR InvalidFont; }; c1: CARD16 ~ 52845; c2: CARD16 ~ 22719; ekey: CARD16 ~ 55665; ckey: CARD16 ~ 4330; Decrypt1: PUBLIC PROC [key: Key, char: CHAR] RETURNS [CHAR] ~ { cipher: BYTE ~ ORD[char]; plain: BYTE ~ Basics.BITXOR[cipher, key.r/256]; key.r ฌ ((cipher+key.r)*c1+c2) MOD (2**16); RETURN [VAL[plain]]; }; BeginEExec: PUBLIC PROC [s: Source] ~ { i: NAT ฌ 0; a: ARRAY [0..4) OF CHAR; nonhex: BOOL ฌ FALSE; s.key ฌ NEW[KeyRep ฌ [r: ekey]]; WHILE i<4 DO char: CHAR ~ GetChar[s]; class: Class ~ classFromChar[char]; IF NOT (i=0 AND class IN WhiteSpace) THEN { a[i] ฌ char; i ฌ i+1; IF class NOT IN HexDigit THEN nonhex ฌ TRUE; }; ENDLOOP; IF nonhex THEN { FOR i: NAT IN[0..4) DO [] ฌ Decrypt1[s.key, a[i]] ENDLOOP; -- cipher bytes 0-3 s.cipher ฌ binary; } ELSE { d: ARRAY [0..4) OF Digit; FOR i: NAT IN[0..4) DO d[i] ฌ digit[a[i]] ENDLOOP; [] ฌ Decrypt1[s.key, VAL[d[0]*16+d[1]]]; -- cipher byte 0 [] ฌ Decrypt1[s.key, VAL[d[2]*16+d[3]]]; -- cipher byte 1 s.cipher ฌ hex; THROUGH [0..2) DO [] ฌ GetChar[s] ENDLOOP; -- cipher bytes 2-3 }; }; untracedZone: ZONE ~ GetUZone[]; GetUZone: PROC RETURNS [ZONE] ~ TRUSTED { RETURN[SafeStorage.GetUntracedZone[]] }; String: TYPE ~ REF StringRep; StringRep: TYPE ~ RECORD [PACKED SEQUENCE length: NAT OF BYTE]; GetBlockFromString: PROC [data: REF] RETURNS [Basics.UnsafeBlock] ~ { string: String ~ NARROW[data]; RETURN[[ base: LOOPHOLE[string], startIndex: BYTES[StringRep[0]], count: string.length ]]; }; CharStringFromString: PROC [string: String] RETURNS [CharString] ~ { RETURN[[data: string, getBlock: GetBlockFromString]]; }; SubrsArray: TYPE ~ REF SubrsArrayRep; SubrsArrayRep: TYPE ~ RECORD [SEQUENCE length: NAT OF String]; CharStringsDict: TYPE ~ RefTab.Ref; -- TABLE ATOM OF String Metrics2Dict: TYPE ~ RefTab.Ref; -- TABLE ATOM OF REF Metrics2 SpecialFromToken: PROC [token: Token] RETURNS [CHAR] ~ { SELECT token.type FROM special => RETURN[token.text[0]]; ENDCASE => ERROR InvalidFont; }; Delim: TYPE ~ {bracket, brace}; OpenFromToken: PROC [token: Token] RETURNS [Delim] ~ { open: Delim ~ SELECT SpecialFromToken[token] FROM '[ => bracket, '{ => brace, ENDCASE => ERROR InvalidFont; RETURN[open]; }; CloseFromToken: PROC [token: Token, open: Delim] ~ { close: Delim ~ SELECT SpecialFromToken[token] FROM '] => bracket, '} => brace, ENDCASE => ERROR InvalidFont; IF open#close THEN ERROR InvalidFont; }; GetOpenDelim: PROC [s: Source] RETURNS [Delim] ~ { RETURN[OpenFromToken[GetToken[s]]]; }; GetCloseDelim: PROC [s: Source, open: Delim] ~ { CloseFromToken[GetToken[s], open]; }; GetMatrix: PROC [s: Source] RETURNS [ImagerTransformation.Transformation] ~ { Index: TYPE ~ [0..6); v: ARRAY Index OF REAL; open: Delim ~ GetOpenDelim[s]; FOR i: Index IN Index DO v[i] ฌ GetReal[s] ENDLOOP; GetCloseDelim[s, open]; RETURN[ImagerTransformation.Create[v[0], v[2], v[4], v[1], v[3], v[5]]]; }; GetBBox: PROC [s: Source] RETURNS [ImagerBox.Box] ~ { Index: TYPE ~ [0..4); v: ARRAY Index OF REAL; open: Delim ~ GetOpenDelim[s]; FOR i: Index IN Index DO v[i] ฌ GetReal[s] ENDLOOP; GetCloseDelim[s, open]; RETURN[[xmin: v[0], ymin: v[1], xmax: v[2], ymax: v[3]]]; }; GetStdW: PROC [s: Source] RETURNS [REAL] ~ { open: Delim ~ GetOpenDelim[s]; v: REAL ~ GetReal[s]; GetCloseDelim[s, open]; RETURN[v]; }; GetArray: PROC [s: Source] RETURNS [array: RealArray] ~ { v: ARRAY [0..14) OF REAL; length: NAT ฌ 0; open: Delim ~ GetOpenDelim[s]; DO token: Token ~ GetToken[s]; IF token.type=special THEN { CloseFromToken[token, open]; EXIT } ELSE { v[length] ฌ RealFromToken[token]; length ฌ length+1 }; ENDLOOP; array ฌ NEW[RealArrayRep[length]]; FOR i: NAT IN[0..length) DO array[i] ฌ v[i] ENDLOOP; }; theStandardEncoding: PUBLIC EncodingArray ~ NEW[EncodingArrayRep ฌ [ NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, $space, $exclam, $quotedbl, $numbersign, $dollar, $percent, $ampersand, $quoteright, $parenleft, $parenright, $asterisk, $plus, $comma, $hyphen, $period, $slash, $zero, $one, $two, $three, $four, $five, $six, $seven, $eight, $nine, $colon, $semicolon, $less, $equal, $greater, $question, $at, $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N, $O, $P, $Q, $R, $S, $T, $U, $V, $W, $X, $Y, $Z, $bracketleft, $backslash, $bracketright, $asciicircum, $underscore, $quoteleft, $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, $q, $r, $s, $t, $u, $v, $w, $x, $y, $z, $braceleft, $bar, $braceright, $asciitilde, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, $exclamdown, $cent, $sterling, $fraction, $yen, $florin, $section, $currency, $quotesingle, $quotedblleft, $guillemotleft, $guilsinglleft, $guilsinglright, $fi, $fl, NIL, $endash, $dagger, $daggerdbl, $periodcentered, NIL, $paragraph, $bullet, $quotesinglbase, $quotedblbase, $quotedblright, $guillemotright, $ellipsis, $perthousand, NIL, $questiondown, NIL, $grave, $acute, $circumflex, $tilde, $macron, $breve, $dotaccent, $dieresis, NIL, $ring, $cedilla, NIL, $hungarumlaut, $ogonek, $caron, $emdash, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, NIL, $AE, NIL, $ordfeminine, NIL, NIL, NIL, NIL, $Lslash, $Oslash, $OE, $ordmasculine, NIL, NIL, NIL, NIL, NIL, $ae, NIL, NIL, NIL, $dotlessi, NIL, NIL, $lslash, $oslash, $oe, $germandbls, NIL, NIL, NIL, NIL ]]; ReadEncoding: PROC [s: Source] RETURNS [EncodingArray] ~ { IF GetKeyword[s]=$StandardEncoding THEN RETURN[theStandardEncoding] ELSE { array: EncodingArray ~ NEW[EncodingArrayRep]; DO SELECT GetKeyword[s] FROM $dup => { index: BYTE ~ GetInt[s]; name: ATOM ~ GetName[s]; array[VAL[index]] ฌ name; }; $readonly, $def => EXIT; ENDCASE; ENDLOOP; RETURN[array]; }; }; ReadCharString: PROC [s: Source] RETURNS [string: String] ~ { n: NAT ~ GetInt[s]; -- [] ฌ GetName[s]; -- RD string ฌ untracedZone.NEW[StringRep[n]]; FOR i: NAT IN[0..n) DO string[i] ฌ ORD[GetChar[s]] ENDLOOP; }; ReadSubrsInner: PROC [s: Source] RETURNS [SubrsArray] ~ { length: NAT ~ GetIntBeforeKeyword[s, $array]; array: SubrsArray ~ NEW[SubrsArrayRep[length]]; FOR i: NAT IN[0..length) DO index: NAT ~ GetIntAfterKeyword[s, $dup]; -- ... dup array[index] ฌ ReadCharString[s]; -- RD ~n~binary~bytes~ ENDLOOP; RETURN[array]; }; ReadSubrs: PROC [s: Source, hybrid: BOOL] RETURNS [array: SubrsArray] ~ { array ฌ ReadSubrsInner[s]; IF hybrid THEN [] ฌ ReadSubrsInner[s]; }; ReadFontInfo: PROC [s: Source, self: Type1Data] ~ { DO SELECT GetKeyword[s] FROM $version => self.version ฌ GetString[s]; $Notice => self.Notice ฌ GetString[s]; $FullName => self.FullName ฌ GetString[s]; $FamilyName => self.FamilyName ฌ GetString[s]; $Weight => self.Weight ฌ GetString[s]; $ItalicAngle => self.ItalicAngle ฌ GetReal[s]; $isFixedPitch => self.isFixedPitch ฌ GetBool[s]; $UnderlinePosition => self.UnderlinePosition ฌ GetReal[s]; $UnderlineThickness => self.UnderlineThickness ฌ GetReal[s]; $end => EXIT; ENDCASE; ENDLOOP; }; ReadCharStringsInner: PROC [s: Source] RETURNS [dict: CharStringsDict] ~ { count: NAT ~ GetIntBeforeKeyword[s, $dict]; dict ฌ RefTab.Create[count]; SkipToKeyword[s, $begin]; DO name: ATOM ~ GetName[s]; -- or end IF name=$end THEN EXIT ELSE { [] ฌ RefTab.Store[dict, name, ReadCharString[s]]; -- RD [] ฌ GetName[s]; -- ND }; ENDLOOP; }; ReadCharStrings: PROC [s: Source, hybrid: BOOL] RETURNS [dict: CharStringsDict] ~ { dict ฌ ReadCharStringsInner[s]; IF hybrid THEN [] ฌ ReadCharStringsInner[s]; }; ReadMetrics2: PROC [s: Source] RETURNS [dict: Metrics2Dict] ~ { count: NAT ~ GetIntBeforeKeyword[s, $dict]; dict ฌ RefTab.Create[count]; SkipToKeyword[s, $begin]; DO name: ATOM ~ GetName[s]; IF name=$end THEN EXIT ELSE { [] ฌ RefTab.Store[dict, name, ReadMetrics2Entry[s]]; [] ฌ GetName[s]; -- ND }; ENDLOOP; }; ReadMetrics2Entry: PROC [s: Source] RETURNS [Metrics2Entry] ~ { Index: TYPE ~ [0..4); v: ARRAY Index OF REAL; open: Delim ~ GetOpenDelim[s]; FOR i: Index IN Index DO v[i] ฌ GetReal[s] ENDLOOP; GetCloseDelim[s, open]; RETURN[untracedZone.NEW[Metrics2EntryRep _ [w: [v[0], v[1]], v: [v[2], v[3]]]]]; }; Data: TYPE ~ REF DataRep; DataRep: TYPE ~ RECORD [ subrs: SubrsArray ฌ NIL, charStrings: CharStringsDict ฌ NIL, metrics2: Metrics2Dict ฌ NIL ]; notdef: ATOM ~ Atom.MakeAtom[".notdef"]; CharStringsLength: PROC [self: Type1Data] RETURNS [NAT] ~ { data: Data ~ NARROW[self.data]; RETURN[RefTab.GetSize[data.charStrings]]; }; CharStringsForAll: PROC [self: Type1Data, action: PROC [ATOM, CharString]] ~ { data: Data ~ NARROW[self.data]; pairAction: RefTab.EachPairAction ~ { name: ATOM ~ NARROW[key]; string: String ~ NARROW[val]; action[name, CharStringFromString[string]]; }; [] ฌ RefTab.Pairs[data.charStrings, pairAction]; }; CharStringsKnown: PROC [self: Type1Data, name: ATOM] RETURNS [BOOL] ~ { data: Data ~ NARROW[self.data]; RETURN[RefTab.Fetch[data.charStrings, name].val#NIL]; }; CharStringsGet: PROC [self: Type1Data, name: ATOM] RETURNS [CharString] ~ { data: Data ~ NARROW[self.data]; val: REF ฌ RefTab.Fetch[data.charStrings, name].val; IF val=NIL THEN val ฌ RefTab.Fetch[data.charStrings, notdef].val; WITH val SELECT FROM string: String => RETURN[CharStringFromString[string]]; ENDCASE => ERROR InvalidFont; }; SubrsGet: PROC [self: Type1Data, n: NAT] RETURNS [CharString] ~ { data: Data ~ NARROW[self.data]; RETURN[CharStringFromString[data.subrs[n]]]; }; ParseFont: PUBLIC PROC [stream: STREAM] RETURNS [self: Type1Data] ~ { buffer: REF TEXT ~ RefText.ObtainScratch[512]; s: Source ~ NEW[SourceRep ฌ [stream: stream, buffer: buffer]]; hybrid: BOOL ฌ FALSE; data: Data ~ NEW[DataRep ฌ []]; self ฌ NEW[Type1DataRep ฌ [data: data, CharStringsLength: CharStringsLength, CharStringsForAll: CharStringsForAll, CharStringsKnown: CharStringsKnown, CharStringsGet: CharStringsGet, SubrsGet: SubrsGet ]]; DO SELECT GetKeyword[s] FROM $FontInfo => ReadFontInfo[s, self]; -- FontInfo dict $FontName => self.FontName ฌ GetName[s]; $Encoding => self.Encoding ฌ ReadEncoding[s]; $PaintType => self.PaintType ฌ GetInt[s]; $FontType => self.FontType ฌ GetInt[s]; $FontMatrix => self.FontMatrix ฌ GetMatrix[s]; $FontBBox => self.FontBBox ฌ GetBBox[s]; $UniqueID => self.UniqueID ฌ GetInt[s]; $StrokeWidth => self.StrokeWidth ฌ GetReal[s]; $Metrics2 => self.Metrics2 ฌ ReadMetrics2[s]; $eexec => BeginEExec[s]; $Private => EXIT; ENDCASE; ENDLOOP; DO -- Private dict SELECT GetKeyword[s] FROM $hires => hybrid ฌ TRUE; $Subrs => data.subrs ฌ ReadSubrs[s, hybrid]; $ForceBold => self.ForceBold ฌ GetBool[s]; $LanguageGroup => self.LanguageGroup ฌ GetInt[s]; $lenIV => self.lenIV ฌ GetInt[s]; $RndStemUp => self.RndStemUp ฌ GetBool[s]; $password => self.password ฌ GetInt[s]; $BlueValues => self.BlueValues ฌ GetArray[s]; $OtherBlues => self.OtherBlues ฌ GetArray[s]; $FamilyBlues => self.FamilyBlues ฌ GetArray[s]; $FamilyOtherBlues => self.FamilyOtherBlues ฌ GetArray[s]; $BlueScale => self.BlueScale ฌ GetReal[s]; $BlueShift => self.BlueShift ฌ GetReal[s]; $BlueFuzz => self.BlueFuzz ฌ GetReal[s]; $StdHW => self.StdHW ฌ GetStdW[s]; $StdVW => self.StdVW ฌ GetStdW[s]; $StemSnapH => self.StemSnapH ฌ GetArray[s]; $StemSnapV => self.StemSnapV ฌ GetArray[s]; $CharStrings => EXIT; ENDCASE; ENDLOOP; data.charStrings ฌ ReadCharStrings[s, hybrid]; -- CharStrings dict RefText.ReleaseScratch[buffer]; }; CStr: TYPE ~ RECORD [base: POINTER TO Basics.RawBytes, start, len, i: CARD, key: CARD16]; Num: TYPE ~ RECORD [SELECT tag: * FROM int => [x: INT], real => [x: REAL], ENDCASE]; DecodeCharString: PUBLIC PROC [block: Basics.UnsafeBlock, lenIV: NAT, int: PROC [INT], cmd1: PROC [Cmd1], cmd2: PROC [Cmd2]] ~ { cstr: CStr ฌ [base: block.base, start: block.startIndex, len: block.count, i: 0, key: ckey]; Get: PROC RETURNS [b: BYTE] ~ { c: BYTE; -- get next byte from charstring TRUSTED { c ฌ cstr.base[cstr.start+Basics.BoundsCheck[cstr.i, cstr.len]] }; cstr.i ฌ cstr.i+1; b ฌ Basics.BITXOR[c, cstr.key/256]; cstr.key ฌ ((cstr.key+c)*c1+c2) MOD (2**16); }; THROUGH [0..lenIV) DO [] ฌ Get[] ENDLOOP; WHILE cstr.i cmd2[VAL[Get[]]]; <32 => cmd1[VAL[v]]; <247 => int[v-139]; -- [-107..107] (1 byte) <251 => int[(v-247)*256+Get[]+108]; -- [108..1131] (2 bytes) <255 => int[-((v-251)*256+Get[]+108)]; -- [-1131..-108] (2 bytes) ENDCASE => { n: Basics.LongNumber; -- 32-bit signed integer (5 bytes) n.hh ฌ Get[]; n.hl ฌ Get[]; n.lh ฌ Get[]; n.ll ฌ Get[]; int[n.int] }; ENDLOOP; }; EncodingGet: PROC [self: Type1Data, code: BYTE] RETURNS [ATOM] ~ { name: ATOM ~ self.Encoding[VAL[code]]; RETURN [IF name#NIL THEN name ELSE notdef]; }; StdEncodingGet: PROC [self: Type1Data, code: BYTE] RETURNS [ATOM] ~ { name: ATOM ~ theStandardEncoding[VAL[code]]; RETURN [IF name#NIL THEN name ELSE notdef]; }; ExecuteChar: PUBLIC PROC [self: Type1Data, name: ATOM, moveTo: MoveToProc, lineTo: LineToProc, curveTo: CurveToProc, flex: FlexProc, close: CloseProc, hstem: HStemProc, hstem3: HStem3Proc, vstem: VStemProc, vstem3: VStem3Proc, discard: DiscardProc, origin: VEC] RETURNS [info: CharInfo ฌ [sb: [0,0], w: [0,0]]] ~ { lenIV: NAT ~ self.lenIV; cstr: CStr ฌ [NIL, 0, 0, 0, 0]; -- current charstring being executed callers: ARRAY [0..10) OF CStr; -- charstring call stack ci: NAT ฌ 0; -- call stack depth Get: PROC RETURNS [b: BYTE] ~ { c: BYTE; -- get next byte from charstring TRUSTED { c ฌ cstr.base[cstr.start+Basics.BoundsCheck[cstr.i, cstr.len]] }; cstr.i ฌ cstr.i+1; b ฌ Basics.BITXOR[c, cstr.key/256]; cstr.key ฌ ((cstr.key+c)*c1+c2) MOD (2**16); }; Begin: PROC [cs: CharString] ~ { -- begin executing a charstring block: Basics.UnsafeBlock ~ cs.getBlock[cs.data]; start: CARD ~ block.startIndex; len: CARD ~ block.count; cstr ฌ [base: block.base, start: block.startIndex, len: block.count, i: 0, key: ckey]; THROUGH [0..lenIV) DO [] ฌ Get[] ENDLOOP; }; stack: ARRAY [0..24) OF Num ฌ ALL[[int[0]]]; -- BuildChar operand stack si: NAT ฌ 0; -- operand stack depth I: PROC [k: NAT] RETURNS [INT] ~ { n: Num ~ stack[k]; RETURN[WITH n: n SELECT FROM int => n.x, ENDCASE => ERROR]; }; R: PROC [k: NAT] RETURNS [REAL] ~ { n: Num ~ stack[k]; RETURN[WITH n: n SELECT FROM int => n.x, real => n.x, ENDCASE => ERROR]; }; PutI: PROC [k: NAT, x: INT] ~ { stack[k] ฌ [int[x]]; }; PutR: PROC [k: NAT, x: REAL] ~ { stack[k] ฌ [real[x]]; }; PushI: PROC [x: INT] ~ INLINE { PutI[si, x]; si ฌ si+1 }; PushR: PROC [x: REAL] ~ INLINE { PutR[si, x]; si ฌ si+1 }; PopI: PROC RETURNS [INT] ~ INLINE { RETURN I[si ฌ si-1] }; PopR: PROC RETURNS [REAL] ~ INLINE { RETURN R[si ฌ si-1] }; weight: RealArray ~ self.WeightVector; Blend: PROC [n: NAT, m: NAT] ~ { k: NAT ~ n/m; -- n arguments, m results FOR i: NAT IN[0..m) DO si0: NAT ~ si+i; -- stack index of result si1: NAT ~ si+m+(k-1)*i; -- stack index of first delta val: REAL ฌ R[si0]; FOR j: NAT IN[1..k) DO val ฌ val+weight[j]*R[si1+j-1] ENDLOOP; PutR[si0, val]; ENDLOOP; }; flexing: BOOL ฌ FALSE; f: FlexArray ฌ ALL[[0,0]]; fi: NAT ฌ 0; -- for Flex moveTo1: PROC [p: VEC] ~ INLINE { IF flexing THEN NULL ELSE moveTo[p] }; cp: VEC ฌ origin; -- current point Begin[self.CharStringsGet[self, name]]; DO v: BYTE ~ Get[]; SELECT v FROM <32 => { -- a command clear: BOOL ฌ TRUE; -- most commands implicitly clear the stack SELECT Cmd1[VAL[v]] FROM hsbw => info ฌ [sb: (cp ฌ [origin.x+R[0], origin.y]), w: [R[1], 0]]; rmoveto => { p1: VEC ~ [ cp.x+R[0], cp.y+R[1] ]; moveTo1[cp ฌ p1]; }; hmoveto => { p1: VEC ~ [ cp.x+R[0], cp.y ]; moveTo1[cp ฌ p1]; }; vmoveto => { p1: VEC ~ [ cp.x, cp.y+R[0] ]; moveTo1[cp ฌ p1]; }; rlineto => { p1: VEC ~ [ cp.x+R[0], cp.y+R[1] ]; lineTo[cp ฌ p1]; }; hlineto => { p1: VEC ~ [ cp.x+R[0], cp.y ]; lineTo[cp ฌ p1]; }; vlineto => { p1: VEC ~ [ cp.x, cp.y+R[0] ]; lineTo[cp ฌ p1]; }; rrcurveto => { p1: VEC ~ [ cp.x+R[0], cp.y+R[1] ]; p2: VEC ~ [ p1.x+R[2], p1.y+R[3] ]; p3: VEC ~ [ p2.x+R[4], p2.y+R[5] ]; curveTo[p1, p2, cp ฌ p3]; }; hvcurveto => { p1: VEC ~ [ cp.x+R[0], cp.y ]; p2: VEC ~ [ p1.x+R[1], p1.y+R[2] ]; p3: VEC ~ [ p2.x, p2.y+R[3] ]; curveTo[p1, p2, cp ฌ p3]; }; vhcurveto => { p1: VEC ~ [ cp.x, cp.y+R[0] ]; p2: VEC ~ [ p1.x+R[1], p1.y+R[2] ]; p3: VEC ~ [ p2.x+R[3], p2.y ]; curveTo[p1, p2, cp ฌ p3]; }; closepath => IF close#NIL THEN close[]; hstem => IF hstem#NIL THEN hstem[y: info.sb.y+R[0], dy: R[1]]; vstem => IF vstem#NIL THEN vstem[x: info.sb.x+R[0], dx: R[1]]; callsubr => { subr: NAT ~ PopI[]; callers[ci] ฌ cstr; ci ฌ ci+1; Begin[self.SubrsGet[self, subr]]; clear ฌ FALSE }; return => { cstr ฌ callers[ci ฌ ci-1]; clear ฌ FALSE }; endchar => RETURN; VAL[15] => { -- undocumented command: ignore and hope for the best -- }; escape => SELECT Cmd2[VAL[Get[]]] FROM seac => { asb: REAL ~ R[0]; adx: REAL ~ R[1]; ady: REAL ~ R[2]; bnameStd: ATOM ~ StdEncodingGet[self, VAL[I[3]]]; anameStd: ATOM ~ StdEncodingGet[self, VAL[I[4]]]; bname: ATOM ~ EncodingGet[self, VAL[I[3]]]; aname: ATOM ~ EncodingGet[self, VAL[I[4]]]; binfo: CharInfo ~ ExecuteChar[self, bnameStd, moveTo, lineTo, curveTo, flex, close, hstem, hstem3, vstem, vstem3, discard, origin]; aorigin: VEC ~ [origin.x+binfo.sb.x-asb+adx, origin.y+ady]; IF discard#NIL THEN discard[]; -- new hints for the accent [] ฌ ExecuteChar[self, anameStd, moveTo, lineTo, curveTo, flex, close, hstem, hstem3, vstem, vstem3, discard, aorigin]; RETURN[binfo]; }; < { asb: REAL ~ R[0]; adx: REAL ~ R[1]; ady: REAL ~ R[2]; bname: ATOM ~ EncodingGet[self, VAL[I[3]]]; aname: ATOM ~ EncodingGet[self, VAL[I[4]]]; binfo: CharInfo ~ ExecuteChar[self, bname, moveTo, lineTo, curveTo, flex, close, hstem, hstem3, vstem, vstem3, discard, origin]; aorigin: VEC ~ [origin.x+binfo.sb.x-asb+adx, origin.y+ady]; IF discard#NIL THEN discard[]; -- new hints for the accent [] ฌ ExecuteChar[self, aname, moveTo, lineTo, curveTo, flex, close, hstem, hstem3, vstem, vstem3, discard, aorigin]; RETURN[binfo]; };>> sbw => info ฌ [sb: cp ฌ [origin.x+R[0], origin.y+R[1]], w: [R[2], R[3]]]; div => { si ฌ si-2; PushR[R[si]/R[si+1]]; clear ฌ FALSE }; dotsection => { --ignored-- }; hstem3 => IF hstem3#NIL THEN hstem3[y0: info.sb.y+R[0], dy0: R[1], y1: info.sb.y+R[2], dy1: R[3], y2: info.sb.y+R[4], dy2: R[5]]; vstem3 => IF vstem3#NIL THEN vstem3[x0: info.sb.x+R[0], dx0: R[1], x1: info.sb.x+R[2], dx1: R[3], x2: info.sb.x+R[4], dx2: R[5]]; callothersubr => { subr: NAT ~ PopI[]; n: NAT ~ PopI[]; si ฌ si-n; -- pop n arguments SELECT subr FROM 0 => { -- end Flex IF flex#NIL THEN flex[f: f, min: R[si]/100] ELSE { curveTo[f[1], f[2], f[3]]; curveTo[f[4], f[5], f[6]] }; PutR[si, cp.x]; PutR[si+1, cp.y]; flexing ฌ FALSE; }; 1 => { fi ฌ 0; flexing ฌ TRUE }; -- begin Flex 2 => { f[fi] ฌ cp; fi ฌ fi+1 }; -- add Flex coordinates 3 => IF discard#NIL THEN discard[] ELSE PutI[si, 3]; -- hint replacement 14 => Blend[n, 1]; 15 => Blend[n, 2]; 16 => Blend[n, 3]; 17 => Blend[n, 4]; 18 => Blend[n, 6]; ENDCASE; clear ฌ FALSE; }; pop => { si ฌ si+1; clear ฌ FALSE }; setcurrentpoint => cp ฌ [R[0], R[1]]; ENDCASE => ERROR; -- unrecognized Cmd2 ENDCASE => ERROR; -- unrecognized Cmd1 IF clear THEN si ฌ 0; }; <247 => PushI[v-139]; -- [-107..107] (1 byte) <251 => PushI[(v-247)*256+Get[]+108]; -- [108..1131] (2 bytes) <255 => PushI[-((v-251)*256+Get[]+108)]; -- [-1131..-108] (2 bytes) ENDCASE => { x: Basics.LongNumber; -- 32-bit signed integer (5 bytes) x.hh ฌ Get[]; x.hl ฌ Get[]; x.lh ฌ Get[]; x.ll ฌ Get[]; PushI[x.int] }; ENDLOOP; }; END. *Type1FontImpl.mesa Copyright ำ 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Michael Plass, September 30, 1992 9:38 pm PDT Doug Wyatt, June 10, 1993 11:44 am PDT Russ Atkinson (RRA) October 28, 1993 2:14 am PDT Scanner Support types Global variables Support procedures Tokens Decryption Parser consumes RD ~n~binary~bytes~ The Subrs section has one of the following forms: Normal font: /Subrs array dup RD noaccess put dup RD noaccess put ... dup RD noaccess put noaccess def Hybrid font: hires {userdict /fsmkr save put} if /Subrs array dup RD noaccess put dup RD noaccess put ... dup RD noaccess put noaccess def hires {fsmkr restore} {userdict /fsmkr save put} ifelse /Subrs array dup RD noaccess put dup RD noaccess put ... dup RD noaccess put noaccess def hires not {fsmkr restore} if ReadSubrs is called when the first instance of /Subrs is encountered. ReadSubrsInner searches for array. Recall that the can contain arbitrary bytes, so we must use ReadSubrsInner to skip the unwanted routines. Just trying to skip to the last 'hires' token will break the lexical scanner. The CharStrings section has one of the following forms: Normal font: /CharStrings dict dup begin RD ND ... end Hybrid font: /CharStrings hires {userdict /fsmkr save put} if dict dup begin RD ND ... end hires {pop fsmkr restore} {userdict /fsmkr save put} ifelse dict dup begin RD ND ... end hires not {pop fsmkr restore} if Hybrid font (alternate): hires {userdict /fsmkr save put} if /CharStrings dict dup begin RD ND ... end hires {pop fsmkr restore} {userdict /fsmkr save put} ifelse /CharStrings dict dup begin RD ND ... end hires not {pop fsmkr restore} if ReadCharStrings is called when the first instance of /CharStrings is encountered. ReadCharStringsInner searches for dict. This routine assumes following description pattern of Metrics2: /Metrics2 95 dict dup begin /c21 [0 -500 250 880 ] def /c22 [0 -500 250 880 ] def . . . /.notdef [0 -500 250 880 ] def end def $UniqueID => IF GetInt[s]#self.UniqueID THEN ERROR InvalidFont; $MinFeature => self.MinFeature _ GetArray[s]; CharString decoding RRA, October 28, 1993 1:42:35 am PDT The Type1Font book (page 50) claims that seac should not work if the encoding vector differs from the standard encoding vector for the aname or bname, but we have evidence of a client who seems to assume the use of the standard encoding vector, even though the font encoding vector is ISO Latin (more or less). The Type1Font book (page 50) claims that seac displaces the origin of the accent [adx, ady] from the origin of the base character, but we seem to get correct results by using sidebearing point, not origin. For reference, here is the old code The Type1Font book (page 50) claims that seac displaces the origin of the accent [adx, ady] from the origin of the base character, but we seem to get correct results by using sidebearing point, not origin. ส2(•NewlineDelimiter –(cedarcode) style˜codešœ™Kšœ ฯeœB™MK™-K™&K™0K˜—šฯk ˜ Kšœžœžœžœžœžœžœžœ˜&Kšœžœ!˜+Kšœžœžœ2˜FKšœ žœ˜Kšœ žœ'˜7Kšœžœ˜4Kšžœžœ žœ˜Kšœžœ+˜5Kšœžœ=˜IKšœžœ/˜Kšœžœ ˜š žœžœžœžœž˜šœ žœž˜Kšœžœžœžœ ˜(Kšœžœžœ ˜K˜K˜K˜K˜K˜K˜K˜K˜K˜ K˜K˜ K˜ K˜Kšžœ˜Kšžœ˜K˜Kšžœ žœ˜&Kšžœ žœ˜(K˜Kšžœ ˜—Kšžœ˜—K˜K˜—š Ÿœžœžœ žœžœ˜>Kšœžœ ˜š žœžœžœžœž˜šœ žœž˜Kšžœ˜Kšžœ˜ Kšžœ˜ Kšžœ˜ —Kšžœ˜—K˜K˜—š Ÿœžœžœ žœžœ˜@Kšœžœ˜š žœžœžœžœž˜šœžœž˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšœ žœ˜Kšžœ žœ˜ Kšžœ ˜—Kšžœ˜—K˜K˜—šŸ œžœžœ˜Lšžœž˜˜ Kšžœžœ žœžœ˜Aš žœžœ žœžœž˜*Kšœ žœ!˜2Kšœ žœ!˜0Kšœ žœ ˜3Kšœ žœ˜1Kšžœžœ(žœ˜@—K˜—šžœ˜Kšžœžœ ž œ$žœ˜MKšžœžœ ž œ'žœ˜MK˜—šžœ˜Kšžœžœ žœžœ˜AKšœ˜—Kšžœ˜—šžœž˜šœ žœž˜Kšœžœ ˜.Kšœžœ!˜.Kšžœžœ ˜9Kšžœžœ ˜1—šœžœž˜Kšœžœ!˜.Kšžœžœ ˜9Kšžœžœ ˜1—šœžœž˜Kšœžœ!˜.Kšœ žœ!˜2Kšœžœ"˜0Kšžœžœ ˜9Kšžœžœ ˜1—šœžœž˜Kšœžœ!˜.Kšœ žœ!˜2Kšžœžœ ˜9Kšžœžœ ˜1—šœ žœž˜Kšžœžœ!˜:Kšžœžœ ˜1—šœ žœž˜Kšœ žœ!˜2Kšžœžœ!˜:Kšžœžœ ˜1—šœ žœž˜Kšœžœ!˜/Kšžœžœ!˜:Kšžœžœ ˜1—šœ žœž˜Kšžœžœ!˜:Kšžœžœ ˜1—šœ žœž˜Kšžœžœ!˜:Kšžœžœ ˜1—šœ žœž˜Kšžœžœ"˜9Kšžœžœ ˜1—šœ žœž˜Kšžœžœ"˜9Kšžœžœ ˜1—Kšœžœ ˜.Kšœ žœ#˜4šœ žœž˜Kšœ žœ%˜8Kšœžœ&˜:Kšœ žœ˜1Kšžœžœ"˜3—šœžœž˜Kšœ žœ ˜1Kšœžœ$˜8Kšžœžœ&˜7—šœžœž˜Kšœžœ&˜:Kšœžœ%˜9Kšžœžœ"˜3—šœžœž˜Kšœžœ&˜:Kšœžœ'˜;Kšžœžœ"˜3—šœžœž˜Kšœžœ#žœ˜>Kšžœ žœ#˜8Kšžœžœ$žœ˜<—šœžœž˜Kšœžœ#žœ˜>Kšžœ žœ#˜8Kšžœžœ$žœ˜<—šœ žœž˜Kšœ žœ˜0Kšžœžœ!˜2—Kšžœžœ$žœ˜<—K˜K˜—š Ÿœžœžœ žœžœ˜HKšœžœ˜šžœžœž˜Kšœžœžœ˜2šžœžœž˜Kšœ(˜(Kšžœ˜—K˜Kšžœ˜—K˜K˜—š Ÿ œžœžœ žœžœ˜;Kšœžœ˜š žœžœžœžœž˜šœ žœž˜Kšžœ˜K˜K˜ K˜Kšžœ ˜—Kšžœ˜—K˜K˜—šŸ œžœ žœ ˜Ešžœ˜šžœž˜šœžœž˜K˜ K˜K˜ Kšžœ ˜—Kšœ žœžœžœ ˜Fšœžœž˜K˜ K˜ K˜Kšžœ ˜—Kšœžœžœžœ ˜9Kšœ žœžœ"žœ ˜RKšœ žœžœžœ ˜IKšœ žœžœžœ ˜:Kšœžœžœžœ ˜8Kšžœ ˜—Kšœ˜—K˜K˜—š Ÿœžœžœ žœžœ˜EKšœžœ˜šžœžœž˜Kšœžœžœ˜4šžœžœž˜Kšœ)˜)Kšžœ˜—K˜Kšžœ˜—K˜K˜——™šŸ œžœ žœžœ ˜6šž˜Kšœžœžœ˜Kšžœžœ žœžœ ˜6Kšžœ˜—K˜K˜—š Ÿœžœžœ žœžœ˜3Kšžœ žœžœžœ˜?šžœ ž˜Kšœ žœžœ˜&Kšœ žœžœ˜8šœ˜Kšœ"˜"Kšœ"˜"Kšžœžœ ˜'K˜—Kšžœžœ˜—K˜K˜—šŸœžœžœžœ˜-Kšžœ žœžœ˜Kšœ žœ˜Kšœ˜K˜K˜K˜—šŸœžœžœ žœ ˜5Kšœžœžœ ˜Kšœ žœ˜ Kšœžœ ˜ K˜Kšœžœ 2˜Išžœ ˜Kšœžœ˜Kšœ#˜#Kšœ4˜4Kšœžœ  ˜2K˜˜šžœž˜Kšœžœ˜Kšœ žœ˜Kšœžœ˜+Kšœ˜Kš œžœ žœžœžœ˜;Kšœ#˜#Kšœžœžœ)˜GKšœžœ˜)Kšœžœžœ'˜CKšžœžœ ˜—šžœžœžœ˜Kšœ˜K˜1K˜K˜—K˜Kšœ žœ žœ˜!Kšžœ žœ˜K˜—Kšžœ žœžœ˜Kšžœ˜—K˜šžœž˜Kšœžœ žœ˜'Kšœžœžœ˜)Kšœžœžœ˜,Kšœ žœžœ˜'Kšœžœžœ˜4Kšœ žœžœ˜'Kšœ žœ˜$Kšœ žœ ˜Kšžœžœ˜!—K˜K˜—šŸ œžœžœžœ žœ žœžœžœ˜WKšœžœžœžœ ˜ Kšœžœ˜Kš žœžœžœ žœžœ˜(šžœžœžœž˜%Kšœžœ ˜K˜Kšžœžœ žœžœ˜!Kšžœ žœžœžœ˜6Kš žœžœžœžœžœžœ˜K˜—K˜K˜——™Kšœžœ˜ š Ÿœžœžœžœžœžœ"˜RK˜—Kšœžœžœ ˜šœ žœžœžœžœ žœžœžœ˜?K˜—šŸœžœžœžœ˜EKšœžœ˜šžœ˜Kšœžœ ˜Kšœ žœ˜ K˜K˜—K˜K™—šŸœžœžœ˜DKšžœ/˜5K˜K˜—Kšœ žœžœ˜%š œžœžœžœ žœžœ ˜>K˜—š œžœ ะck ก ก ˜;K˜—š œžœ ก ก ก ก  ˜>K˜—šŸœžœžœžœ˜8šžœ ž˜Kšœ žœ˜!Kšžœžœ ˜—K˜K˜—šœžœ˜K˜—šŸ œžœžœ ˜6šœžœž˜1Kšœžœžœ ˜9—Kšžœ˜ K˜K˜—šŸœžœ ˜4šœžœž˜2Kšœžœžœ ˜9—Kšžœ žœžœ ˜%K˜K˜—šŸ œžœ žœ ˜2Kšžœ˜#K˜K˜—šŸ œžœ˜0Kšœ"˜"K˜K˜—šŸ œžœ žœ*˜MKš œžœžœžœžœ˜-Kšœ˜Kšžœ žœžœžœ˜3Kšœ˜KšžœB˜HK˜K˜—šŸœžœ žœ˜5Kš œžœžœžœžœ˜-Kšœ˜Kšžœ žœžœžœ˜3Kšœ˜Kšžœ3˜9K˜K˜—šŸœžœ žœžœ˜,Kšœ˜Kšœžœ˜Kšœ˜Kšžœ˜ K˜K˜—šŸœžœ žœ˜9Kš œžœ žœžœ žœ˜*Kšœ˜šž˜K˜Kšžœžœ žœ˜@Kšžœ9˜=Kšžœ˜—Kšœžœ˜"Kš žœžœžœ žœžœ˜4K˜K˜—šœžœžœ˜DKšžœžœžœžœžœžœžœžœ˜(Kšžœžœžœžœžœžœžœžœ˜(Kšžœžœžœžœžœžœžœžœ˜(Kšžœžœžœžœžœžœžœžœ˜(KšœU˜UKšœM˜MKšœ7˜7KšœG˜GKšœ!˜!Kšœ ˜ Kšœ ˜ KšœP˜PKšœ(˜(Kšœ ˜ Kšœ ˜ Kšœ8žœ˜=Kšžœžœžœžœžœžœžœžœ˜(Kšžœžœžœžœžœžœžœžœ˜(Kšžœžœžœžœžœžœžœžœ˜(Kšžœžœžœžœžœžœžœžœ˜(KšžœE˜HKšœc˜cKšžœ1žœ˜NKšœZžœ˜nKšžœD˜GKšœ žœžœ"˜FKšœ žœžœžœžœžœžœžœ˜,Kšžœžœžœžœžœžœžœžœ˜(Kš žœžœžœžœžœžœ˜1Kš œ&žœžœžœžœ˜:Kš žœžœžœžœ žœžœ˜.Kšœ$žœžœžœž˜6šœ˜K˜——šŸ œžœ žœ˜:šžœ ˜"Kšžœžœ˜ šžœ˜Kšœžœ˜-šž˜šžœž˜˜ Kšœžœ ˜Kšœžœ˜Kšœžœ˜K˜—Kšœžœ˜Kšžœ˜—Kšžœ˜—Kšžœ˜K˜——K˜K˜—šŸœžœ žœ˜=K™ Kšœžœ ˜Kšœ ˜Kšœžœ˜(Kš žœžœžœžœ žœ žœ˜;K˜K˜—™1™ Iasciišœฎ™ฎ—™ Mšœี™ี——šœcะfrœว™ธM˜—šŸœžœ žœ˜9Kšœžœ"˜-Kšœžœ˜/šžœžœžœ ž˜Kšœžœ  ข ˜Kšœžœžœ˜Kšœ žœ˜šœžœ˜&K˜%K˜%K˜#K˜K˜K˜—šž˜šžœž˜Kšœ$ ˜4Kšœ(˜(K˜-K˜)K˜'Kšœ.˜.Kšœ(˜(K˜'K˜.K˜-Kšœ˜Kšœ žœ˜Kšžœ˜—Kšžœ˜—šžœ ˜šžœž˜Kšœžœ˜K˜,Kšœ*˜*Kšœ1˜1Kšœ!˜!Kšœ*˜*Kšœ'˜'Kšœ žœžœžœ ™?K˜-K˜-K˜/K˜9Kšœ*˜*Kšœ*˜*Kšœ(˜(Kšœ"˜"Kšœ"˜"K˜+K˜+Kšœ-™-Kšœžœ˜Kšžœ˜—Kšžœ˜—Kšœ/ ˜BK˜K˜K˜——™š œžœžœžœžœ!žœžœ˜YK˜—šœžœžœžœžœ žœžœžœ˜TK™—šŸœžœžœ$žœžœžœ žœžœ ˜K˜\š Ÿœžœžœžœ žœ  ˜IKšžœD˜KKšœžœ˜6Kšœ žœ ˜,K˜—Kšžœ žœ žœ˜)š žœžœžœ žœž˜7Kšœ žœ ˜Kšœ žœ˜Kšœ ˜+Kšœ$ ˜K˜Kšžœ˜—K˜—Kš œ žœžœžœ žœ  ˜JKšœ žœžœžœžœ žœžœžœ ˜HKšœžœ  ˜"K˜'šžœžœ žœž˜!šœ   ˜Kšœžœžœ +˜?šžœžœž˜K˜D˜ Itcodešœžœ˜#K˜K˜—˜ Nšœžœ˜K˜K˜—˜ Nšœžœ˜K˜K˜—˜ Nšœžœ˜#K˜K˜—˜ Nšœžœ˜K˜K˜—˜ Nšœžœ˜K˜K˜—˜Nšœžœ˜#Nšœžœ˜#Nšœžœ˜#K˜K˜—˜Nšœžœ˜Nšœžœ˜#Nšœžœ˜K˜K˜—˜Nšœžœ˜Nšœžœ˜#Nšœžœ˜K˜K˜—Kšœ žœžœžœ ˜'Kšœ žœžœžœ$˜>Kšœ žœžœžœ$˜>KšœžœUžœ˜tKšœ/žœ˜7Kšœ žœ˜Kšžœ  8œ˜Hšœ žœžœ ž˜&˜ ™$K™ถ—Kšœžœžœžœ˜5Kšœ žœžœ˜1Kšœ žœžœ˜1Kšœžœžœ˜+Kšœžœžœ˜+K˜„šœ žœ/˜;Kšœ<ฯbœ#ฃœDฃœ™ฮ—Kšžœ žœžœ  ˜:K˜xKšžœ˜K˜—K™#˜ Kšœžœžœžœ˜5Kšœžœžœ˜+Kšœžœžœ˜+K˜šœ žœ/˜;Kšœ<ฃœ#ฃœDฃœ™ฮ—Kšžœ žœžœ  ˜:K˜uKšžœ˜K˜—K˜IKšœ2žœ˜:Kšœ  œ˜Kšœ žœžœžœf˜‚Kšœ žœžœžœf˜‚šœ˜Kšœžœ ˜Kšœžœ ˜Kšœ  ˜šžœž˜šœ  ˜Kšžœžœžœ˜+Kšžœ:˜>K˜!Kšœ žœ˜K˜—Kšœžœ  ˜.Kšœ  ˜7Kš œžœ žœžœ žœ ˜HK˜K˜K˜K˜K˜Kšžœ˜—Kšœžœ˜Kšœ˜—Kšœžœ˜$K˜%Kšžœžœ ˜&—Kšžœžœ ˜&—Kšžœžœ˜K˜—Kšœ ˜-Kšœ& ˜>Kšœ) ˜CKšžœ "œH˜Kšžœ˜—K˜K˜——K˜Kšžœ˜—…—“าn